RSA加密的使用

RSA 简介
RSA——非对称加密,会产生公钥和私钥,公钥在客户端,私钥在服务端。公钥用于加密,私钥用于解密。

RSA 其实是三位数学家名字的缩写,1977年,三位数学家 Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。

在1977年的RSA论文里,提到分解一个75位十进制数字大约需要104天。人类的技术进步是如此惊人!

当攻方的矛越来越锋利时,守方的盾就必须越来越厚重。所以,1024比特RSA已经不安全,应用系统不应该使用少于2048比特的公钥 值。而当需要高安全性时,选择4096比特RSA。

RSA 常用的加密填充模式
RSA/None/PKCS1Padding
RSA/ECB/PKCS1Padding
Java 默认的 RSA 实现是 RSA/None/PKCS1Padding , 默认实现如下:

Cipher cipher = Cipher.getInstance("RSA");

使用模式方式的 Cipher 生成的密文总是不一致的 ,Bouncy Castle的默认 RSA 实现是 RSA/None/NoPadding 。

为什么 Java 默认的 RSA 实现每次生成的密文都不一致呢,即使每次使用同一个明文、同一个公钥?这是因为 RSA 的 PKCS #1 padding 方案在加密前对明文信息进行了随机数填充。

实际运用注意事项
(1)一般由服务器创建秘钥对,私钥保存在服务器,公钥下发至客户端

(2)公钥是二进制数据,怎么下发给客户端呢?
第一种方式:服务器把二进制数据写入文件,然后把文件传给客户端。由客户端从文件读取二进制数据。
第二种方式:服务器把二进制数据转成 base64 字符串,客户端获取到 base64 字符串后,再转码为二进制数据。

(3)使用相同的公钥加密后的数据,每次都不一样,这是因为 RSA 的填充方案在加密前对明文信息进行了随机数填充。但是不并不影响解密的结果

(4)在创建RSA秘钥对时,长度最好选择 2048的整数倍,长度为1024在今天的互联网已经不安全了。
 

封装RSA加密管理类

package com.phone.common_library.manager;
 
import java.security.InvalidKeyException;
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.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
 
public class RSAManager {
 
 
    /**
     * 使用公钥加密
     *
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) {
        // 得到公钥对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory keyFactory = null;
        // 加密数据
        Cipher cp = null;
        byte[] byteArr = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(keySpec);
            // 加密数据
            cp = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cp.init(Cipher.ENCRYPT_MODE, pubKey);
            byteArr = cp.doFinal(data);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
 
        return byteArr;
    }
 
    /**
     * 使用私钥解密
     *
     * @param encrypted
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) {
        // 得到私钥对象
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory kf = null;
        byte[] byteArr = null;
        try {
            kf = KeyFactory.getInstance("RSA");
            PrivateKey keyPrivate = kf.generatePrivate(keySpec);
            // 解密数据
            Cipher cp = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cp.init(Cipher.DECRYPT_MODE, keyPrivate);
            byteArr = cp.doFinal(encrypted);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return byteArr;
    }
 
    /**
     * 创建非对称加密RSA秘钥对
     *
     * @param keyLength
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair generateRSAKeyPair(int keyLength) {
        KeyPairGenerator kpg = null;
        try {
            kpg = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
 
        kpg.initialize(keyLength);
        return kpg.genKeyPair();
    }
 
    /**
     * 获取公钥,打印为48-12613448136942-12272-122-913111503-126115048-12...等等一长串用-拼接的数字
     */
    public static byte[] getPublicKey(KeyPair keyPair) {
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        return rsaPublicKey.getEncoded();
    }
 
    /**
     * 获取私钥,同上
     */
    public static byte[] getPrivateKey(KeyPair keyPair) {
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        return rsaPrivateKey.getEncoded();
    }
 
}

如何使用?

String message = "Trump is yellow hair";
 
        //创建秘钥对
        KeyPair keyPair = RSAManager.generateRSAKeyPair(2048);
        //获取公钥
        byte[] publicKey = RSAManager.getPublicKey(keyPair);
        //获取私钥
        byte[] privateKey = RSAManager.getPrivateKey(keyPair);
        //公钥base64编码
//            String publicBase64 = Base64.getEncoder().encodeToString(publicKey);
//            String publicBase64 = Base64.encodeToString(publicKey, Base64.DEFAULT);
        BASE64Encoder encoder = new BASE64Encoder();
        String publicBase64 = encoder.encodeBuffer(publicKey).trim();
        LogManager.i(TAG, "publicBase64*****" + publicBase64);
 
        //加密
        byte[] encryptResult = RSAManager.encryptByPublicKey(message.getBytes(), publicKey);
        //解密
        byte[] decryptResult = RSAManager.decryptByPrivateKey(encryptResult, privateKey);
        LogManager.i(TAG, "解密*****" + new String(decryptResult, StandardCharsets.UTF_8));

打印的日志如下

2022-07-21 15:43:45.960 3757-3757/com.phone.rxjava2andretrofit2 I/MineActivity: publicBase64*****MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqYP560CfS7gihDI3nABjMehyZ8fmsz/P
    V5BtWxFjNU522hMMI1rpqZoPY8mpfcMJMFjMIvjzFHhz5ZbPWNbDNBt4JdiudtYQ49gwdokwuPcA
    86kYh28sBM2VcACmWmqS7q9NY6n3mpI8hjFw6VEBAQ6FqR2k81CfvugrdDyJmk87kCuZQaUqkhf2
    jT/T7sWNV66Eshh7FCSBDGMYf0MMQKL0NMFqQ7wiJPI5wdvl2TQFy/nkVrBxR3avx7W8IcmkcvXu
    bdxv8M2FybIIQvocrN40cnKY84JDyhPFSEllSjhwMKgpjZpCEzi/dGCCvWB3NLe4agAvJwKlLMAH
    BH/NIwIDAQAB
2022-07-21 15:43:45.970 3757-3757/com.phone.rxjava2andretrofit2 I/MineActivity: 解密*****Trump is yellow hair
知识拓展
Https 证书
我们看一下百度的 https 证书信息

公钥信息是 RSA 算法。

Https 协议是结合了非对称加密和对称加密一起工作,从而保证数据传输的安全性的。

非对称加密用于确保客户端可以安全地获取到服务器的真实公钥。
对称加密用于确保客户端和服务器之间的数据传输不会被任何人监听和解密,因为对称加密使用的密钥只有客户端和服务器这两者知道,其他任何人在不知道密钥的情况下都无法对传输数据进行解密。

数字签名是什么? - 阮一峰的网络日志

为什么如此安全的https协议却仍然可以被抓包呢?_guolin的博客-CSDN博客

写一篇最好懂的HTTPS讲解_guolin的博客-CSDN博客_https 郭霖

签名认证过程
为什么会有签名认证?

如对此有疑问,请联系qq1164688204。

推荐Android开源项目

项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。

项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/NakajimaFN/article/details/125913821

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值