RSA 敏感数据加解密方案

RSA 敏感数据加解密方案

文章目录

  • RSA 敏感数据加解密方案
    • RSA密码
    • RSA加解密算法
    • 举个例子
      • 加密
      • 解密
    • 超长文本加密方案
    • REFERENCES

手机用户请横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以扫码加入『知识星球』(文末)获取长期知识分享服务。


RSA密码

RSA密码是1978年美国麻省理工学院三位密码学者R.L.Rivest、A.Shamir和L.Adleman提出的一种基于大合数因子分解困难性的公开密钥密码。由于RSA密码既可用于加密,又可用于数字签名,通俗易懂,因此RSA密码已成为目前应用最广泛的公开密钥密码。RSA算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法。在了解RSA算法之前,先熟悉下几个术语,根据密钥的使用方法,可以将密码分为对称密码和公钥密码。

  • 对称密码:加密和解密使用同一种密钥的方式
  • 公钥密码:加密和解密使用不同的密码的方式,因此公钥密码通常也称为非对称密码。

RSA加解密算法

1.随机地选择两个大素数p和q,而且保密;

2.计算n=pq,将n公开;

3.计算φ(n)=(p-1)(q-1),对φ(n)保密;

4.随机地选取一个正整数e,1

5.根据ed=1(mod φ(n)),求出d,并对d保密;

6.加密运算:c=m^e(mod n); 也就是说对密文进行D次方后除以N的余数就是明文,这就是RSA解密过程。知道D和N就能进行解密密文了,所以D和N的组合就是私钥

7.解密运算:m=c^d(mod n)。

注意:在加密运算和解密运算中,m和c的值都必须小于n,也就是说,如果明文(或密文)太大,必须进行分组加密(或解密)

RSA的加密方式和解密方式是相同的,加密是求``e次方的mod n;解密是求d次方的mod n,此处d`是解密(Decryption)的首字母;n是数字(Number)的首字母;e是加密(Encrypt)的首字母。

举个例子

小写转为大写,便于阅读,

表达式约定

RSA 敏感数据加解密方案_第1张图片

求解方式

RSA 敏感数据加解密方案_第2张图片

N

我们准备两个很小对质数,
p = 17
q = 19
N = p * q = 323

L

L 是 p-1 和 q-1的最小公倍数,可用如下表达式表示L = lcm(p-1, q-1)

L`= lcm(16,18) = 144,即144为16和18对最小公倍数

E

求E必须要满足2个条件:1 < E < L ,gcd(E,L)=1,即1 < E < 144,gcd(E,144) = 1
E和144互为质数,5显然满足上述2个条件
故E = 5,此时公钥=(E,N)= (5,323)

D

求D也必须满足2个条件:1 < D < L,E*D mod L = 1
即1 < D < 144,5 * D mod 144 = 1
显然当D= 29 时满足上述两个条件
1 < 29 < 144
5*29 mod 144 = 145 mod 144 = 1
此时私钥=(D,N)=(29,323)

加密

准备的明文必须时小于N的数,因为加密或者解密都要mod N其结果必须小于N
假设明文 = 123
则 密文=明文^E mod N=123^5 mod 323=225

解密

明文=密文^D mod N=225^29 mod 323=123
解密后的明文为123。

好了至此RSA的算法原理已经讲解完毕,是不是很简单?

超长文本加密方案

问题原因:
前端敏感数据加密,文本过长导致加密失败。

日志

Data must not be longer than 245 bytes
javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes

原因: 待加密数据超长的原因

处理方式: 分片加解密

/*
 * @ProjectName: 编程学习
 * @Copyright:   2020 HangZhou Yiyuery Dev, Ltd. All Right Reserved.
 * @address:     微信搜索公众号「架构探险之道」获取更多资源。
 * @date:        2020/8/15 4:50 下午
 * @description: 本内容仅限于编程技术学习使用,转发请注明出处.
 */
package com.dsb.framework.boot.security.ed;

import org.apache.commons.io.IOUtils;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 

* RSA 加解密工具类 *

* * @author Yiyuery * @date 2020/8/15 4:50 下午 */
public class RsaAssistant { /** * 算法名称 */ private static final String KEY_ALGORITHM = "RSA"; /** * 密钥长度 */ private static final int KEY_SIZE = 2048; /** * RSA最大加密明文大小 KEY_SIZE/8-11 */ private static final int MAX_ENCRYPT_BLOCK = 245; /** * RSA最大解密密文大小 KEY_SIZE/8 */ private static final int MAX_DECRYPT_BLOCK = 256; /** * 随机生成密钥对(包含公钥和私钥) */ public static KeyPair generateKeyPair() throws Exception { // 获取指定算法的密钥对生成器 KeyPairGenerator gen = KeyPairGenerator.getInstance(KEY_ALGORITHM); // 初始化密钥对生成器(指定密钥长度, 使用默认的安全随机数源) gen.initialize(KEY_SIZE); // 随机生成一对密钥(包含公钥和私钥) return gen.generateKeyPair(); } /** * 将 公钥/私钥 编码后以 Base64 的格式保存到指定文件 */ public static void saveKeyForEncodedBase64(Key key, File keyFile) throws IOException { // 获取密钥编码后的格式 byte[] encBytes = key.getEncoded(); // 转换为 Base64 文本 String encBase64 = Base64Utils.encodeToString(encBytes); // 保存到文件 IOUtils.write(encBase64, new FileWriter(keyFile)); } /** * RSA公钥加密 * * @param str 加密字符串 * @param publicKey 公钥 * @return 密文 * @throws Exception 加密过程中的异常信息 */ public static String encrypt(String str, String publicKey) throws Exception { //base64编码的公钥 byte[] decoded = Base64Utils.decodeFromString(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(decoded)); //RSA加密 String outStr = Base64Utils.encodeToString(cipherEncrypt(str, pubKey)); return outStr; } private static byte[] cipherEncrypt(String str, RSAPublicKey pubKey) throws Exception { byte[] srcBytes = str.getBytes("UTF-8"); Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, pubKey); return cipherDoFinal(cipher,srcBytes,MAX_ENCRYPT_BLOCK); } /** * RSA私钥解密 * * @param str 加密字符串 * @param privateKey 私钥 * @return 铭文 * @throws Exception 解密过程中的异常信息 */ public static String decrypt(String str, String privateKey) throws Exception { //64位解码加密后的字符串 byte[] inputByte = Base64Utils.decode(str.getBytes("UTF-8")); //base64编码的私钥 byte[] decoded = Base64Utils.decodeFromString(privateKey); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decoded)); //RSA分段解密 String outStr = new String(cipherDecrypt(inputByte, priKey)); return outStr; } /** * 分段解密 * * @param inputByte * @param priKey * @return */ private static byte[] cipherDecrypt(byte[] inputByte, RSAPrivateKey priKey) throws Exception { Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, priKey); return cipherDoFinal(cipher,inputByte,MAX_DECRYPT_BLOCK); } /** * 分段大小 * * @param cipher * @param srcBytes * @return * @throws Exception */ private static byte[] cipherDoFinal(Cipher cipher, byte[] srcBytes,int segment) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); int inputLen = srcBytes.length; int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > segment) { cache = cipher.doFinal(srcBytes, offSet, segment); } else { cache = cipher.doFinal(srcBytes, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * segment; } byte[] data = out.toByteArray(); out.close(); return data; } }

超长加密测试

/**
     * 测试加解密
     */
    @Test
    public void encryptAndDecrypt() throws Exception {
     
        String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqtu2aVZv7xG0Ti2JxvJojR2l9yF+w9ptIYGLAoTVISzQ80V43Otxx769idFyLRDDaxcIMFMmBX2IKhQjBecUMxPuo1nKJq6HEVfTKXaWezJgedyY+HfmkoVBZ6f0FEWUXwQlLKMazQ7T1Uu5nYD5RqYm+UDW70kEPcMz+S5RJ2URBTXHtJx4dgnfY+jWD77o1Rag4Rai6/N8qXVnDhx5LAmxT+efmnJ3Uw74yJqJMmRaHlwOoERm7kIiS6w084Fi4ttFk+HlRDqo5/tRL00BmNOh4pbjoln+8hwgqzwQkpAwZp2Y2S0OelCIsl07LqnY+XIMZVpEfq4K8223skWw1wIDAQAB";
        String priKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCq27ZpVm/vEbROLYnG8miNHaX3IX7D2m0hgYsChNUhLNDzRXjc63HHvr2J0XItEMNrFwgwUyYFfYgqFCMF5xQzE+6jWcomrocRV9MpdpZ7MmB53Jj4d+aShUFnp/QURZRfBCUsoxrNDtPVS7mdgPlGpib5QNbvSQQ9wzP5LlEnZREFNce0nHh2Cd9j6NYPvujVFqDhFqLr83ypdWcOHHksCbFP55+acndTDvjImokyZFoeXA6gRGbuQiJLrDTzgWLi20WT4eVEOqjn+1EvTQGY06HiluOiWf7yHCCrPBCSkDBmnZjZLQ56UIiyXTsuqdj5cgxlWkR+rgrzbbeyRbDXAgMBAAECggEBAJ3WBnbdEN5rHoOx8btFqGvkXbMk0DQhjfsL7tzO1QymmAiDvxlmr190xyePwsf62mwNhNUPmuorgyRMIeaMB87/tM5WXjbJt6C/3yRIls8MRK+OqAmwyeHFFByrvQEVHfGApM7Nhi60aeB66eekg6NOTmaoDWZTr4VW1KZ2sSWP3/XG1m+ursijpVBJcDJLClAoY32HmQ0IkwBqt2yI03esI+Y/fgFKUwM9XWQo0NPfCncaxu7cpnIi7wccs0So00VmvsFua/HcryhjkCgEaZi9nZgGMZbRIDPn6Rh/xJ3uS5tHFMNqkF8Xd67zIuneBWFG7Au4x/fcW3/Y40LnBAECgYEA/p+MAiXK2o4WMH7apggHXLTQsJCRvblkj/Qo5fV2EXdlAS+hvrV8+C7pEufI0r5kLB/0LDwB4cZFk+xK4XPB7xUgJKoO80NxXCvYIFgXAivu69EBJoV3o2CRqsoK4CGaykWTwKnNCkrD6hGFYVJLHBGe/K3alAL9lfuFdzj0tdcCgYEAq8g3iv3LY/qY/b00AUgEsGJlISDZ6ROZWhYHzypbmFKNjTbUh3EoHlyhXdmwad9lW2gr5ixlIydjg7MhYbNvr9JSsXM+iYIH8/DjiHkmg8WGhDMb72Bo65GkUUsPl/JuMycF50L9UyQkPaabej4PiI03LXCxnKyeqGK9+rjRfQECgYAsrvkWA2XW9upj9k8OpggMt9qLscMxxVAlhxaKTIo8xHQgQiijXBwjPbA/VhfDDBBuQelKvfkikvXw4J2/dN4Kw+1RIdrfy+0f3L3f5zWadvVFwvbtuKxnKnJFw5EnBh6w8obcX7AQ50/8SrjafGOb+GerNiNOqDuyT2J7qq4fHwKBgQCJMNnLE24AZv8Qhq6l51J3W93QW2AtGQ38OGP8O6PzPtr10Lhjgye7N9dYEKcnptZX7hZBOWt8a9S6NbGPSbMFBEAuoA9t2n9nfxb4w2jTDEmmAvtobeLdX++PTRcjDuaby6qXS5TtdYvMAOdi9XWKZN2QWNRAgEwlxtZbCoekAQKBgQDy+ZlS4iM36LzN5BWPncXRmnGUNnDsSoWpP7yXjOuDpKFMF4cZi+0jDwyHxhSTTg24JOcZDZdRmkvQtF2cgC2QCN9twqLM79+VlGV/KABX0xebZdz6DrlWDwk7jem6b3zCh1XwuzHAvTPthIgGUGBPZjHQgcwoozXZ/TXY0fAlSg==";
        String text = "asdasdasda";
        for (; text.length() < 200; text += text) {
     

        }
        String encodeStr = RsaAssistant.encrypt(text, pubKey);
        LogAssistant.info("解密后:{}", RsaAssistant.decrypt(encodeStr, priKey));
    }

在这里插入图片描述

REFERENCES

  • RSA加密与解密(Java实现)

  • RSA加密文本过长

  • rsa加解密的内容超长的问题解决

  • Java RSA分段加密

  • RSA详解(Java实现)

  • RSA算法原理(一)

  • RSA算法原理(二)

  • 带你彻底理解RSA算法原理


RSA 敏感数据加解密方案_第3张图片
RSA 敏感数据加解密方案_第4张图片

你可能感兴趣的:(算法,信息安全,RSA)