RSA非对称加密

一、对称加密与非对称加密

  • 对称加密:加密和解密使用的是同一个密钥,加解密双方必须使用同一个密钥才能进行正常的沟通。
  • 非对称加密:需要两个密钥来进行加密和解密,公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥) ,公钥加密的信息只有私钥才能解开,私钥加密的信息只有公钥才能解开。

需要注意的一点,这个公钥和私钥必须是一对的,如果用公钥对数据进行加密,那么只有使用对应的私钥才能解密,所以只要私钥不泄露,那么我们的数据就是安全的。

常用的加密算法:

  • 对称加密:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES。
  • 非对称加密:RSA、ECC(椭圆曲线加密算法)、Diffie-Hellman、El Gamal、DSA(数字签名用)
  • Hash 算法:MD2、MD4、MD5、HAVAL、SHA-1、SHA256、SHA512、RipeMD、WHIRLPOOL、SHA3、HMAC

二、非对称加密工作过程

甲乙双方使用非对称加密算法的方式进行数据传输

  • 乙方生成一对密钥(公钥与私钥),并将公钥向甲方公开
  • 甲方获取到公钥后,将需要传输的数据用公钥进行加密发送给乙方
  • 乙方获取到甲方加密数据后,用私钥进行解密
  • 在数据传输过程中,即使数据被攻击者截取并获取了公钥,攻击者也无法破解密文,因为只有乙方的私钥才能解密

三、非对称加密中,究竟是公钥加密还是私钥加密?

  • 对于加密:公钥加密,私钥加密。毕竟公钥可以公开,但是私钥只有你自已知道,你也同样希望只有你自已才能解密
  • 对于签名:私钥加密,公钥解密。好比你的签名只有你自已签的才是真的,别人签的都是假的。

四、RSA非对称加密代码示例

RSA 算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

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 待加密数据
     * @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);
            // 对数据加密
            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 加密数据
     * @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);
            // 对数据解密
            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;
    }

    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       加密数据
     * @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);
            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
            signature.initSign(key);
            signature.update(data);
            str = encryptBase64(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 校验数字签名
     *
     * @param data      加密数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @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);
            // 用公钥验证数字签名
            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 字节数组
     */
    public static byte[] decryptBase64(String key) throws Exception {
        return Base64.decode(key);
    }

    /**
     * BASE64 加密
     *
     * @param key 需要加密的字节数组
     * @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非对称加密的缺点

加解密速度较慢,不太适用于高并发的业务场景,一般用它做少量的数据加密。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小工匠技术圈

【Java小工匠聊密码学】--数字签名-DSA

DSA(Digital Signature Algorithm)是Schnorr和ElGamal签名算法的变种,被美国NIST作为数字签名标准(DigitalS...

1052
来自专栏静默虚空的博客

[Java 安全]加密算法

Base64编码 算法简述 定义 Base64内容传送编码是一种以任意8位字节序列组合的描述形式,这种形式不易被人直接识别。 Base64是一种很常见的编码规范...

8026
来自专栏日暮星辰

SSL/TLS加密检测脚本testssl.sh

以前SSL检测常用工具就是ssllabs的:https://www.ssllabs.com/ssltest/ 以及国内的https://myssl.com/.

5132
来自专栏iOS 开发杂谈

HTTPS 之对称加密与非对称加密

加密 encryption 与解密 decryption 使用的是同样的密钥 secret key,对称加密是最快速、最简单的一种加密方式。加密和解密算法是公开...

2984
来自专栏java 成神之路

RSA 非对称加密原理(小白也能看懂哦~)

1.9K9
来自专栏个人随笔

Java MD5加密与RSA加密

8394
来自专栏Android-薛之涛

Android-加解密

不可逆加密算法的特征是加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,只有重新输入明文,并再次经过同样不可...

1543
来自专栏Java学习网

Java 开发中实现DES/3DES/AES 三种对称加密算法方法学习

对称密码算法是当今应用范围最广,使用频率最高的加密算法。它不仅应用于软件行业,在硬件行业同样流行。各种基础设施凡是涉及到安全需求,都会优先考虑对称加密算法。

2415
来自专栏小工匠技术圈

【小工匠聊密码学】--对称加密--DES

  DES对称加密,对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的密钥,信息的发送者和信息的接收者在进行信息的传输与处理时,必须共同持有...

712
来自专栏数据之美

pyDes 实现 Python 版的 DES 对称加密/解密

手头有个 Java 版的 DES 加密/解密程序,最近想着将其 Python 重构下,方便后续脚本解析,捣鼓了两下 pyDes 貌似很方便,不过据网上其他同学测...

8366

扫码关注云+社区

领取腾讯云代金券