Loading

对称加密和伪随机性

加密算法设计的两种基本策略

流密码:(序列密码)

  • 将密钥扩展到与密文等长
  • 加密算法一般为异或操作
  • 其安全性主要在于密钥扩展后的随机性

分组密码:

  • 将明文分成等长的分组(比如64bit, 128bit)
  • 对每个分组采用相同的加密算法进行加密
  • 算法一般是交替使用混合和扩散技术

注意:替换使用混乱和扩散技术的本质是为了实现伪随机函数(PRF)。

随机函数:给定集合X和Y,设函数\(f:X \to Y\)。则该类函数\(f\)一共有\(|X|^{|Y|}\)个,令集合\(D=\{f_i|f_i : X\to Y\}\)。随机从集合D中选择一个元素\(f_i\),则称\(f_i\)为随机函数

伪随机函数:设K为密文空间,X是输入数据,Y是输出数据。若\(k \in K, x \in X, y \in Y, \ y=F(k, x)\in Y\),其安全性要求:给定一个随机产生的密钥k,函数\(F(k,)\)为集合X到集合Y的随机函数。

常见的流密码加密算法

  • RC4加密算法

    该算法包括2个过程:

    • 密钥调度算法:置乱S盒的初式序列
    • 伪随机生成算法:输出随机序列并修改S的当前排列顺序

    更加详细请看该博客

package io.kzw.advance.csdn_blog;
 
public class RC4 {
 
    public static String decry_RC4(byte[] data, String key) {
        if (data == null || key == null) {
            return null;
        }
        return asString(RC4Base(data, key));
    }
 
    public static String decry_RC4(String data, String key) {
        if (data == null || key == null) {
            return null;
        }
        return new String(RC4Base(HexString2Bytes(data), key));
    }
 
    public static byte[] encry_RC4_byte(String data, String key) {
        if (data == null || key == null) {
            return null;
        }
        byte b_data[] = data.getBytes();
        return RC4Base(b_data, key);
    }
 
    public static String encry_RC4_string(String data, String key) {
        if (data == null || key == null) {
            return null;
        }
        return toHexString(asString(encry_RC4_byte(data, key)));
    }
 
 
    private static String asString(byte[] buf) {
        StringBuffer strbuf = new StringBuffer(buf.length);
        for (int i = 0; i < buf.length; i++) {
            strbuf.append((char) buf[i]);
        }
        return strbuf.toString();
    }
 
    private static byte[] initKey(String aKey) {
        byte[] b_key = aKey.getBytes();
        byte state[] = new byte[256];
 
        for (int i = 0; i < 256; i++) {
            state[i] = (byte) i;
        }
        int index1 = 0;
        int index2 = 0;
        if (b_key == null || b_key.length == 0) {
            return null;
        }
        for (int i = 0; i < 256; i++) {
            index2 = ((b_key[index1] & 0xff) + (state[i] & 0xff) + index2) & 0xff;
            byte tmp = state[i];
            state[i] = state[index2];
            state[index2] = tmp;
            index1 = (index1 + 1) % b_key.length;
        }
        return state;
    }
 
    private static String toHexString(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = (int) s.charAt(i);
            String s4 = Integer.toHexString(ch & 0xFF);
            if (s4.length() == 1) {
                s4 = '0' + s4;
            }
            str = str + s4;
        }
        // 0x表示十六进制
        return str;
    }
 
 
    private static byte[] HexString2Bytes(String src) {
        int size = src.length();
        byte[] ret = new byte[size / 2];
        byte[] tmp = src.getBytes();
        for (int i = 0; i < size / 2; i++) {
            ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
        }
        return ret;
    }
 
    private static byte uniteBytes(byte src0, byte src1) {
        char _b0 = (char) Byte.decode("0x" + new String(new byte[]{src0}))
                .byteValue();
        _b0 = (char) (_b0 << 4);
        char _b1 = (char) Byte.decode("0x" + new String(new byte[]{src1}))
                .byteValue();
        byte ret = (byte) (_b0 ^ _b1);
        return ret;
    }
 
    private static byte[] RC4Base(byte[] input, String mKkey) {
        int x = 0;
        int y = 0;
        // 这边将密钥确保为 256 个字节
        byte key[] = initKey(mKkey);
        int xorIndex;
        byte[] result = new byte[input.length];
 
        for (int i = 0; i < input.length; i++) {
            x = (x + 1) & 0xff;
            y = ((key[x] & 0xff) + y) & 0xff;
            byte tmp = key[x];
            key[x] = key[y];
            key[y] = tmp;
            xorIndex = ((key[x] & 0xff) + (key[y] & 0xff)) & 0xff;
            result[i] = (byte) (input[i] ^ key[xorIndex]);
        }
        return result;
    }
}

常见的分组加密算法

  • DES加密算法

DES算法的入口参数有三个:key, data, mode(DES的工作方式:加密,解密)

DES是一种分组加密算法,该算法每次处理固定长度(64bit)的数据段。DES算法具体通过对明文进行一系列的排列和替换将其加密。过程的关键就是从给定的初始密钥中得到16个密钥的函数。将要加密一组明文,每个子密钥按照顺序进行位运算。每一个子密钥一次,重复16次。要对密文解密逆向其过程即可。

子密钥的生成过程:

image-20230301043146113

加密/解密过程:

image-20230301043339694

更加详细的博客

private static final String ALGO = "DES";
 
    private static byte[] encrypt(byte[] src, String password) {
        try {
            // DES 算法要求有一个可信任的随机数源
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创建一个密匙工厂,然后用它把 DESKeySpec 转换成 SecretKey
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGO);
            SecretKey securekey = keyFactory.generateSecret(desKey);
            // Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance(ALGO);
            // 用密匙初始化 Cipher 对象,ENCRYPT_MODE 用于将 Cipher 初始化为加密模式的常量
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            // 加密数据
            return cipher.doFinal(src);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }
 
    private static byte[] decrypt(byte[] src, String password) {
        try {
            // DES 算法要求有一个可信任的随机数源
            SecureRandom random = new SecureRandom();
            // 创建一个 DESKeySpec 对象
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创建一个密匙工厂
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGO);
            // 将 DESKeySpec 对象转换成 SecretKey 对象
            SecretKey securekey = keyFactory.generateSecret(desKey);
            // Cipher 对象实际完成解密操作
            Cipher cipher = Cipher.getInstance(ALGO);
            // 用密匙初始化 Cipher 对象
            cipher.init(Cipher.DECRYPT_MODE, securekey, random);
            // 解密数据
            return cipher.doFinal(src);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }
 
    public static void main(String[] args) {
        String psw = "12345678";
        String data = "hello Test symmetric encry";
        byte[] encryData = encrypt(data.getBytes(), psw);
        System.out.println("encryData = " + new String(encryData));
        byte[] decryData = decrypt(encryData, psw);
        System.out.println("decryData = " + new String(decryData));
    }
  • 3DES加密算法

    3DES加密算法本质是有3个不同的DES密钥,然后按照下列流程进行加密:

    image-20230301043824857

    注意:当3个DES密钥相同,其中前2次加密被抵消,退化为DES加密,过程如下:

    image-20230301043935880

private static final String Algorithm = "DESede";
    private static byte[] encrypt(byte[] keybyte, byte[] src) {
        try {
            // 生成密钥
            SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            // 加密数据
            return c1.doFinal(src);
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }
 
    private static byte[] decrypt(byte[] keybyte, byte[] src) {
        try {
            // 生成密钥
            SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.DECRYPT_MODE, deskey);
            // 解密
            return c1.doFinal(src);
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }
 
    public static void main(String[] args) {
        // 添加新安全算法,如果用JCE就要把它添加进去
        Security.addProvider(new com.sun.crypto.provider.SunJCE());
        // 24字节的密钥
        final byte[] keyBytes = {
                0x11, 0x22, 0x4F, 0x58,
                (byte) 0x88, 0x10, 0x40, 0x38,
                0x28, 0x25, 0x79, 0x51,
                (byte) 0xCB, (byte) 0xDD, 0x55, 0x66,
                0x77, 0x29, 0x74, (byte) 0x98,
                0x30, 0x40, 0x36, (byte) 0xE2
        };
 
        String szSrc = "hello Test symmetric encry";
        byte[] encryData = encrypt(keyBytes, szSrc.getBytes());
        System.out.println("encryData: " + new String(encryData));
 
        byte[] decryptData = decrypt(keyBytes, encryData);
        System.out.println("decryptData: " + (new String(decryptData)));
    }
  • AES加密算法
private static final String ALGO = "AES/ECB/PKCS5Padding";
 
    public static byte[] encrypt(String data, Key key) {
        try {
            Cipher cipher = Cipher.getInstance(ALGO);
            cipher.init(cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(data.getBytes());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }
 
    private static byte[] decrypt(byte[] result, Key key) {
        try {
            Cipher cipher = Cipher.getInstance(ALGO);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }
 
    private static Key createKey() {
        try {
            // 生成key
            KeyGenerator keyGenerator;
            // 构造密钥生成器,指定为AES算法,不区分大小写
            keyGenerator = KeyGenerator.getInstance("AES");
            // 生成一个128位的随机源,根据传入的字节数组
            keyGenerator.init(128);
            // 产生原始对称密钥
            SecretKey secretKey = keyGenerator.generateKey();
            // 获得原始对称密钥的字节数组
            byte[] keyBytes = secretKey.getEncoded();
            // key转换,根据字节数组生成AES密钥
            return new SecretKeySpec(keyBytes, "AES");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
 
    public static void main(String[] args) {
        String data = "hello Test symmetric encry";
        Key key = createKey();
        byte[] encryData = encrypt(data, key);
        System.out.println("encryData = " + new String(encryData));
        byte[] decryData = decrypt(encryData, key);
        System.out.println("decryData = " + new String(decryData));
    }
posted @ 2023-03-01 04:51  青山新雨  阅读(53)  评论(0编辑  收藏  举报