閱讀794 返回首頁    go 阿裏雲 go 技術社區[雲棲]


JAVA加密與解密

摘要算法
摘要算法主要包含三大類型:MD算法,SHA算法,已經基於KEY的MAC算法

MD算法
MD算法主要有MD2,MD3,MD4以及最常用的MD5。
SHA算法主要有SHA-1,SHA-224,SHA-256,SHA-384,SHA-512。
MAC算法是基於哈西散列算法(MD係列或者SHA係列等),在HASH散列進行KEY加密

JAVA密碼體係對主流摘要算法的支持
screenshot

MD5算法的調用示例

package com.rcl.platform.demo;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.Security;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class ProviderTest {

    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.update("我是MD".getBytes());
        byte [] md5 = messageDigest.digest();
        System.out.println(byte2HexStr(md5));


        Security.addProvider(new BouncyCastleProvider());//注冊BouncyCastleProvider
        Provider provider = Security.getProvider("BC");
        messageDigest = MessageDigest.getInstance("MD4", provider);
        messageDigest.update("我是MD".getBytes());
        byte [] md4 = messageDigest.digest();
        System.out.println(byte2HexStr(md4));

        messageDigest = MessageDigest.getInstance("SHA512");//調用SHA算法
        messageDigest.update("我是SHA".getBytes());
        byte [] sha512 = messageDigest.digest();
        System.out.println(byte2HexStr(sha512));

        SecretKey secretKey = new SecretKeySpec("woshikey".getBytes(), "HmacSHA512");//HMAC算法調用
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        byte [] hmacSHA224 = mac.doFinal("我是SHA".getBytes());
        System.out.println(byte2HexStr(hmacSHA224));


    }

    public static String byte2HexStr(byte[] b) {    
        String stmp="";    
        StringBuilder sb = new StringBuilder("");    
        for (int n=0;n<b.length;n++) {    
            stmp = Integer.toHexString(b[n] & 0xFF);    
            sb.append((stmp.length()==1)? "0"+stmp : stmp);    
            sb.append("");    
        }    
        return sb.toString().toLowerCase().trim();    
    }  


}

執行結果

f610c6a17a31eec9d36c5ef646149ea6
d40694ae1650fdb9bfe807833a3b6c89
e7046e9687398575eadf7eadf5854103b9a98fbedc1333cd553bc288b3518f997884cb7b827bc789b973d2dcf818253359133361602518d045d2cc2ff0eb0871
4e8f13266500448abf27d54aeaeb7825ed62c62d6c40633b3066faf10f6b3b9e933ec2e335b9ab5388da1c09161bf75a2e6fdac7f01ebeb1910f187824fc2562

對稱加密
1、對稱加密體製要求加密與解密使用同一個共享密鑰,解密是加密的逆運算,對於共享密鑰,要求通訊雙方在通訊前協商共享密鑰並妥善保存
2、對稱加密體製分為兩種:一種是對明文的單個位(或單個字節)進行加密,稱為流密碼;另一種是明文劃分為不同的組(或塊),分別對組加密,稱為分組加密
3、常用的為分組加密,分組加密的安全性與分組長度有關,但是一般默認的長度為56位
4、對稱加密有DES,DESede,AES,Blowfish,RC2,RC4,IDEA。相關概念可以百度百科

分組密碼工作模式
1、電子密碼本模式ECB:每次加密均產生獨立的密文分組,每組加密的結果不會對其他組產生影響,無初始化向量
2、密文連接模式CBC:目前應用最廣泛的工作模式,組明文加密前需先與前麵的組密文進行異或運算(XOR)在加密
3、密文反饋模式CFB:類似於自同步流密碼,分組加密後,按8位分組將密文和明文進行位移異或得到輸出並同時反饋回位移寄存器
4、輸出反饋模式OFB:和CFB類似,不過OFB用的是前一個n位密文輸出分組反饋回位移寄存器
5、計數器模式CTR:將計數器從初始值開始計數,所得到的值發送給分組密碼,隨著計數器的增加,分組密碼算法輸出連續的分組來構成一個位串,該串用來與明文分組進行異或運算。在AES中,經常使用的是CBC和CTR,CTR用的比CBC更多些

填充模式
對於明文進行分組,最後一個分組長度不滿足默認長度,稱為短分組。對於短分組如何處理,需要使用到填充模式。

Java對對稱加密算法的支持
DES
screenshot
DESede
screenshot
AES
screenshot
IDEA
screenshot
PBE
screenshot
示例代碼

package com.rcl.platform.demo;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public abstract class DESCoder {

    public static void main(String[] args) throws Exception {
        String inputStr = "我是加密內容";
        byte[] inputData = inputStr.getBytes();
        byte[] key = "key123321".getBytes();

        inputData = encrypt(inputData, key);
        byte[] outputData = decrypt(inputData, key);
        System.out.println("解密後:\t" + new String(outputData));

        byte [] iv = "11111111".getBytes();
        inputData = encryptCBC(inputStr.getBytes(), key, iv);
        outputData = decryptCBC(inputData, key, iv);
        System.out.println("解密後   CBC模式:\t" + new String(outputData));


        byte[] data = encrypt(inputStr.getBytes(), "snowolf1", "11111111".getBytes());//SALT必須為8字節
        byte[] output = decrypt(data, "snowolf1", "11111111".getBytes());
        System.out.println("PBE解密後:\t" + new String(output));
    }

    private static Key toKey(byte[] key) throws Exception {
        // 實例化DES密鑰材料
        DESKeySpec dks = new DESKeySpec(key);
        // 實例化秘密密鑰工廠
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 生成秘密密鑰
        SecretKey secretKey = keyFactory.generateSecret(dks);
        return secretKey;
    }

    /**
     * 轉換密鑰
     * 
     * @param key
     *            二進製密鑰
     * @return Key 密鑰
     * @throws Exception
     */
    private static Key toKeyDESede(byte[] key) throws Exception {

        // 實例化DES密鑰材料
        DESedeKeySpec dks = new DESedeKeySpec(key);

        // 實例化秘密密鑰工廠
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");

        // 生成秘密密鑰
        SecretKey secretKey = keyFactory.generateSecret(dks);

        return secretKey;
    }

    /**
     * 轉換密鑰
     * 
     * @param key
     *            二進製密鑰
     * @return Key 密鑰
     * @throws Exception
     */
    private static Key toKeyAESOrIDEA(byte[] key) throws Exception {
        // 實例化AES密鑰材料
        SecretKey secretKey = new SecretKeySpec(key, "AES");
//      SecretKey secretKey = new SecretKeySpec(key, "IDEA");

        return secretKey;
    }

    /**
     * 轉換密鑰
     * 
     * @param password
     *            密碼
     * @return Key 密鑰
     * @throws Exception
     */
    private static Key toKeyPBE(String password) throws Exception {

        // 密鑰材料轉換
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());

        // 實例化
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndTripleDES");

        // 生成密鑰
        SecretKey secretKey = keyFactory.generateSecret(keySpec);

        return secretKey;
    }

    /**
     * 解密
     * 
     * @param data
     *            待解密數據
     * @param key
     *            密鑰
     * @param ivParameterSpec
     *            加密向量
     * @return byte[] 解密數據
     * @throws Exception
     */
    public static byte[] decryptCBC(byte[] data, byte[] key, byte [] ivParameterSpec) throws Exception {
        // 還原密鑰
        Key k = toKey(key);
        // 實例化
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        //初始化加密向量,CBC模式必須參數,參數最少8位
        IvParameterSpec param = new IvParameterSpec(ivParameterSpec);//CBC
        // 初始化,設置為解密模式
        cipher.init(Cipher.DECRYPT_MODE, k, param);
        // 執行操作
        return cipher.doFinal(data);
    }

    /**
     * 加密
     * 
     * @param data
     *            待加密數據
     * @param key
     *            密鑰
     * @param ivParameterSpec
     *            加密向量
     * @return byte[] 加密數據
     * @throws Exception
     */
    public static byte[] encryptCBC(byte[] data, byte[] key, byte [] ivParameterSpec) throws Exception {
        // 還原密鑰
        Key k = toKey(key);
        // 實例化
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        IvParameterSpec param = new IvParameterSpec(ivParameterSpec);//CBC
        // 初始化,設置為加密模式
        cipher.init(Cipher.ENCRYPT_MODE, k, param);
        // 執行操作
        return cipher.doFinal(data);
    }

    /**
     * 解密
     * 
     * @param data
     *            待解密數據
     * @param key
     *            密鑰
     * @return byte[] 解密數據
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
        // 還原密鑰
        Key k = toKey(key);
        // 實例化
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5PADDING");
        // 初始化,設置為解密模式
        cipher.init(Cipher.DECRYPT_MODE, k);
        // 執行操作
        return cipher.doFinal(data);
    }

    /**
     * 加密
     * 
     * @param data
     *            待加密數據
     * @param key
     *            密鑰
     * @return byte[] 加密數據
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
        // 還原密鑰
        Key k = toKey(key);
        // 實例化
        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5PADDING");
        // 初始化,設置為加密模式
        cipher.init(Cipher.ENCRYPT_MODE, k);
        // 執行操作
        return cipher.doFinal(data);
    }


    /**
     * 加密
     * 
     * @param data
     *            數據
     * @param password
     *            密碼
     * @param salt
     *            鹽
     * @return byte[] 加密數據
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String password, byte[] salt)
            throws Exception {

        // 轉換密鑰
        Key key = toKeyPBE(password);

        // 實例化PBE參數材料
        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);

        // 實例化
        Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");

        // 初始化
        cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

        // 執行操作
        return cipher.doFinal(data);

    }

    /**
     * 解密
     * 
     * @param data
     *            數據
     * @param password
     *            密碼
     * @param salt
     *            鹽
     * @return byte[] 解密數據
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String password, byte[] salt)
            throws Exception {

        // 轉換密鑰
        Key key = toKeyPBE(password);

        // 實例化PBE參數材料
        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);

        // 實例化
        Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");

        // 初始化
        cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

        // 執行操作
        return cipher.doFinal(data);

    }
}

執行結果

解密後:  我是加密內容
解密後   CBC模式:  我是加密內容
PBE解密後:   我是加密內容

最後更新:2017-10-30 10:03:48

  上一篇:go  阿裏雲雙11訪談之數據智能
  下一篇:go  AI翻譯離無障礙交流有多遠