天天看点

Java实现对称密钥算法

1.简介

对称密钥算法(英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。事实上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通信联系。与公开密钥加密相比,要求双方获取相同的密钥是对称密钥加密的主要缺点之一。

常见的对称加密算法有AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。对称加密的速度比公钥加密快很多,在很多场合都需要对称加密。

  • 对称加密算法消息传递图示
Java实现对称密钥算法

2. 对称密钥算法--DES

DES算法在98年之后不断的被破解,当下DES的加密已经不具备安全性了,所以现在一个新项目或者没有使用过加密算法的应用,在加密算法选型的时候不用考虑DES算法。DES目前只出现在一些介绍、案例或者一些遗留的软件或者硬件中。

在这里介绍下DES算法,因为DES在加密算法(尤其是对称加密算法)中的地位是非常高的。

DES(Data Encryption Standard)数据加密标准

密钥长度 默认 工作模式 填充方式 实现方
56 56 ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128

NoPadding、

PKCS5Padding、

ISO10126Padding

JDK
64 56 ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128

PKCS7Padding、

SO10126d2Padding、

X032Padding、

ISO7816d4Padding、

ZeroBytePadding

Bouncy

Castle

DES加密示例:

package com.bity.des;

import org.apache.commons.codec.binary.Hex;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import static java.lang.System.*;

/**
 * <p>Title: JdkDes</p >
 * <p>Description: DES加密算法 </p >
 * <p>Company: http://www.agree.com</p >
 * <p>Project: security</p >
 *
 * @author <a href="mailto:[email protected]">WEIQI</a>
 * @version 1.0
 * @date 2022-04-26 20:21
 */
public class JdkDes {
    
    private static final String SRC = "I'm DES encryption algorithm";
    
    public static void main(String[] args) {
        jdkDes();
    }
    
    /**
     * JDK-DES对称密钥算法实现
     * 
     * @author: <a href="mailto:[email protected]">WEIQI</a>
     * @date: 2022-04-26 20:41
     */
    private static void jdkDes() {
        try {
            // generator KEY
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] bytesKey = secretKey.getEncoded();
            
            // convert KEY
            DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
            Key convertSecureKey = secretKeyFactory.generateSecret(desKeySpec);
            
            // encryption
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecureKey);
            byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
            
            out.println("encryption result is : " + Hex.encodeHexString(result));
            
            //decrypt
            cipher.init(Cipher.DECRYPT_MODE, convertSecureKey);
            result = cipher.doFinal(result);
    
            out.println("decrypt result is : " + new String(result));
        } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
    }
}      

运行结果如下:

encryption result is : 97919bd6b4d1590e773fdc1100564f1fecb6d585cb80015b080bb75c29f15d4d
decrypt result is : I'm DES encryption algorithm      

DES加密算法消息传递如下所示:

Java实现对称密钥算法

3. 对称密钥算法--3重DES

3重DES的出现是因为DES算法是半公开的,这点恰好违反了柯克霍夫原则,安全性也有问题。3重DES对密码长度做了增强、迭代次数进行了提高,是目前实际应用中用得最多的。

3DES(Triple DESDESede)

密钥长度 默认 工作模式 填充方式 实现方

112

168

168 ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128

NoPadding、

PKCS5Padding、

ISO10126Padding

JDK

128

192

168 ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128

PKCS7Padding、

SO10126d2Padding、

X032Padding、

ISO7816d4Padding、

ZeroBytePadding

Bouncy

Castle

3DES加密示例:

package com.bity.des;

import org.apache.commons.codec.binary.Hex;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import static java.lang.System.out;

/**
 * <p>Title: Jdk3Des</p >
 * <p>Description: 3DES加密算法实践 </p >
 * <p>Company: http://www.agree.com</p >
 * <p>Project: security</p >
 *
 * @author <a href="mailto:[email protected]">WEIQI</a>
 * @version 1.0
 * @date 2022-04-26 20:55
 */
public class Jdk3Des {
    private static final String SRC = "I'm 3DES encryption algorithm";
    
    public static void main(String[] args) {
        jdk3Des();
    }
    
    /**
     * JDK-DES对称密钥算法实现
     *
     * @author: <a href="mailto:[email protected]">WEIQI</a>
     * @date: 2022-04-26 20:41
     */
    private static void jdk3Des() {
        try {
            // generator KEY
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            keyGenerator.init(168);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] bytesKey = secretKey.getEncoded();
            
            // convert KEY
            DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
            Key convertSecureKey = secretKeyFactory.generateSecret(desKeySpec);
            
            // encryption
            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecureKey);
            byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
            
            out.println("encryption result is : " + Hex.encodeHexString(result));
            
            //decrypt
            cipher.init(Cipher.DECRYPT_MODE, convertSecureKey);
            result = cipher.doFinal(result);
            
            out.println("decrypt result is : " + new String(result));
        } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
    }
}      

运行结果:

encryption result is : c44fb80f098ba6d601032abd18b71cee83f7b533b053c227350cfc89892143cb
decrypt result is : I'm 3DES encryption algorithm      

4. 对称密钥算法--AES

由于DES安全性没有了保证,3DES性能比较低,所以出现了AES对称加密算法。AES是目前使用最多的对称加密算法,AES至今尚未被破解。该算法通常用于移动通信系统的加密以及基于SSH协议的软件。

AES(Advanced Encryption Standard)

密钥长度 默认 工作模式 填充方式 实现方
128、192、256 128 ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128

NoPadding、

PKCS5Padding、

ISO10126Padding

JDK
128、192、256 128 ECB、CBC、PCBC、CTR、CTS、CFB、CFB8到128、OFB、OFB8到128

PKCS7Padding、

ZeroBytePadding

Bouncy

Castle

这里注意:JDK实现方256位密钥需要获得无政策限制权限文件。无政策限制文件是指因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。

AES加密示例:

package com.bity.aes;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import static java.lang.System.*;

/**
 * <p>Title: JdkAes</p >
 * <p>Description: </p >
 * <p>Company: http://www.agree.com</p >
 * <p>Project: security</p >
 *
 * @author <a href="mailto:[email protected]">WEIQI</a>
 * @version 1.0
 * @date 2022-04-26 21:09
 */
public class JdkAes {
    private static final String SRC = "I'm AES encryption algorithm";
    
    public static void main(String[] args) {
        jdkAes();
    }
    
    /**
     * JDK-AES加密实现
     * 
     * @author: <a href="mailto:[email protected]">WEIQI</a>
     * @date: 2022-04-26 21:17
     */
    private static void jdkAes() {
        
        try {
            // generator KEY
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] bytesKey = secretKey.getEncoded();
    
            // convert KEY
            Key key = new SecretKeySpec(bytesKey, "AES");
            
            // encryption
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
    
            out.println("aes encryption result is : " + Base64.encodeBase64String(result));
            
            //decrypt
            cipher.init(Cipher.DECRYPT_MODE, key);
            result = cipher.doFinal(result);
            
            out.println("aes decrypt result is : " + new String(result));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
    }
}
      

运行结果:

aes encryption result is : zbnnZOB0dwJH4V/zeNVbOEjDR5/ltFZXkqqZY7Y+JHw=
aes decrypt result is : I'm AES encryption algorithm      

5. 对称密钥算法--PBE

PBE算法结合了消息摘要算法和对称加密算法的优点,对已有算法进行包装,形成了一个特殊的对称加密算法。

PBE算法消息通信

Java实现对称密钥算法

PBE(Password Based Encryption)基于口令的加密

算法 密钥长度 默认 工作方式 填充方式 实现
PBEWithMD5AndDES 64 64 CBC

PKCS5Padding

PKCS7Padding

ISO10126Padding

ZeroBytePadding

BC
PBEWithMD5AndRC2 112 112
PBEWithSHA1AndDES 64 64
PBEWithSHA1AndRC2 128 128
PBEWithSHAAndIDEA-CBC 128 128
PBEWithSHAAnd2-KeyTripleDES-CBC 128 128
PBEWithSHAAnd3-KeyTripleDES-CBC 128 128

PBE加密示例

package com.bity.pbe;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * <p>Title: JdkPbe</p >
 * <p>Description: PBE算法实现 </p >
 * <p>Company: http://www.agree.com</p >
 * <p>Project: security</p >
 *
 * @author <a href="mailto:[email protected]">WEIQI</a>
 * @version 1.0
 * @date 2022-04-26 21:37
 */
public class JdkPbe {
    
    private static final String SRC = "I'm PBE encryption algorithm";
    
    public static void main(String[] args) {
        jdkPbe();
    }
    
    private static void jdkPbe() {
        try {
            // 初始化盐
            SecureRandom random = new SecureRandom();
            byte[] salt = random.generateSeed(8);
            
            // 口令和密钥
            String token = "Abcd1234!@#$";
            PBEKeySpec pbeKeySpec = new PBEKeySpec(token.toCharArray());
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
            Key key = factory.generateSecret(pbeKeySpec);
            
            // 加密
            PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 100);
            Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES");
            cipher.init(Cipher.ENCRYPT_MODE, key, pbeParameterSpec);
            byte[] result = cipher.doFinal(SRC.getBytes(StandardCharsets.UTF_8));
            
            System.out.println("pbe encryption result is : " + Base64.encodeBase64String(result));
            
            // 解密
            cipher.init(Cipher.DECRYPT_MODE, key, pbeParameterSpec);
            result = cipher.doFinal(result);
            
            System.out.println("pbe decrypt reult is : " + new String(result));
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
        
    }
}
      

运行结果:

pbe encryption result is : 1VcN0rTwdFxFgtKtedxnD2Zr3em8/tKWmg0vW1W6Abk=
pbe decrypt reult is : I'm PBE encryption algorithm      

6. 总结

附加