天天看點

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. 總結

附加