java实现对称加密—基本实现

文章目录

  • 前言
  • 一、什么是对称密码体制
  • 二、对称加密算法家谱
  • 三、java代码实现
    • 1.引入jar包
    • 2.DES实现
    • 3.AES实现
  • 四、分组密码的工作模式
  • 总结


前言

项目中经常会对数据库的密码加密后放到配置文件中,启动项目连接数据库时再对其进行解密,此加密与解密过程一般采用对称加密算法。本篇主要介绍什么是对称加密算法及如何用java实现,之后一篇说明项目中的实际应用


一、什么是对称密码体制

对称密码体制的保密通信模型如下图所示,解密是加密的逆运算。通信双方共享同一个密钥,该密钥称为秘密密钥。
java实现对称加密—基本实现_第1张图片
对称密码根据加密方式分为两种:一种是对明文的单个位(或字节)进行运算,称为流密码(这里不做介绍),另一种是把明文信息划分成不同的组结构,分别对每个组进行加密与解密,称为分组密码(重点)。
分组密码又有不同的工作模式,如ECB模式,CBC模式,CFB模式等。

二、对称加密算法家谱

java实现对称加密—基本实现_第2张图片
目前已知通过java语言实现的对称密码算法有20多种,如常用的DES,DESede,AES,Blowfish等算法。其他算法(如IDEA算法)需要通过第三方机密软件包Bouncy Castle算法提供实现。
DES算法密钥偏短,仅56位,迭代次数偏少,已不安全。笔者在实际项目中使用最多的AES算法

三、java代码实现

1.引入jar包

JDK提供了多种算法支持,但并不完善,许多加密强度较高的算法,JDK未能提供,我们可以引入Bouncy Castle

<dependency>
     <groupId>org.bouncycastlegroupId>
     <artifactId>bcprov-jdk15onartifactId>
     <version>1.67version>
 dependency>

Commons Codec对JDK原生api进行了良好的封装,提高了方法的易用性

 <dependency>
      <groupId>commons-codecgroupId>
      <artifactId>commons-codecartifactId>
      <version>1.14version>
 dependency>

2.DES实现

密钥长度与安全性成正比,jdk仅支持56位密钥长度,作为补充Bouncy Castle提供了64位密钥长度支持

算法 密钥长度 长度默认值 工作模式 填充方式 备注
DES 56 56 ECB、CBC、PCBC、CTR等 NoPadding
PKCS5Pading
ISO10126Padding
java8实现
DES 64 56 同上 同上
PKCS7Pading等
Bouncy Castle实现
public class DESUtil {
    public static void main(String[] args) throws Exception {
        byte[] plainTxt = "helloWorld".getBytes(StandardCharsets.UTF_8);
        byte[] key = initKey();
        System.out.println("key:" + Base64.getEncoder().encodeToString(key));
        // Wrong IV length: must be 8 bytes long
        byte[] salt = secureRandom(8);
        byte[] encrypt = encrypt(plainTxt, salt, key);
        System.out.println("after encrypt:" + Base64.getEncoder().encodeToString(encrypt));
        byte[] decrypt = decrypt(encrypt, salt, key);
        System.out.println("after decrypt:" + new String(decrypt, StandardCharsets.UTF_8));
    }

    /**
     * 密钥算法
     */
    private static final String KEY_ALGORITHM = "DES";

    /**
     * 加密/解密
     * 

* 算法/工作模式/填充方式 * ECB mode cannot use IV(注意有些工作模式不支持IV) * Wrong IV length: must be 8 bytes long */ private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding"; private static Key toKey(byte[] key) throws Exception { DESKeySpec spec = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM); return keyFactory.generateSecret(spec); } /** * 加密 * @param data 明文 * @param salt IV * @param key 密钥材料 * @return 密文 * @throws Exception Exception */ private static byte[] encrypt(byte[] data, byte[] salt, byte[] key) throws Exception { Key k = toKey(key); // Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, new BouncyCastleProvider()); cipher.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(salt)); return cipher.doFinal(data); } /** * 解密 * @param data 密文 * @param salt iv(解密跟加密操作需使用同一个iv) * @param key 密钥 * @return byte[] 明文 * @throws Exception Exception */ private static byte[] decrypt(byte[] data, byte[] salt, byte[] key) throws Exception { Key k = toKey(key); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, new BouncyCastleProvider()); // Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(salt)); return cipher.doFinal(data); } /** * 生成密钥 * Java只支持56位密钥 * Bouncy Castle支持64位密钥 * * @return byte[] 二进制密钥 * @throws Exception Exception */ private static byte[] initKey() throws Exception { // new BouncyCastleProvider() 表示采用Bouncy Castle实现 KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM, new BouncyCastleProvider()); // KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM); /** * Wrong keysize: must be equal to 56 * sun的长度只能是56 * bouncycastle的长度可以是64 */ // kg.init(56); kg.init(64); SecretKey secretKey = kg.generateKey(); return secretKey.getEncoded(); } /** * 获取指定长度IV值 * * @param len 长度 * @return byte[] * @throws NoSuchAlgorithmException */ private static byte[] secureRandom(int len) throws NoSuchAlgorithmException { SecureRandom random = SecureRandom.getInstanceStrong(); byte[] bytes = new byte[len]; random.nextBytes(bytes); return bytes; } }

3.AES实现

AES算法成为DES算法的替代者,其实现称为其他对称加密算法实现的参考模型。以下为实现细节

算法 密钥长度 长度默认值 工作模式 填充方式 备注
AES 128、192、256 128 ECB、CBC、PCBC、CTR、CTS、CFB等 NoPadding
PKCS5Pading
ISO10126Padding
java8实现
AES 同上 同上 同上 同上
PKCS7Padding
ZeroBytePadding
Bouncy Castle实现
public class AESUtil {
    public static void main(String[] args) throws Exception {
        byte[] plainTxt = "helloWorld".getBytes(StandardCharsets.UTF_8);
        byte[] key = initKey();
        System.out.println("key:" + Base64.getEncoder().encodeToString(key));
        // Wrong IV length: must be 16 bytes long
        byte[] salt = secureRandom(16);
        byte[] encrypt = encrypt(plainTxt, salt, key);
        System.out.println("after encrypt:" + Base64.getEncoder().encodeToString(encrypt));
        byte[] decrypt = decrypt(encrypt, salt, key);
        System.out.println("after decrypt:" + new String(decrypt, StandardCharsets.UTF_8));
    }

    /**
     * 密钥算法
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * 加密/解密
     * 

* 算法/工作模式/填充方式 * ECB mode cannot use IV */ private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding"; private static Key toKey(byte[] key) throws Exception { SecretKeySpec keySpec = new SecretKeySpec(key, KEY_ALGORITHM); return keySpec; } private static byte[] encrypt(byte[] data, byte[] salt, byte[] key) throws Exception { Key k = toKey(key); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,new BouncyCastleProvider()); // Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(salt)); return cipher.doFinal(data); } private static byte[] decrypt(byte[] data, byte[] salt, byte[] key) throws Exception { Key k = toKey(key); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,new BouncyCastleProvider()); // Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(salt)); return cipher.doFinal(data); } private static byte[] initKey() throws NoSuchAlgorithmException { KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM); /** * Wrong keysize: must be equal to 128, 192 or 256 * 128 或者192 或256 */ kg.init(128); SecretKey secretKey = kg.generateKey(); return secretKey.getEncoded(); } private static byte[] secureRandom(int len) throws NoSuchAlgorithmException { SecureRandom random = SecureRandom.getInstanceStrong(); byte[] bytes = new byte[len]; random.nextBytes(bytes); return bytes; } }

四、分组密码的工作模式

分组密码对固定长度的一组明文进行加密,这一固定长度称为分组长度。分组长度与安全性成正比。
DES算法的分组长度是56位。但56位的分组长度已经不安全了,目前分组密码多选择128位作为算法的分组长度,如AES算法的分组长度就是128位
DES算法根据其加密算法所定义的明文分组的大小(56位),将数据分隔成若干56位的加密区块,再以加密区块为单位,分别进行加密处理。如果最后剩下不足一个区块的大小,称之为短块,短块的处理方法有填充法,流密码加密法等
根据数据加密时每个加密区块之间的关联方式,可以分为以下4种工作模式

  • 电子密码本模式——ECB
  • 密文连接模式——CBC
  • 密文反馈模式——CFB
  • 输出反馈模式——OFB

AES算法在DES算法工作模式的基础上,还推荐了一种新的工作模式——计数器模式(CTR)
下面以项目中用到的CBC模式为例,画出其流程图
java实现对称加密—基本实现_第3张图片


总结

DES算法已不具备安全性,建议选择AES算法。笔者在项目中使用的对称加密算法为AES/CBC/PKCS5Padding,密钥长度为128和256位两种。AES算法的分组长度固定为128位,其强度由密钥长度决定。

你可能感兴趣的:(java加密与解密,java,加密解密,密码学)