RSA非對稱加密算法

一、對稱加密與非對稱加密

  • 對稱加密:加密和解密使用的是同一個密鑰,加解密雙方必須使用同一個密鑰才能進行正常的溝通。

  • 非對稱加密:需要兩個密鑰來進行加密和解密,公開密鑰(public key,簡稱公鑰)和私有密鑰(private key,簡稱私鑰) ,公鑰加密的信息只有私鑰才能解開,私鑰加密的信息只有公鑰才能解開。

需要注意的一點,這個公鑰和私鑰必須是一對的,如果用公鑰對數(shù)據(jù)進行加密,那么只有使用對應的私鑰才能解密,所以只要私鑰不泄露,那么我們的數(shù)據(jù)就是安全的。

常用的加密算法:

  • 對稱加密:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES。

  • 非對稱加密:RSA、ECC(橢圓曲線加密算法)、Diffie-Hellman、El Gamal、DSA(數(shù)字簽名用)

  • Hash 算法:MD2、MD4、MD5、HAVAL、SHA-1、SHA256、SHA512、RipeMD、WHIRLPOOL、SHA3、HMAC

二、非對稱加密工作過程

甲乙雙方使用非對稱加密算法的方式進行數(shù)據(jù)傳輸

  • 乙方生成一對密鑰(公鑰與私鑰),并將公鑰向甲方公開
  • 甲方獲取到公鑰后,將需要傳輸?shù)臄?shù)據(jù)用公鑰進行加密發(fā)送給乙方
  • 乙方獲取到甲方加密數(shù)據(jù)后,用私鑰進行解密
  • 在數(shù)據(jù)傳輸過程中,即使數(shù)據(jù)被攻擊者截取并獲取了公鑰,攻擊者也無法破解密文,因為只有乙方的私鑰才能解密

三、非對稱加密中,究竟是公鑰加密還是私鑰加密?

  • 對于加密:公鑰加密,私鑰加密。畢竟公鑰可以公開,但是私鑰只有你自已知道,你也同樣希望只有你自已才能解密
  • 對于簽名:私鑰加密,公鑰解密。好比你的簽名只有你自已簽的才是真的,別人簽的都是假的。

四、RSA非對稱加密代碼示例

RSA 算法基于一個十分簡單的數(shù)論事實:將兩個大素數(shù)相乘十分容易,但是想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。

  • 1、添加jar包
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.56</version>
</dependency>

  • 2、RSAUtil.java
package com.kimeng.weipan.utils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * @author: 會跳舞的機器人
 * @date: 2017/9/18 15:00
 * @description: RSA工具類
 */
public class RSAUtil {
    /**
     * 定義加密方式
     */
    private final static String KEY_RSA = "RSA";
    /**
     * 定義簽名算法
     */
    private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
    /**
     * 定義公鑰算法
     */
    private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
    /**
     * 定義私鑰算法
     */
    private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 初始化密鑰
     */
    public static Map<String, Object> init() {
        Map<String, Object> map = null;
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
            generator.initialize(2048);
            KeyPair keyPair = generator.generateKeyPair();
            // 公鑰
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            // 私鑰
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 將密鑰封裝為map
            map = new HashMap<>();
            map.put(KEY_RSA_PUBLICKEY, publicKey);
            map.put(KEY_RSA_PRIVATEKEY, privateKey);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 公鑰加密
     *
     * @param data 待加密數(shù)據(jù)
     * @param key  公鑰
     */
    public static byte[] encryptByPublicKey(String data, String key) {
        byte[] result = null;
        try {
            byte[] bytes = decryptBase64(key);
            // 取得公鑰
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PublicKey publicKey = factory.generatePublic(keySpec);
            // 對數(shù)據(jù)加密
            Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");

            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encode = cipher.doFinal(data.getBytes());
            // 再進行Base64加密
            result = Base64.encode(encode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 私鑰解密
     *
     * @param data 加密數(shù)據(jù)
     * @param key  私鑰
     */
    public static String decryptByPrivateKey(byte[] data, String key) {
        String result = null;
        try {
            // 對私鑰解密
            byte[] bytes = decryptBase64(key);
            // 取得私鑰
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            PrivateKey privateKey = factory.generatePrivate(keySpec);
            // 對數(shù)據(jù)解密
            Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // 先Base64解密
            byte[] decoded = Base64.decode(data);
            result = new String(cipher.doFinal(decoded));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 獲取公鑰
     */
    public static String getPublicKey(Map<String, Object> map) {
        String str = "";
        try {
            Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 獲取私鑰
     */
    public static String getPrivateKey(Map<String, Object> map) {
        String str = "";
        try {
            Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 用私鑰對信息生成數(shù)字簽名
     *
     * @param data       加密數(shù)據(jù)
     * @param privateKey 私鑰
     */
    public static String sign(byte[] data, String privateKey) {
        String str = "";
        try {
            // 解密由base64編碼的私鑰
            byte[] bytes = decryptBase64(privateKey);
            // 構造PKCS8EncodedKeySpec對象
            PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
            // 指定的加密算法
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            // 取私鑰對象
            PrivateKey key = factory.generatePrivate(pkcs);
            // 用私鑰對信息生成數(shù)字簽名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initSign(key);
            signature.update(data);
            str = encryptBase64(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 校驗數(shù)字簽名
     *
     * @param data      加密數(shù)據(jù)
     * @param publicKey 公鑰
     * @param sign      數(shù)字簽名
     * @return 校驗成功返回true,失敗返回false
     */
    public static boolean verify(byte[] data, String publicKey, String sign) {
        boolean flag = false;
        try {
            // 解密由base64編碼的公鑰
            byte[] bytes = decryptBase64(publicKey);
            // 構造X509EncodedKeySpec對象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
            // 指定的加密算法
            KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
            // 取公鑰對象
            PublicKey key = factory.generatePublic(keySpec);
            // 用公鑰驗證數(shù)字簽名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initVerify(key);
            signature.update(data);
            flag = signature.verify(decryptBase64(sign));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * BASE64 解密
     *
     * @param key 需要解密的字符串
     * @return 字節(jié)數(shù)組
     */
    public static byte[] decryptBase64(String key) throws Exception {
        return Base64.decode(key);
    }

    /**
     * BASE64 加密
     *
     * @param key 需要加密的字節(jié)數(shù)組
     * @return 字符串
     */
    public static String encryptBase64(byte[] key) throws Exception {
        return new String(Base64.encode(key));
    }


    public static void main(String[] args) throws Exception {
        String publicKey = "";
        String privateKey = "";
        Map<String, Object> keyMap = RSAUtil.init();
        publicKey = RSAUtil.getPublicKey(keyMap);
        privateKey = RSAUtil.getPrivateKey(keyMap);
        System.out.println("公鑰:\n\r" + publicKey);
        System.out.println("私鑰:\n\r" + privateKey);

        System.out.println("公鑰加密======私鑰解密");
        String str = "會跳舞的機器人";
        byte[] enStr = RSAUtil.encryptByPublicKey(str, publicKey);
        String decStr = RSAUtil.decryptByPrivateKey(enStr, privateKey);
        System.out.println("加密前:" + str + "\n\r解密后:" + decStr);

        System.out.println("\n\r");
        System.out.println("私鑰簽名======公鑰驗證");
        String sign = RSAUtil.sign(str.getBytes(), privateKey);
        System.out.println("簽名:\n\r" + sign);
        boolean flag = RSAUtil.verify(str.getBytes(), publicKey, sign);
        System.out.println("驗簽結果:\n\r" + flag);
    }
}

輸出

公鑰:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkmIH1vvK8A+EDak84WOuOrN2IgzlarfDu6vp4i/vv/4Edezr1J5kWGf9WpGx2lfpZPS80bN03nxeA1utRoktJvqu++oXkoU3oDLlm/MciTV2lpSiDf8BiZfZ298FKQsG7CKI1Tj9ii9MlHWCsIDHfEJBsQTYONgDSjM6yecfRu0Xg0ZCNklNNeDki60oFa20hiUdLthSopuCWmxAGQL7uuOwlj07xzBXGEJkh8ixGF9v+CDMQLLU6ezk8ZWnPsOwS7OiJZkndyw13NKx8PMmaHX+cOYL5b6Vi7UQ+yizpGejV36XuX0Zpxb2AZee/IZCRGt/cOg0QKmEcN5KeKG6qQIDAQAB
私鑰:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCSYgfW+8rwD4QNqTzhY646s3YiDOVqt8O7q+niL++//gR17OvUnmRYZ/1akbHaV+lk9LzRs3TefF4DW61GiS0m+q776heShTegMuWb8xyJNXaWlKIN/wGJl9nb3wUpCwbsIojVOP2KL0yUdYKwgMd8QkGxBNg42ANKMzrJ5x9G7ReDRkI2SU014OSLrSgVrbSGJR0u2FKim4JabEAZAvu647CWPTvHMFcYQmSHyLEYX2/4IMxAstTp7OTxlac+w7BLs6IlmSd3LDXc0rHw8yZodf5w5gvlvpWLtRD7KLOkZ6NXfpe5fRmnFvYBl578hkJEa39w6DRAqYRw3kp4obqpAgMBAAECggEAcZ0onJGddylzwu6h1AX8Co+TluYPgf7TKmxKAUZXfNp5N9YFTGcLVxqPJ6aBNgiZm8PgcZopkS1SAqU7Hc4Gf4R+IAQW+5/uBqa6U4ojkdMvEbyW8uoDlXmInADDDpICc3ByZ5vuHTyM4YU7RCcPrb/3IJ+z+pqeIw8UB/Uc73yUkao+KwL1alpKY8YTkHGMvIwgQDzhRSrfw7Nc5ZLZlkulWfgPN6B51peAqi8ZHGlyECtheEaS/Ws5O/Ju3y7V50WIs/rKT9DFpUZ8nueUPyn1+m+arMFPP3fKd2+9lUotQIIFgkyhLCdX6j7fxhDy2mQk7F68RhZPcGehg86SSQKBgQDM4uK6LCJ8BNURaaOospuOw0nmxeRmDxGMtGDIuTiOLccxwYJPQDQadZ76bfQpn7WmWyQrJWeKmDuvPZ+Mi+RHSL1W0mJnY9/0nLkgsu7fFFq5TDDBnEfNgqfyrozHZa6Eg89exjfH7WQTDbBI2/JXiNHA1iRwRsLIe+RJM/QsYwKBgQC25tBsLoDNUdyaXL9tf2kCG6vepUfdOdfSpby1pU4zpdONJXMenZglh3wIAKWoLVlhchRn/us1ClNasDqJX2O6WgXYh1OL88wFY8B04VnpV3o73vSJhxibZnm6KOzdonHiDAaP5+p/2jVRKewOoEmMFCITzDgSLqcKhA35wxosgwKBgAPUZdqHAqoAyR7HM7juhbvYaKQ4pLlHpNNVd82osKbvsh56+H2UvKSV+D/EGGFCy/ltELMBwvqzN8Jhy36sCrtOX8OksRQvqLsAxvEWhyKCVePKycqEqk7sF0mQ+66qduWhNRoXaGmDRXCZu+bQvannM8x/9DRpDjEDJ9Q6dWDzAoGBAK5GdCYAkX4SGG+FHGnLU1VM5JE7T6R97yWqAovaPQ99XHxLSMvNQiHQXOCLLU14GIh/WO5WuetKMW5iKQSoPbBdAuD04SijXq1sBP/ZkgCC99eAc+VvMoUwOaCmSjxNAtJuvvnz8z9rvg3eMi0lka7FqErQ9kRs64Fbnq1zt8bdAoGABbMMrAgeDvfkQId/1GsFP/xdgUicnXrLhD/cn6NlAqcU9lAubsRDewIQtfw377OsutK6gzbFdrLnaigRDgwf+y0XACdhldE8vTVOPtBaUIqSjTSjuRlp4ZBN1vx2or6QBG7Om061EuaL625YguAjeHpSxTiAbk5tejBnICXPFhY=
公鑰加密======私鑰解密
加密前:會跳舞的機器人
解密后:會跳舞的機器人


私鑰簽名======公鑰驗證
簽名:
DqSegeOz0lIESAd7J7tlkYHsm/81vITAS9RWEmTtOtz5+NVtcD1RGgau2hMVDhNsIr7F0qP2SJSCu0SlAJxvN0pYYrRo5Cy1aLUCfsv/BEoLi32IcNN8cDClCxLa/uIDzyRd3+q8yMDuAhvX2eojiiu6cT3jwrajK4mtxncIbXvNFJ9/po36q8NYujvOhI0ujEFlDC5o5GwskXsJgk/gKf9raiGS9O7Pm8XejsSyDPITre86tuntWQppqWHIku/uN8Cf2n7AlD2HVBryQrma922iIxE3ykfNGoxF4wwof3AGXG4P12nC0rDB/V/7twFZvKmYBWAejni7bDJaV3+pUg==
驗簽結果:
true

五、RSA非對稱加密的缺點

加解密速度較慢,不太適用于高并發(fā)的業(yè)務場景,一般用它做少量的數(shù)據(jù)加密。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容