對稱加密算法實踐與總結

序言

對稱加密算法,加密與解密的密鑰是一樣的,密鑰管理比較困難,容易泄露,一旦泄露就會很容易導致數據不安全。

相關概念

明文: 數據沒有進行加密,原始數據信息。

密文: 加密過後得到的數據, 隱藏了原始數據的含義。

加密 : 將明文轉爲密文的過程。

解密 : 將密文轉爲明文的過程。

密鑰: 是一種參數,是在加密或解密中輸入的參數。

對稱加密

定義: 指的是加密與解密使用相同的密鑰。這種加密方式稱爲對稱加密。

對稱加密一般有: DES 、 3DES 、 AES 、 PBE

  • DES(Data Encryption Standard): 數據加密標準,速度較快,適用於加密大量數據的場合。
  • 3DES(Triple DES): 基於DES, 對一塊數據用三個不同的密鑰進行三次加密,強度更高。
  • AES(Advanced Encryption Standard): 高級加密標準,是下一代的加密算法標準,速度快,安全級別高,支持128、192、256、512位密鑰的加密。
  • PBE(Password Based Encryption): 是一種基於口令的加密算法,其特點是使用口令代替了密鑰,而口令由用戶自己掌管,採用隨機數雜湊多重加密等方法保證數據的安全性。

對稱加密特徵:

  • 加密方和解密方使用同一個密鑰。
  • 加密與解密的速度較快。
  • 密鑰傳輸過程不安全,且容易被破解,密鑰管理也很麻煩。

代碼實現:

DES算法

 /**
 * @program
 * @Desc
 * @Author 遊戲人日常
 * @CreateTime 2019/08/11--2:21
 */
public class DesTest {
    //轉化格式
    public static final String TRAMSFORMATION = "DES/ECB/PKCS5Padding";
    //算法  DES
    public static final String ALGORITHM = "DES";
    //待加密的源串
    public static final String msg = "helloWorld";
    //密鑰
    public static final String key = "123456789";

    public static void main(String args[]) {
        System.out.println("待加密數據: " + msg);
        byte[] encryptStr = encrypt(msg, key);
        System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
        byte[] decryptStr = decrypt(encryptStr, key);
        System.out.println("解密後的結果:" + new String(decryptStr));
    }

    /**
     *    解密
     * @param encryptionStr  加密的數據
     * @param key  密鑰
     * @return
     */
    private static byte[] decrypt(byte[] encryptionStr, String key) {
        try {
            //1.KEY轉換
            DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());//實例化DESKey祕鑰的相關內容
            SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);//實例一個祕鑰工廠,指定加密方式
            Key convertKey  = factory.generateSecret(desKeySpec);

            //2.解密    DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
            cipher.init(Cipher.DECRYPT_MODE, convertKey );
            byte[] result = cipher.doFinal(encryptionStr);

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * @param encryptionStr 待加密的串
     * @param key           密鑰
     * @return
     */
    public static byte[] encrypt(String encryptionStr, String key) {
        try {
            //1.KEY轉換
            DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());//實例化DESKey祕鑰的相關內容
            SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);//實例一個祕鑰工廠,指定加密方式
            Key convertKey  = factory.generateSecret(desKeySpec);

            //2.加密    DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
            cipher.init(Cipher.ENCRYPT_MODE, convertKey );
            byte[] result = cipher.doFinal(encryptionStr.getBytes());//輸入要加密的內容

            return result;

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

輸出結果

待加密數據: helloWorld
加密後以十六進制輸出的結果: -60fd73ff69e3352e5e2e976c55e6ed92
解密後的結果:helloWorld

3DES算法

/**
 * @program
 * @Desc
 * @Author 遊戲人日常
 * @CreateTime 2019/08/11--14:45
 */
public class DES3Test {

    //轉化格式
    public static final String TRAMSFORMATION = "DESEde/ECB/PKCS5Padding";
    //算法  DES
    public static final String ALGORITHM = "DESEde";
    //待加密的源串
    public static final String msg = "helloWorld";
    //密鑰
    public static final String key = "1234567812345678123456789";

    public static void main(String[] args) {
        System.out.println("待加密數據: " + msg);
        byte[] encryptStr = encrypt(msg, key);
        System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
        byte[] decryptStr = decrypt(encryptStr, key);
        System.out.println("解密後的結果:" + new String(decryptStr));
    }

    /**
     * 解密
     *
     * @param encryptionStr 加密的數據
     * @param key           密鑰
     * @return
     */
    private static byte[] decrypt(byte[] encryptionStr, String key) {
        try {
            //1.生成KEY
            DESedeKeySpec desKeySpec = new DESedeKeySpec(key.getBytes());//實例化DESKey祕鑰的相關內容
            SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);//實例一個祕鑰工廠,指定加密方式
            Key convertKey  = factory.generateSecret(desKeySpec);

            //2.解密    DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
            cipher.init(Cipher.DECRYPT_MODE, convertKey );
            byte[] result = cipher.doFinal(encryptionStr);

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] encrypt(String encryptionStr, String key) {
        try {

            //1.轉換KEY
            DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(key.getBytes());
            SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
            Key convertKey = factory.generateSecret(deSedeKeySpec);

            //2.加密
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, convertKey);
            byte[] result = cipher.doFinal(encryptionStr.getBytes());
            return result;

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

輸出結果

待加密數據: helloWorld
加密後以十六進制輸出的結果: -60fd73ff69e3352e5e2e976c55e6ed92
解密後的結果:helloWorld

AES算法

/**
 * @program
 * @Desc
 * @Author 遊戲人日常
 * @CreateTime 2019/08/11--15:16
 */
public class AESTest {

    //轉化格式
    public static final String TRAMSFORMATION = "AES/ECB/PKCS5Padding";
    //算法  DES
    public static final String ALGORITHM = "AES";
    //待加密的源串
    public static final String msg = "helloWorld";
    //密鑰
    public static final String key = "1234567812345678";

    public static void main(String[] args) {
        System.out.println("待加密數據: " + msg);
        byte[] encryptStr = encrypt(msg, key);
        System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
        byte[] decryptStr = decrypt(encryptStr, key);
        System.out.println("解密後的結果:" + new String(decryptStr));
    }

    /**
     * 解密
     *
     * @param encryptionStr 加密的數據
     * @param key           密鑰
     * @return
     */
    private static byte[] decrypt(byte[] encryptionStr, String key) {
        try {
            //1.轉換KEY
            Key convertKey = new SecretKeySpec(key.getBytes(), ALGORITHM);

            //2.解密    DES/ECB/PKCS5Padding--->算法/工作方式/填充方式
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);//通過Cipher這個類進行加解密相關操作
            cipher.init(Cipher.DECRYPT_MODE, convertKey);
            byte[] result = cipher.doFinal(encryptionStr);

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] encrypt(String encryptionStr, String key) {
        try {
            //1.轉換KEY
            Key convertKey = new SecretKeySpec(key.getBytes(), ALGORITHM);

            //2.加密
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, convertKey);
            byte[] result = cipher.doFinal(encryptionStr.getBytes());

            return result;

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

輸出結果

待加密數據: helloWorld
加密後以十六進制輸出的結果: -680bb3194a04ff1ece4e28227012ad33
解密後的結果:helloWorld

PBE算法

/**
 * @program
 * @Desc
 * @Author 遊戲人日常
 * @CreateTime 2019/08/11--15:55
 */
public class PBETest {
    //轉化格式
    public static final String TRAMSFORMATION = "PBEWITHMD5andDES";
    //待加密的源串
    public static final String msg = "helloWorld";
    //密鑰
    public static final String key = "123456789";

    public static void main(String args[]) {
        byte[] salt=initSalt();//初始化salt
        System.out.println("待加密數據: " + msg);
        byte[] encryptStr = encrypt(salt,msg,key);
        System.out.println("加密後以十六進制輸出的結果: " + new BigInteger(encryptStr).toString(16));//以十六進制輸出
        byte[] decryptStr = decrypt(salt,encryptStr, key);
        System.out.println("解密後的結果:" + new String(decryptStr));
    }

     public static byte[] initSalt(){
         SecureRandom secureRandom = new SecureRandom();
         byte[] salt = secureRandom.generateSeed(8);
         return salt;
     }

    /**
     *    解密
     * @param  salt
     * @param encryptionStr  加密的數據
     * @param key   這個是加密用的口令
     * @return
     */
    private static byte[] decrypt(byte[] salt, byte[] encryptionStr, String key) {
        try {
            //1.轉換KEY
            PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray());
            SecretKeyFactory factory = SecretKeyFactory.getInstance(TRAMSFORMATION);
            Key convertKey = factory.generateSecret(pbeKeySpec);
            //2.解密
            PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);//100是你選擇迭代的次數
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, convertKey, parameterSpec);
            byte[] result = cipher.doFinal(encryptionStr);

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
	 * 加密
     * @param  salt
     * @param encryptionStr 待加密的串
     * @param key           這個是加密用的口令
     * @return
     */
    public static byte[] encrypt(byte[] salt,String encryptionStr,String key) {
        try {
            //1.轉換KEY
            PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray());
            SecretKeyFactory factory = SecretKeyFactory.getInstance(TRAMSFORMATION);
            Key convertKey = factory.generateSecret(pbeKeySpec);
            //2. 加密
            PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);//100是你選擇迭代的次數
            Cipher cipher = Cipher.getInstance(TRAMSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, convertKey, parameterSpec);
            byte[] result = cipher.doFinal(encryptionStr.getBytes());

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

輸出結果

待加密數據: helloWorld
加密後以十六進制輸出的結果: 450056595e1fbcc4f35bf855bd18dee2
解密後的結果:helloWorld

總結

  1. 這些對稱算法全是JDK自帶的API實現,也可以用第三方(BouncyCastle)的實現。
  2. 不同的算法對key的長度有要求,通過查看jdk代碼發現DES的key必須大於8,3DES大於24等等。 否則會拋異常:Wrong key size
  3. 這些對稱算法的底層原理是怎麼實現的本文沒有敘述,具體怎麼實現請查看其它的資料。

對稱算法優缺點

優點

速度快,通常在消息發送方需要加密大量數據時使用,算法公開、計算量小、加密速度快、加密效率高。

缺點

在數據傳輸前,發送和接收方必須確定好密鑰,然後雙方都能保存這個密鑰,一旦泄露那麼數據的傳輸這個過程就很不安全。

一個遊戲技術人,分享Java、Python、H5、Android 等知識。同時會分享遊戲行業日常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章