前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RSA 敏感数据加解密方案

RSA 敏感数据加解密方案

作者头像
架构探险之道
发布2020-08-17 17:29:32
1.1K0
发布2020-08-17 17:29:32
举报
文章被收录于专栏:架构探险之道架构探险之道

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<e<φ(n)且(e,φ(n))=1,将e公开;

  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)的首字母。

举个例子

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

表达式约定

在这里插入图片描述

求解方式

在这里插入图片描述

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

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

处理方式: 分片加解密

代码语言:javascript
复制
/*
 * @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;

/**
 * <p>
 * RSA 加解密工具类
 * </p>
 *
 * @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;
    }
}

超长加密测试

代码语言:javascript
复制
/**
     * 测试加解密
     */
    @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));
    }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构探险之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RSA 敏感数据加解密方案
    • RSA密码
      • RSA加解密算法
        • 举个例子
          • 加密
          • 解密
        • 超长文本加密方案
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档