Java 专栏

Java 常用加密算法(二)---对称加密(DES/3DES(T

2017-08-27  本文已影响84人  _凌浩雨

Java 常用加密算法(二)---对称加密(DES/3DES(TripleDES)/AES)

基于“对称密钥”的加密算法主要有DES、3DES(TripleDES)、AES、RC2、RC4、RC5和Blowfish等。

代码中用到的Base64与BouncyCastleProvider的jar包可在本文末尾下载源码,从源码获取jar包。

  1. DES
    DES算法全称为Data Encryption Standard,即数据加密算法,它是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
    五种分组模式:EBC模式、CBC模式、CFB模式、OFB模式、CTR模式。
    其中CTR 模式被广泛用于 ATM 网络安全和 IPSec应用中,相对于其它模式而言,CRT模式具有如下特点:
    ■硬件效率:允许同时处理多块明文 / 密文。
    ■ 软件效率:允许并行计算,可以很好地利用 CPU 流水等并行技术。
    ■ 预处理:算法和加密盒的输出不依靠明文和密文的输入,因此如果有足够的保证安全的存储器,加密算法将仅仅是一系列异或运算,这将极大地提高吞吐量。
    ■ 随机访问:第 i 块密文的解密不依赖于第 i-1 块密文,提供很高的随机访问能力
    ■ 可证明的安全性:能够证明 CTR 至少和其他模式一样安全(CBC, CFB, OFB, ...)
    ■ 简单性:与其它模式不同,CTR模式仅要求实现加密算法,但不要求实现解密算法。对于 AES 等加/解密本质上不同的算法来说,这种简化是巨大的。
    ■ 无填充,可以高效地作为流式加密使用。
    在Java进行DES、3DES和AES三种对称加密算法时,常采用的是NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。
    示例:

/**
 * DES加密工具类
 * @author mazaiting
 */
public class DESUtil {
    /**
     * 算法名称
     */
    public static final String KEY_ALGORITHM = "DES";
    /**
     * 算法名称/加密模式/填充方式
     * DES的四种工作模式:ECB(电子密码本)、CBC(加密分组链接)、
     * CFB(加密反馈模式)、OFB(输出反馈)
     * 当前无填充的情况:
     *      加密数据必须为8的倍数,密钥输入必须为16的倍数
     *  使用
        String source = "abcdefgh";// 为8位的倍数
        String key = "A1B2C3D4E5F60708";// 为16位的倍数
        
        String encryptData = DESUtil.encrypt(source, key);
        System.out.println("加密后: " + encryptData);
        
        String decryptData = DESUtil.decrypt(encryptData, key);
        System.out.println("解密后: " + decryptData);
     */
    public static final String CIPHER_ALGORITHM_DES_ECB_NOPADDING = "DES/ECB/NoPadding";
    /**
     * DES/CBC/PKCS5Padding
     * PKCS5Padding填充时:
     *      加密数据无位数控制,密钥输入必须为16的倍数
     *  使用
        String source = "abcdefgh";// 无需控制位数
        String key = "A1B2C3D4E5F60708";// 为16位的倍数
        
        String encryptData = DESUtil.encrypt(source, key);
        System.out.println("加密后: " + encryptData);
        
        String decryptData = DESUtil.decrypt(encryptData, key);
        System.out.println("解密后: " + decryptData);
        
     */
    public static final String CIPHER_ALGORITHM_DES_ECB_PKCS5_PADDING = "DES/ECB/PKCS5Padding";
    
    /**
     * 加密数据
     * @param data 待加密的数据--8位
     * @param key 密钥--16位
     * @return 加密后的数据
     */
    public static String encrypt(String data, String key) {
        try {
            // 获得一个密钥
            Key deskey = keyGenerator(key);
            // 实例化一个Cipher(密码)对象,用于完成加密操作
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_DES_ECB_PKCS5_PADDING);
            SecureRandom random = new SecureRandom();
            // 初始化Cipher对象,设置为加密模式
            cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
            byte[] bytes = data.getBytes();
            // 执行加密操作
            byte[] results = cipher.doFinal(bytes);
            return Base64.encodeBase64String(results);
        } catch (InvalidKeyException e) {
            return "无效KEY"; // 无效KEY
        } catch (NoSuchAlgorithmException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (InvalidKeySpecException e) {
            return "无效KeySpec"; // 无效KeySpec
        } catch (NoSuchPaddingException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (IllegalBlockSizeException e) {
            return "无效字节"; // 无效字节
        } catch (BadPaddingException e) {
            return "解析异常"; // 解析异常
        }
    }

    /**
     * 解密数据
     * @param data 待解密数据
     * @param key 密钥
     * @return 解密后的数据
     */
    public static String decrypt(String data, String key) {
        try {
            Key desKey = keyGenerator(key);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_DES_ECB_PKCS5_PADDING);
            // 初始化Cipher对象,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, desKey);
            // 执行解密操作
            byte[] decBytes = cipher.doFinal(Base64.decodeBase64(data));
            return new String(decBytes,"UTF-8");
        } catch (InvalidKeyException e) {
            return "无效KEY"; // 无效KEY
        } catch (NoSuchAlgorithmException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (InvalidKeySpecException e) {
            return "无效KeySpec"; // 无效KeySpec
        } catch (NoSuchPaddingException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (IllegalBlockSizeException e) {
            return "无效字节"; // 无效字节
        } catch (BadPaddingException e) {
            return "解析异常"; // 解析异常
        } catch (UnsupportedEncodingException e) {
            return "编码异常"; // 编码异常
        }
    }
    
    /**
     * 生成密钥key对象
     * @param key 密钥字符串
     * @return 密钥对象
     * @throws InvalidKeyException 无效的key
     * @throws NoSuchAlgorithmException 算法名称未发现
     * @throws InvalidKeySpecException 无效的KeySpec
     */
    private static Key keyGenerator(String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] input = hexString2Bytes(key);
        DESKeySpec desKey = new DESKeySpec(input);
        // 创建一个密钥工厂,然后用它把DESKeySpec转化
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        // 获得一个密钥
        SecretKey secretKey = keyFactory.generateSecret(desKey);
        return secretKey;
    }

    /**
     * 从十六进制字符串到字节数组转化
     * @param key 密钥
     */
    private static byte[] hexString2Bytes(String key) {
        byte[] b = new byte[key.length()/2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = key.charAt(j++);
            char c1 = key.charAt(j++);
            // c0做b[i]的高字节,c1做低字节
            b[i] = (byte) ((parse(c0)<<4)|parse(c1));
        }
        return b;
    }

    /**
     * 将字符转换为int值
     * @param c 要转化的字符
     * @return ASCII码值
     */
    private static int parse(char c) {
        if (c >= 'a') {
            return (c - 'a' + 10) & 0x0f;
        }
        if (c >= 'A') {
            return (c - 'A' + 10) & 0x0f;
        }
        return (c - '0') & 0x0f;
    }   
}

  1. 3-DES
    3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法
    示例:
/**
 * 3-DES加密工具类
 * @author mazaiting
 */
public class ThreeDESUtil {
    /**
     * 算法名称
     */
    public static final String KEY_ALGORITHM = "desede";
    /**
     * 算法名称/加密模式/填充方式
     * 
        String source = "abcdefgh"; // 无填充情况下,长度必须为8的倍数
        String key = "6C4E60E55552386C759569836DC0F83869836DC0F838C0F7";// 长度必须大于等于48
        System.out.println(key.length());
        String encryptData = ThreeDESUtil.tDesEncryptCBC(source, key);
        System.out.println("加密后: " + encryptData);
        
        String decryptData = ThreeDESUtil.tDesDecryptCBC(encryptData, key);
        System.out.println("解密后: " + decryptData);  
     */
    public static final String CIPHER_ALGORITHM = "desede/CBC/NoPadding";
    /**
     * IvParameterSpec参数
     */
    public static final byte[] keyiv = { 1, 2, 3, 4, 5, 6, 7, 8 };
    
    /**
     * CBC加密
     * @param data 明文
     * @param key 密钥
     * @return Base64编码的密文
     */
    public static String tDesEncryptCBC(String data, String key){
        try {
            // 添加一个安全提供者
            Security.addProvider(new BouncyCastleProvider());
            // 获得密钥
            Key desKey = keyGenerator(key);
            // 获取密码实例
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            IvParameterSpec ips = new IvParameterSpec(keyiv);
            // 初始化密码
            cipher.init(Cipher.ENCRYPT_MODE, desKey, ips);
            // 执行加密
            byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
            return Base64.encodeBase64String(bytes);
        } catch (InvalidKeyException e) {
            return "无效KEY"; // 无效KEY
        } catch (NoSuchAlgorithmException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (InvalidKeySpecException e) {
            return "无效KeySpec"; // 无效KeySpec
        } catch (NoSuchPaddingException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (IllegalBlockSizeException e) {
            return "无效字节"; // 无效字节
        } catch (BadPaddingException e) {
            return "解析异常"; // 解析异常
        } catch (UnsupportedEncodingException e) {
            return "编码异常"; // 编码异常
        } catch (InvalidAlgorithmParameterException e) {
            return "摘要参数异常"; // 摘要参数异常
        }
    }
    
    /**
     * CBC解密
     * @param data Base64编码的密文
     * @param key 密钥
     * @return
     */
    public static String tDesDecryptCBC(String data, String key) {
        try {
            Key desKey = keyGenerator(key);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            IvParameterSpec ips = new IvParameterSpec(keyiv);
            cipher.init(Cipher.DECRYPT_MODE, desKey, ips);
            byte[] bytes = cipher.doFinal(Base64.decodeBase64(data));
            return new String(bytes, "UTF-8");
        } catch (InvalidKeyException e) {
            return "无效KEY"; // 无效KEY
        } catch (NoSuchAlgorithmException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (InvalidKeySpecException e) {
            return "无效KeySpec"; // 无效KeySpec
        } catch (NoSuchPaddingException e) {
            return "无效算法名称"; // 无效算法名称
        } catch (IllegalBlockSizeException e) {
            return "无效字节"; // 无效字节
        } catch (BadPaddingException e) {
            return "解析异常"; // 解析异常
        } catch (UnsupportedEncodingException e) {
            return "编码异常"; // 编码异常
        } catch (InvalidAlgorithmParameterException e) {
            return "摘要参数异常"; // 摘要参数异常
        }
    }
    
    
    /**
     * 生成密钥key对象
     * @param key 密钥字符串
     * @return 密钥对象
     * @throws InvalidKeyException 无效的key
     * @throws NoSuchAlgorithmException 算法名称未发现
     * @throws InvalidKeySpecException 无效的KeySpec
     */
    private static Key keyGenerator(String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] input = hexString2Bytes(key);
        DESedeKeySpec desKey = new DESedeKeySpec(input);
        // 创建一个密钥工厂,然后用它把DESKeySpec转化
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        // 获得一个密钥
        SecretKey secretKey = keyFactory.generateSecret(desKey);
        return secretKey;
    }

    /**
     * 从十六进制字符串到字节数组转化
     * @param key 密钥
     */
    private static byte[] hexString2Bytes(String key) {
        byte[] b = new byte[key.length()/2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = key.charAt(j++);
            char c1 = key.charAt(j++);
            // c0做b[i]的高字节,c1做低字节
            b[i] = (byte) ((parse(c0)<<4)|parse(c1));
        }
        return b;
    }

    /**
     * 将字符转换为int值
     * @param c 要转化的字符
     * @return ASCII码值
     */
    private static int parse(char c) {
        if (c >= 'a') {
            return (c - 'a' + 10) & 0x0f;
        }
        if (c >= 'A') {
            return (c - 'A' + 10) & 0x0f;
        }
        return (c - '0') & 0x0f;
    }   
    
}
  1. AES加密
    AES是分组密钥,算法输入128位数据,密钥长度也是128位。

/**
 * AES加密工具类
 * <p>
 * 使用:
 * String source = "mazaiting";
 * String key = "123456";
 * <p>
 * String encryptString = AesUtil.encrypt(source, key);
 * System.out.println("加密后: " + encryptString);
 * <p>
 * String decryptString = AesUtil.decrypt(encryptString, key);
 * System.out.println("解密后: " + decryptString);
 * 需要依赖:compile 'commons-codec:commons-codec:1.11'
 * @author mazaiting
 */
public class AesUtil {
  /**
   * 算法名称
   */
  private static final String KEY_ALGORITHM = "AES";
  /**
   * 算法
   */
  private static final String CIPHER_ALGORITHM = "AES";
  
  /**
   * 加密数据
   *
   * @param data 待加密内容
   * @param key  加密的密钥
   * @return 加密后的数据
   */
  public static String encrypt(String data, String key) {
    try {
      // 获得密钥
      Key deskey = keyGenerator(key);
      // 实例化一个密码对象
      Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
      // 密码初始化
      cipher.init(Cipher.ENCRYPT_MODE, deskey);
      // 执行加密
      byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
      // 返回Base64编码后的字符串
      return Base64.encodeBase64String(bytes);
    } catch (NoSuchAlgorithmException e) {
      return "加密名称异常"; // 获取加密名称异常
    } catch (UnsupportedEncodingException e) {
      return "未知编码格式"; // 未知编码格式
    } catch (InvalidKeyException e) {
      return "无效Key"; // 无效Key
    } catch (NoSuchPaddingException e) {
      return "无效密码算法"; // 无效密码算法
    } catch (IllegalBlockSizeException e) {
      return "无效字节"; // 无效字节
    } catch (BadPaddingException e) {
      return "解析异常"; // 解析异常
    }
  }
  
  /**
   * 解密数据
   *
   * @param data 待解密的内容
   * @param key  解密的密钥
   * @return 解密后的文字
   */
  public static String decrypt(String data, String key) {
    try {
      // 生成密钥
      Key kGen = keyGenerator(key);
      // 实例化密码对象
      Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
      // 初始化密码对象
      cipher.init(Cipher.DECRYPT_MODE, kGen);
      // 执行解密
      byte[] bytes = cipher.doFinal(Base64.decodeBase64(data));
      // 返回解密后的字符串
      return new String(bytes, "UTF-8");
    } catch (NoSuchAlgorithmException e) {
      return "加密名称异常"; // 获取加密名称异常
    } catch (UnsupportedEncodingException e) {
      return "未知编码格式"; // 未知编码格式
    } catch (InvalidKeyException e) {
      return "无效Key"; // 无效Key
    } catch (NoSuchPaddingException e) {
      return "无效密码算法"; // 无效密码算法
    } catch (IllegalBlockSizeException e) {
      return "无效字节"; // 无效字节
    } catch (BadPaddingException e) {
      return "解析异常"; // 解析异常
    }
  }
  
  /**
   * 获取密钥
   *
   * @param key 密钥字符串
   * @return 返回一个密钥
   * @throws NoSuchAlgorithmException
   * @throws UnsupportedEncodingException
   */
  private static Key keyGenerator(String key) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    KeyGenerator kGen = KeyGenerator.getInstance(KEY_ALGORITHM);
    kGen.init(128, new SecureRandom(hexString2Bytes(key)));
    SecretKey secretKey = kGen.generateKey();
    byte[] encoded = secretKey.getEncoded();
    return new SecretKeySpec(encoded, KEY_ALGORITHM);
  }
  
  
  /**
   * 从十六进制字符串到字节数组转化
   *
   * @param key 密钥
   */
  private static byte[] hexString2Bytes(String key) {
    byte[] b = new byte[key.length() / 2];
    int j = 0;
    for (int i = 0; i < b.length; i++) {
      char c0 = key.charAt(j++);
      char c1 = key.charAt(j++);
      // c0做b[i]的高字节,c1做低字节
      b[i] = (byte) ((parse(c0) << 4) | parse(c1));
    }
    return b;
  }
  
  /**
   * 将字符转换为int值
   *
   * @param c 要转化的字符
   * @return ASCII码值
   */
  private static int parse(char c) {
    if (c >= 'a') {
      return (c - 'a' + 10) & 0x0f;
    }
    if (c >= 'A') {
      return (c - 'A' + 10) & 0x0f;
    }
    return (c - '0') & 0x0f;
  }
}

代码下载

上一篇下一篇

猜你喜欢

热点阅读