【JAVA基礎】Java中常用加密算法的使用方法

加密算法小科普

常見加密算法分類

  • 對稱加密 指加密和解密使用相同密鑰的加密算法
    • DES、3DES、DESX、Blowfish、IDEA、RC4、RC5、RC6和AES
  • 非對稱加密 指加密和解密使用不同密鑰的加密算法,也稱爲公私鑰加密
    • RSA、ECC(移動設備用)、Diffie-Hellman、El Gamal、DSA(數字簽名用)
  • Hash算法 一種單向算法,通過Hash算法對目標信息生成一段特定長度的唯一的Hash值,但不能通過這個Hash值重新獲得目標信息
    • MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1

簡單的 Java 加密算法有

  • BASE64 嚴格地說,屬於編碼格式,而非加密算法
  • MD5(Message Digest algorithm 5,信息摘要算法)
  • SHA(Secure Hash Algorithm,安全散列算法)
  • HMAC(Hash Message Authentication Code,散列消息鑑別碼)

talk is cheap, show me the code.

BASE64Encoder / BASE64Decoder

import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @description:
 * @author: tanpeng
 * @date: 2020-03-24 14:34
 * @version: v1.0.0
 */
@Slf4j
public class TestBASE64 {

    private static String CHARSET_UTF8 = "UTF-8";

    public static void main(String[] args) throws Exception {
        String plaintext = "123456";
        byte[] plaintextByteArray = plaintext.getBytes(CHARSET_UTF8);

        System.out.println("=================================== BASE64Encoder / BASE64Decoder ===================================");

        String encode1 = new BASE64Encoder().encode(plaintextByteArray);
        byte[] decode1 = new BASE64Decoder().decodeBuffer(encode1);
        log.info("Base64 encode1 {}", encode1);
        log.info("Base64 decode1 {}", new String(decode1, CHARSET_UTF8));

        System.out.println("=================================== Base64.getEncoder() / Base64.getDecoder() ===================================");

        byte[] encode2 = Base64.getEncoder().encode(plaintextByteArray);
        byte[] decode2 = Base64.getDecoder().decode(encode2);
        log.info("Base64 encode2 {}", new String(encode2, CHARSET_UTF8));
        log.info("Base64 decode2 {}", new String(decode2, CHARSET_UTF8));
    }
}

輸出

=================================== BASE64 ===================================
14:43:27.621 [main] INFO com.itplh.encrypt.TestBASE64 - Base64 encode MTIzNDU2
14:43:27.639 [main] INFO com.itplh.encrypt.TestBASE64 - Base64 decode 123456

MessageDigest

import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import java.security.MessageDigest;

/**
 * @description:
 * @author: tanpeng
 * @date: 2020-03-24 14:36
 * @version: v1.0.0
 */
@Slf4j
public class TestMessageDigest {
    private static String CHARSET_UTF8 = "UTF-8";
    private static int RADIX_16 = 1<<4;
    private static int RADIX_32 = 1<<5;

    public static void main(String[] args) throws Exception {
        String plaintext = "123456";
        byte[] plaintextByteArray = plaintext.getBytes(CHARSET_UTF8);
        byte[] slatByteArray = "slat".getBytes(CHARSET_UTF8);

        System.out.println("=================================== MD5 ===================================");

        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(plaintextByteArray);
        byte[] md5Encode = md5.digest(); // 調用digest方法後會重置狀態爲 INITIAL
        String md5MessageDigest = new BigInteger(md5Encode).toString(RADIX_16);
        log.info("MD5 encode {}", md5MessageDigest);

        md5.update(plaintextByteArray);
        md5.update(slatByteArray);
        log.info("MD5 slat encode {}", new BigInteger(md5.digest()).toString(RADIX_16));

        md5.update(plaintextByteArray);
        md5.update(slatByteArray);
        log.info("MD5 slat encode {}", new BigInteger(md5.digest()).toString(RADIX_16));

        System.out.println("=================================== SHA-1 ===================================");

        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
        sha1.update(plaintextByteArray);
        log.info("SHA-1 encode {}", new BigInteger(sha1.digest()).toString(RADIX_32));

        sha1.update(plaintextByteArray);
        sha1.update(slatByteArray);
        log.info("SHA-1 slat encode {}", new BigInteger(sha1.digest()).toString(RADIX_32));

        sha1.update(plaintextByteArray);
        sha1.update(slatByteArray);
        log.info("SHA-1 slat encode {}", new BigInteger(sha1.digest()).toString(RADIX_32));

        System.out.println("=================================== SHA-256 ===================================");

        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        sha256.update(plaintextByteArray);
        log.info("SHA-256 encode {}", new BigInteger(sha256.digest()).toString(RADIX_32));

        sha256.update(plaintextByteArray);
        sha256.update(slatByteArray);
        log.info("SHA-256 slat encode {}", new BigInteger(sha256.digest()).toString(RADIX_32));

        sha256.update(plaintextByteArray);
        sha256.update(slatByteArray);
        log.info("SHA-256 slat encode {}", new BigInteger(sha256.digest()).toString(RADIX_32));
        
    }
}

輸出

=================================== MD5 ===================================
14:44:38.581 [main] INFO com.itplh.encrypt.TestMessageDigest - MD5 encode -1ef523c6b645a65441a91fa80df077c2
14:44:38.597 [main] INFO com.itplh.encrypt.TestMessageDigest - MD5 slat encode 7d991ee60623856907a6baffc15164da
14:44:38.597 [main] INFO com.itplh.encrypt.TestMessageDigest - MD5 slat encode 7d991ee60623856907a6baffc15164da
=================================== SHA-1 ===================================
14:44:38.598 [main] INFO com.itplh.encrypt.TestMessageDigest - SHA-1 encode fh58q2ea6thauof5ikg98fe2ciafh50r
14:44:38.598 [main] INFO com.itplh.encrypt.TestMessageDigest - SHA-1 slat encode bvs54f4a210bmpm9ecb6dg9s508lgl7q
14:44:38.598 [main] INFO com.itplh.encrypt.TestMessageDigest - SHA-1 slat encode bvs54f4a210bmpm9ecb6dg9s508lgl7q
=================================== SHA-256 ===================================
14:44:38.599 [main] INFO com.itplh.encrypt.TestMessageDigest - SHA-256 encode -sj9c4892d9c7lisb7bdfscnic7jo2haauag1gqurvfjdn2i74re
14:44:38.599 [main] INFO com.itplh.encrypt.TestMessageDigest - SHA-256 slat encode r498dqrlfo7649m7ausnpnvsf7ueb9kp89oq2301ne6lkeashg8
14:44:38.600 [main] INFO com.itplh.encrypt.TestMessageDigest - SHA-256 slat encode r498dqrlfo7649m7ausnpnvsf7ueb9kp89oq2301ne6lkeashg8

KeyGenerator

支持的算法有

  • AES
  • ARCFOUR
  • Blowfish
  • DES
  • DESede
  • HmacMD5
  • HmacSHA1 HmacSHA256 HmacSHA384 HmacSHA512
  • RC2
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * @description:
 * @author: tanpeng
 * @date: 2020-03-24 14:51
 * @version: v1.0.0
 */
@Slf4j
public class TestKeyGenerator {

    private static String CHARSET_UTF8 = "UTF-8";

    public static void main(String[] args) throws Exception {

        String plaintext = "1234.56.78";

        System.out.println("=================================== HmacMD5 ===================================");
        encodeMac("HmacMD5", plaintext);

        System.out.println("=================================== HmacSHA1 ===================================");
        encodeMac("HmacSHA1", plaintext);

        System.out.println("=================================== HmacSHA256 ===================================");
        encodeMac("HmacSHA256", plaintext);

        System.out.println("=================================== HmacSHA384 ===================================");
        encodeMac("HmacSHA384", plaintext);

        System.out.println("=================================== HmacSHA512 ===================================");
        encodeMac("HmacSHA512", plaintext);

        System.out.println("=================================== AES ===================================");
        decodeAES("12345678ABCDEFGH", encodeAES("12345678ABCDEFGH", plaintext));

    }

    private static String encodeMac(String algorithm, String plaintext) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
        // 產生摘要算法的密鑰key
        byte[] key = KeyGenerator.getInstance(algorithm)
                .generateKey()
                .getEncoded();
        key = Base64.getEncoder().encode(key); // 使用base64對祕鑰進行編碼
        log.info("{} key {}", algorithm, new String(key, CHARSET_UTF8));
        // 摘要算法
        key = Base64.getDecoder().decode(key);// 使用base64對祕鑰進行解碼
        SecretKey key2 = new SecretKeySpec(key, algorithm); // 還原密鑰
        Mac mac = Mac.getInstance(key2.getAlgorithm()); // 實例化Mac
        mac.init(key2); // 初始化mac
        mac.update(plaintext.getBytes(CHARSET_UTF8)); // 計算消息摘要
        byte[] digest = mac.doFinal(); // 獲取消息摘要
        String result = new HexBinaryAdapter().marshal(digest); // //轉爲十六進制的字符串
        log.info("{} encode {}", algorithm, result);
        return result;
    }

    private static String encodeAES(String encodeRules, String plaintext) throws Exception {
        String AES = "AES";
        // 產生摘要算法的密鑰key
        byte[] raw = generateAESKey(encodeRules);
        // AES摘要算法
        //5.根據字節數組生成AES密鑰
        SecretKey key = new SecretKeySpec(raw, AES);
        //6.根據指定算法AES自成密碼器
        Cipher cipher = Cipher.getInstance(AES);
        //7.初始化密碼器,第一個參數爲加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二個參數爲使用的KEY
        cipher.init(Cipher.ENCRYPT_MODE, key);
        //8.獲取加密內容的字節數組(這裏要設置爲utf-8)不然內容中如果有中文和英文混合中文就會解密爲亂碼
        byte[] byte_encode = plaintext.getBytes(CHARSET_UTF8);
        //9.根據密碼器的初始化方式--加密:將數據加密
        byte[] byte_AES = cipher.doFinal(byte_encode);
        //10.將加密後的數據轉換爲字符串
        String ciphertext = new BASE64Encoder().encode(byte_AES);
        //11.將字符串返回
        log.info("AES encode {}", ciphertext);
        return ciphertext;
    }

    private static String decodeAES(String encodeRules, String ciphertext) throws Exception {
        String AES = "AES";
        // 產生摘要算法的密鑰key
        byte[] raw = generateAESKey(encodeRules);
        // 解密AES摘要
        //5.根據字節數組生成AES密鑰
        SecretKey key = new SecretKeySpec(raw, AES);
        //6.根據指定算法AES自成密碼器
        Cipher cipher = Cipher.getInstance(AES);
        //7.初始化密碼器,第一個參數爲加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二個參數爲使用的KEY
        cipher.init(Cipher.DECRYPT_MODE, key);
        //8.BASE64解碼密文
        byte[] byteCiphertext = new BASE64Decoder().decodeBuffer(ciphertext);
        //9.解密
        byte[] byteDecode = cipher.doFinal(byteCiphertext);
        //10.將字節數組轉爲明文字符串
        String plaintext = new String(byteDecode, CHARSET_UTF8);
        log.info("AES decode {}", plaintext);
        return plaintext;
    }

    // javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    // 實現generateAESKey方法時不使用SecureRandom生成SecretKey
    //
    // java.security.NoSuchAlgorithmException: AES SecretKeyFactory not available
    // 使用 SecretKeySpec 直接生成一個密鑰
    //
    // Exception java.security.InvalidKeyException: Invalid AES key length: 3 bytes?
    // AES allows 128, 192 or 256 bit key length. That is 16, 24 or 32 byte. Try taking just the first 16 bytes of your encodeRules as the keyAsBytes.
    private static byte[] generateAESKey(String encodeRules) throws Exception {
        String AES = "AES";

//        //1.構造密鑰生成器,指定爲AES算法,不區分大小寫
//        KeyGenerator keygen = KeyGenerator.getInstance(AES);
//        //2.根據ecnodeRules規則初始化密鑰生成器
//        //生成一個128位的隨機源,根據傳入的字節數組
//        keygen.init(128, new SecureRandom(encodeRules.getBytes()));
//        //3.產生原始對稱密鑰
//        SecretKey originalKey = keygen.generateKey();
//        //4.獲得原始對稱密鑰的字節數組
//        byte[] keyEncoded = originalKey.getEncoded();
//        return keyEncoded;

//        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(AES);
//        SecretKey originalKey = secretKeyFactory.generateSecret(new SecretKeySpec(encodeRules.getBytes(CHARSET_UTF8), AES));
//        return originalKey.getEncoded();

        SecretKey originalKey = new SecretKeySpec(encodeRules.getBytes(CHARSET_UTF8), AES);
        return originalKey.getEncoded();
    }
}

輸出

=================================== HmacMD5 ===================================
17:37:51.467 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacMD5 key 5Q+yQ+icsqC2qS5CR3TULslTE4b3bsMS2q/xpjnbx4DAz76OQ/4IgpjPP2w2UNxCDx46uWMy+wbJXGFmYzar+w==
17:37:51.484 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacMD5 encode 3EC9DD765FDE7CCDF51F33512EBEC06B
=================================== HmacSHA1 ===================================
17:37:51.484 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA1 key XfSINYU99W3E7dLZbvycTPA5A8TAlgFMSsI3AV/pMC7QPq8M51mThv1Yp9cxPv/Uxlq2j9ViW8h1bWBjPQcbWg==
17:37:51.485 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA1 encode 323E5241DAE5484FE25FFA4BCF27C4E2B4FB6EBD
=================================== HmacSHA256 ===================================
17:37:51.486 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA256 key 7/ctQyvQ8ddwmHe+v7DyQSU+lejGmWXlwCx01kFOeWI=
17:37:51.487 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA256 encode FAA343D654681A07E2F4828AF263BC4C33444581968589C26803C91066C8F15A
=================================== HmacSHA384 ===================================
17:37:51.487 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA384 key 11SpITSJisQQqV4IVUnfUhKzWu4ge2S1XDtL+remqexnxOmXE0ImD75pYINIzImy
17:37:51.488 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA384 encode 143EB582223E887BE0A7F11C0B71846DC5A17FD2B9B216D24138C30E6C85F4B5D510BB15E4A36D1BC37F73659844A47E
=================================== HmacSHA512 ===================================
17:37:51.489 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA512 key PfMIrHMdrjJ7Laxytp6LZXVWA7bHaij7Jb1dBpm3bCAWTT1neS76YgHMug536cf1bytqSz75Go4FsdpHTEYtJA==
17:37:51.490 [main] INFO com.itplh.encrypt.TestKeyGenerator - HmacSHA512 encode DE1D7C852C5A96958DF2C420E9CE9623B1759EDDE3CDE6190FA111D9CC1891141E2AA6BC225D4C82B5DA333AF65E6CD21A4C6134AF83513261ACF96CB153A3AE
=================================== AES ===================================
17:37:51.521 [main] INFO com.itplh.encrypt.TestKeyGenerator - AES encode IUEleZreAU0tk6ewY9aGUA==
17:37:51.522 [main] INFO com.itplh.encrypt.TestKeyGenerator - AES decode 1234.56.78

參考

Java中4大基本加密算法解析

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