密码学第一次作业DES算法

内容###

编程统计DES算法中明文(或密钥)改变1位,2位。。。64位的情况下,密文位数的变化量情况具体要求: 编程实现
1。在密钥不变情况下,明文改变1位,2位。。。64位,观察并统计密文位数变化规律。
2。在明文不变情况下,密钥改变1位,2位。。。64(56)位,观察并统计密文位数变化规律。
为了使统计局有客观性,上述每种情况可以重复多次,然后求平均值。
编程语言不限,建议采用java 或 C#等高级语言,因为这些语言中有内置的DES算法包,如果采用C/C++则需要自己到网上搜索DES算法库,
提交方式:将程序源代码和运行结果截图以电子文档的形式提交。

电子版作业上交要求###

注意:每个人的邮件标题和附件文件名要带上自己的编号203 姓名冯光平,学号3114006176,比如 001_31012xxx_张三_信息安全第X次作业 。这样便于管理。注意:直接发送到我的QQ邮箱,不要通过通过QQ传输。
特别要注意,附件的文件名也要采用上述命名格式,不要使用“文档1.docx”等默认文件名,如果包含多个文件,请先用压缩...

源代码###

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class des {
     private static byte[][] b;

    /**
     * 加密方法
     * @param datasource 明文
     * @param password 秘钥
     * @return 密文
     */
    public static byte[] desCrypto(byte[] datasource, String password) {
        try{
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            //创建一个密匙工厂,然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            //Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            //用密匙初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            //现在,获取数据并加密
            //正式执行加密操作
            return cipher.doFinal(datasource);
        }catch(Throwable e){
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 初始化辅助数组 b是需要初始化的数组
     */
    public static void initBytes() {
        //64代表的是含有1-64个1的串,8代表8个字节(64位)
        b = new byte[64][8];
        b[0][0] = -128; // 10000000
        for(int i = 1; i < 64; i++) {
            for(int j = 0; j < 8; j++) {
                b[i][j] = b[i-1][j];
            }
            int k = i/8;
            int z = (i+1)%8; z = z == 0 ? 8 : z;
            b[i][k] ^= (byte) Math.pow(2, (8-z));
        }
    }
    
    /**
     * 循环右移一个byte数组
     * @param num 右移位数
     * @param b 数组
     * @return 右移后数组
     */
    public static byte[] bytesMoveToRight(int num , byte[] b) {
        byte[] bytes = b;
        for(int i = 0; i < num; i++) { //每次循环右移一位,实现比较简单,但是效率比较慢
            byte low = (byte)(bytes[bytes.length-1] & 1); //记录最后一个字节的最低1位
            for(int j = 0; j < bytes.length; j++) { //从第一个字节开始
                byte loww = (byte)(bytes[j] & 1); //记录最低一位
                bytes[j] = (byte)(bytes[j]>>1&127); //右移一位,高位补0,可以用>>>代替,但是不知道为啥我的开发环境>>>失效了
                bytes[j] = (byte) (bytes[j] ^ (low<<7) ); //把高位补上之前记录的最低1位
                low = loww; //替换成新的最低1位
            }
        }
        return bytes;
    }
    
    /**
     * 求两个字节数组的二进制中不同的位数
     * @param m 
     * @param n
     * @return 返回不同的位数的个数
     */
    public static int countBitDiff(byte[] m, byte[] n) {
        if(m.length != n.length) return -1;

        byte[] ans = new byte[m.length];
        for(int i = 0; i < m.length; i++) { //异或操作
            ans[i] =(byte) (m[i] ^ n[i]);
        }
        int count = 0;
        for(int i = 0; i < ans.length; i++) { //统计1的个数
            while(ans[i] != 0){
                ans[i] &= (byte)(ans[i] -1);
                count++;
            }
        }
        return count;
    }
    
    public static void main(String[] args) {
        //初始化辅助数组
        initBytes();
        //初始明文
        String word = "AAAAAAAA";
        printTo8Binary( word.getBytes());
        //初始秘钥
        String password = "12345678";
        printTo8Binary( password.getBytes());
        //加密
        byte[] result = desCrypto(word.getBytes(),password);
        printTo8Binary(result);

        /**改变明文位数**/
        for(int i = 1; i <= 64; i++) { //改变1-64位
            System.out.print("明文改变"+i+"位: ");
            byte[] origin = word.getBytes(); //原始明文
            int digits = 0; //改变位数
            for(int j = 0; j < 10; j++) { //10种情况取平均
                byte[] now = new byte[8]; //现在明文
                for(int k = 0; k < origin.length; k++) { //用辅助数组进行变位(i-1位)
                    now[k] = (byte)(origin[k] ^ b[i-1][k]);
                }
                bytesMoveToRight(1 , b[i-1]); //右移一下辅助数组,供下种情况使用
//                printTo8Binary("改变"+(j+1)+"后明文: " , now);
                //加密
                byte[] r = desCrypto(now,password);
//                printTo8Binary("改变"+(j+1)+"后密文: " , r);
                digits += countBitDiff(r , result);//和原始密文比较,记录改变位数
//                System.out.println("密文改变了"+countBitDiff(r , result)+"位");
            }
            System.out.println("密文平均改变了"+(double)digits/10.0+"位");
        }

        /**改变秘钥位数**/
        for(int i = 1; i <= 64; i++) { //改变1-64位
            System.out.print("秘钥改变"+i+"位: ");
            byte[] origin = password.getBytes();//原始秘钥
            int digits = 0; //改变位数
            for(int j = 0; j < 10; j++) { //10种情况取平均
                byte[] now = new byte[8]; //现在秘钥
                for(int k = 0; k < origin.length; k++) { //用辅助数组进行变位(i-1位)
                    now[k] = (byte)(origin[k] ^ b[i-1][k]);
                }
                bytesMoveToRight(1 , b[i-1]); //右移一下辅助数组,供下种情况使用
//                printTo8Binary("改变后秘钥: " , now);
                //加密
                byte[] r = desCrypto(now,password);
//                printTo8Binary("改变后密文: " , r);
                digits += countBitDiff(r , result);//和原始密文比较,记录改变位数
            }
            System.out.println("密文平均改变了"+(double)digits/10.0+"位");
        }
    }
    
    /**
     * 把byte数组类型转换为8位二进制类型字符串输出
     * @param tByte 字节数组
     * @return
     */
    public static void printTo8Binary( byte[] tByte) {
        for(int i=0; i<tByte.length; i++) {
            String tString = Integer.toBinaryString((tByte[i] & 0xFF) + 0x100).substring(1);
            System.out.print(tString + " ");
        }
        System.out.println();
    }
    
    /**
     * 字节循环右移
     * @param num 右移位数
     * @param b 原字节
     * @return
     */
    public static byte cycleToRight(int num , byte b) {
        byte low = (byte) (b & (byte)(Math.pow(2 , num) - 1)); //记录低num位
        byte temp = (byte)~( (byte)(Math.pow(2 , num) - 1) << (8 - num) );
        byte result = (byte) (b >> num & temp); //右移num位,高num位补0,同>>>
        result ^= low << (8 - num);
        return result;
    }
}

结果截图###

结果截图一
结果截图二
结果截图三
结果截图四
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容