天天看點

開箱即用系列-工具包-非對稱加密算法-RSA

加密算法種類:

  1. 對稱加密

    對稱加密,意味着加密和解密使用同一個秘鑰,安全級别相對于非對稱加密要低.

  2. 非對稱加密

    非對稱加密,意味着加密和解密使用不同的秘鑰,安全級别相對于對稱加密要高.

  3. hash算法

    hash算法是一種單向算法,不可還原成加密之前的元字元.

    常用的加密算法

    常見的對稱加密算法

    DES、3DES、DESX、Blowfish、IDEA、RC4、RC5、RC6和AES

    常見的非對稱加密算法

    RSA、ECC、Diffie-Hellman、El Gamal、DSA

    常見的Hash算法

    MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1

    非對稱加密算法-RSA實作

依賴的POM:
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
           
實作代碼:
import com.bruce.tool.common.exception.ExceptionUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RSA {

    private static final String KEY_ALGORITHM = "RSA";
    private static final String RSA_SIGNATURE_ALGORITHM = "SHA1withRSA";

    /**
     * 初始化密鑰
     */
    public static KeyPair init() {
        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGen.initialize(1024);
            return keyPairGen.generateKeyPair();
        } catch (Exception e) {
            ExceptionUtils.printStackTrace(e);
        }
        return null;
    }

    /**
     * 取得公鑰
     */
    public static String publicKey(KeyPair keyPair) {
        if(Objects.isNull(keyPair) ){ return null; }
        return Base64.encode(keyPair.getPublic().getEncoded());
    }

    /**
     * 取得私鑰
     */
    public static String privateKey(KeyPair keyPair) {
        if(Objects.isNull(keyPair)){ return null; }
        return Base64.encode(keyPair.getPrivate().getEncoded());
    }

    /**
     * 用公鑰加密
     * @param data 中繼資料位元組碼
     * @param base64PublicKey base64編碼過的公鑰(publicKey)
     * @return 加密結果
     */
    public static byte[] encrypt(byte[] data, String base64PublicKey) {
        try {
            // 對公鑰解密
            byte[] keyBytes = Base64.decode(base64PublicKey);
            // 取得公鑰
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicKey = keyFactory.generatePublic(x509KeySpec);
            // 對資料加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            return cipher.doFinal(data);
        } catch (Exception e) {
            ExceptionUtils.printStackTrace(e);
        }
        return new byte[0];
    }

    /**
     * 用私鑰解密
     * @param data 中繼資料位元組碼
     * @param base64PrivateKey base64編碼過的私鑰(privateKey)
     * @return 解碼結果
     */
    public static byte[] decrypt(byte[] data, String base64PrivateKey) {
        try {
            // 對密鑰解密
            byte[] keyBytes = Base64.decode(base64PrivateKey);

            // 取得私鑰
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 對資料解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            return cipher.doFinal(data);
        } catch (Exception e) {
            ExceptionUtils.printStackTrace(e);
        }
        return new byte[0];
    }

    /**
     * 簽名-私鑰簽名
     * @param data 中繼資料位元組碼
     * @param base64PrivateKey base64編碼過的私鑰
     * @return 簽名結果
     */
    public static byte[] sign(byte[] data, String base64PrivateKey){
        try {
            // Base64 --> Key
            byte[] bytes = Base64.decode(base64PrivateKey);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            // Sign
            Signature signature = Signature.getInstance(RSA_SIGNATURE_ALGORITHM);
            signature.initSign(privateKey);
            signature.update(data);
            return signature.sign();
        } catch (Exception e) {
            ExceptionUtils.printStackTrace(e);
        }
        return new byte[0];
    }

    /**
     * 驗簽-公鑰驗簽
     *
     * @param data 需要驗簽的字元串
     * @param base64PublicKey base64編碼之後的公鑰
     * @param sign 需要驗證的簽名
     * @return
     */
    public static boolean verify(byte[] data, String base64PublicKey, String sign) {
        try {
            // Base64 --> Key
            byte[] bytes = Base64.decode(base64PublicKey);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            // verify
            Signature signature = Signature.getInstance(RSA_SIGNATURE_ALGORITHM);
            signature.initVerify(publicKey);
            signature.update(data);
            return signature.verify(Base64.decode(sign));
        } catch (Exception e) {
            ExceptionUtils.printStackTrace(e);
        }
        return false;
    }

}
           
測試類:

import com.bruce.tool.common.util.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.security.KeyPair;

@Slf4j
public class RSATest {

    /**生成簽名**/
    @Test
    public void createKeys() {
        KeyPair keyPair = RSA.init();
        LogUtils.info(log,RSA.publicKey(keyPair));
        LogUtils.info(log,RSA.privateKey(keyPair));
    }

    /**簽名和驗簽**/
    @Test
    public void signAndVerify() {
    	KeyPair keyPair = RSA.init();
        String publicKey = RSA.publicKey(keyPair));
        String privateKey = RSA.privateKey(keyPair));
        String payload = "a=1&b=2&c=3";
        byte[] sign = RSA.sign(payload.getBytes(),privateKey);
        LogUtils.info(log,Base64.encode(sign));
        boolean verify = RSA.verify(payload.getBytes(),publicKey,Base64.encode(sign));
        LogUtils.info(log,verify);
    }

    /**加密解密**/
    @Test
    public void encryptAndDecrypt() {
        KeyPair keyPair = RSA.init();
        String publicKey = RSA.publicKey(keyPair));
        String privateKey = RSA.privateKey(keyPair));
        String payload = "123456";
        byte[] encrypts = RSA.encrypt(payload.getBytes(),publicKey);
        LogUtils.info(log,Base64.encode(encrypts));
        byte[] decrypts = RSA.decrypt(Base64.decode(Base64.encode(encrypts)),privateKey);
        LogUtils.info(log,new String(decrypts));
    }
}

           

補充說明

  1. 在做計算算法概念确定的時候,最初給加密算法想當然的給列了如下的種類:
    1.不可逆加密(不可解密)
    	不可逆,意味着加密之後,不能被解密.
    2.可逆加密(可解密)
    	A.對稱加密
       		對稱加密,意味着加密和解密使用同一個秘鑰,安全級别相對于非對稱加密要低.
    	B.非對稱加密
       		非對稱加密,意味着加密和解密使用不同的秘鑰,安全級别相對于對稱加密要高.
               
    在想說明一下MD5的時候,覺着不太精确,怕誤導大家,于是,到CSDN首頁查了一下,發現一篇文章MD5到底是不是加密算法,于是修改了關于算法的種類說明.
  2. 關于加密算法,還有許多知識點,在此并沒有細說,因為這片文章的目的是"開箱即用".
  3. 文章裡邊使用到lombok,使用ide的童鞋,請安裝對應的lombok插件.
  4. 文章裡邊使用到ExceptionUtils以及LogUtils是我自己封裝的工具類,大家用的時候,可以替換成自己的.

參考文獻

1.百度百科-算法種類說明

2.百度百科-RSA算法說明

3.部落格園-常用加密算法概述

繼續閱讀