rsa加解密字符串

之前在做项目时,客户提了个需求说是对前后台交互进行加密传输,我们给的解决方案是前端进行加密后将加密数据传输给后台,然后后台根据对应的密钥进行解密,当时选择的算法是rsa算法,但是大家都知道rsa算法加解密是有最大长度限制的,加密的最长字符串是117个字节,解密的最大长度是

前端js使用jsencrypt模块进行加密,jsencrypt模块原来只支持不超过117字节的字符串的加密,我对其进行了再次封装,现在支持超长字符串的加密,目前看还没有限制。该方案首先需要下载jsencrypt-master模块,下载地址如下:

define([
  'jsencrypt-master',
], function(JsEncrypt) {
  var encrypt = new JsEncrypt.JSEncrypt();
  var publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8uzbhIUv3zdejTP/XKqkGE/UktNExg3wX++1W6ccWEFsSm5S0GdCmy2gdZqXiLHnditoMYHrA6GoUChE9+QyiZKmeuCjJgzbx2pR6RW4eEwEoGl0+kmz+yK3bOFeLSS/hdbgBUH7cuzbrAK3/nF7aegzgOSX7Ezde7b2jRTK9PwIDAQAB';
  encrypt.setPublicKey(publicKey);
  var b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  var b64pad = '=';

  function hex2b64(h) {
    var i;
    var c;
    var ret = '';
    for (i = 0; i + 3 <= h.length; i += 3) {
      c = parseInt(h.substring(i, i + 3), 16);
      ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
    }
    if (i + 1 == h.length) {
      c = parseInt(h.substring(i, i + 1), 16);
      ret += b64map.charAt(c << 2);
    }
    else if (i + 2 == h.length) {
      c = parseInt(h.substring(i, i + 2), 16);
      ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
    }
    while ((ret.length & 3) > 0) {
      ret += b64pad;
    }
    return ret;
  }
  return function encryptLong (string) {
    var k = encrypt.getKey();
    try {
      var ct = '';
      //RSA每次加密117bytes,需要辅助方法判断字符串截取位置
      //1.获取字符串截取点
      var bytes = new Array();
      bytes.push(0);
      var byteNo = 0;
      var len, c;
      len = string.length;
      var temp = 0;
      for (let i = 0; i < len; i++) {
        c = string.charCodeAt(i);
        if (c >= 0x010000 && c <= 0x10FFFF) {
          byteNo += 4;
        } else if (c >= 0x000800 && c <= 0x00FFFF) {
          byteNo += 3;
        } else if (c >= 0x000080 && c <= 0x0007FF) {
          byteNo += 2;
        } else {
          byteNo += 1;
        }
        if ((byteNo % 117) >= 114 || (byteNo % 117) == 0) {
          if (byteNo - temp >= 114) {
            bytes.push(i);
            temp = byteNo;
          }
        }
      }
      //2.截取字符串并分段加密
      if (bytes.length > 1) {
        for (let i = 0; i < bytes.length - 1; i++) {
          var str;
          if (i == 0) {
            str = string.substring(0, bytes[i + 1] + 1);
          } else {
            str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);
          }
          var t1 = k.encrypt(str);
          ct += t1;
        }
        if (bytes[bytes.length - 1] != string.length - 1) {
          var lastStr = string.substring(bytes[bytes.length - 1] + 1);
          ct += k.encrypt(lastStr);
        }
        return hex2b64(ct);
      }
      var t = k.encrypt(string);
      var y = hex2b64(t);
      return y;
    } catch (ex) {
      return false;
    }
  };
});

后台使用python的内置模块PKCS1_v1_5解密,也是进行了再次封装,以下代码可以支持超长字符串解密,我用的是python2.7,使用python3及以上的版本可能会有些许不同,大家可以根据自己的实际情况进行调整。

import os
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
import base64
# from urllib import parse

# 获取当前路径
curr_dir = os.path.dirname(os.path.realpath(__file__))
private_key_file = os.path.join(curr_dir, "my_private_rsa_key.bin") # 私钥,和前端加密使用的保持一致
public_key_file = os.path.join(curr_dir, "my_rsa_public.pem")  # 公钥,和前端加密使用的保持一致

# 适合加密前明文长度不超过117直接的字符串解密
def decrypt_data(inputdata, code="123456"):
    # URLDecode
    # data = parse.unquote(inputdata)

    # openssl genrsa - out rsa_1024_priv.pem 1024  生成私钥
    # openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem 生成公钥

    # base64decode
    data = base64.b64decode(inputdata)

    private_key = RSA.importKey(
        open(curr_dir + "/my_private_rsa_key.bin").read(),
        passphrase=code
    )
    # 使用 PKCS1_v1_5,不要用 PKCS1_OAEP
    # 使用 PKCS1_OAEP 的话,前端 jsencrypt.js 加密的数据解密不了
    cipher_rsa = PKCS1_v1_5.new(private_key)

    # 当解密失败,会返回 sentinel
    sentinel = None
    ret = cipher_rsa.decrypt(data, sentinel)

    return ret

# 适合加密前明文长度不超过117(及密文长度不超过128字节)直接的字符串和明文长度超过117字节的字符串解密
def rsa_decrypt(msg, code="123456"):
    """
    1024bit的证书用128,2048bit证书用256位
    """
    private_key = RSA.importKey(
        open(curr_dir + "/my_private_rsa_key.bin").read(),
        passphrase=code
    )
    cipher = PKCS1_v1_5.new(private_key)
    tempData = base64.b64decode(msg)
    # 当解密失败,会返回 sentinel
    sentinel = None
    offset = 0
    res = []
    length = len(tempData)
    # 128:rsa算法加密后并转成十六进制的最大密文长度
    if length > 128:
        while length - offset > 0:
            if length - offset > 128:
                tempStr = tempData[offset: offset+128]
            else:
                tempStr = tempData[offset:]
            # data = base64.b64decode(tempStr)
            ret = cipher.decrypt(tempStr, sentinel)
            res.append(ret)
            offset += 128
        return "".join(res)
    else:
        ret = cipher.decrypt(tempData, sentinel)
        return ret

呼~终于解决了一个大难题,亲测加解密成功,并且支持中文

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值