【问题标题】:How do I encrypt Crypto-JS keys with JSBN?如何使用 JSBN 加密 Crypto-JS 密钥?
【发布时间】:2013-05-21 22:34:27
【问题描述】:

我正在使用JSBN 使用公钥/私钥对加密/解密数据。它适用于文本数据,包括十六进制字符串。

我的问题是我现在有二进制数据,特别是 Crypto-JS 字数组,我需要用公钥加密并发送到另一个平台。

所以考虑一下:

var key = CryptoJS.lib.WordArray.random(256/8);
var rsa = new RSAKey();
rsa.setPublic(modulus, exponent);
var encrypted_key = rsa.encrypt(key.toString());

这可行,但这意味着“encrypted_key”实际上是一个已加密的十六进制字符串,而不是实际的密钥。我需要加密实际的密钥。

所以我在这里看到了两个挑战:

1) 我不能 100% 确定如何从 CryptoJS.lib.WordArray 中获取实际字节——尽管这似乎并非完全不可克服。

2) 我不知道是否可以使用 JSBN 加密二进制数据。我很想知道如何做到这一点。

有什么想法吗?

【问题讨论】:

    标签: javascript rsa cryptojs jsbn


    【解决方案1】:

    JSBN 库包含一个函数,即 pkcs1pad2(),它使用 JavaScript 的 charCodeAt() 函数将文本转换为数值。您将在第一个 while() 循环中看到转换代码:

    function pkcs1pad2(s,n) {
      if(n < s.length + 11) { // TODO: fix for utf-8
        alert("Message too long for RSA");
        return null;
      }
      var ba = new Array();
      var i = s.length - 1;
      while(i >= 0 && n > 0) {
        var c = s.charCodeAt(i--);
        if(c < 128) { // encode using utf-8
          ba[--n] = c;
        }
        else if((c > 127) && (c < 2048)) {
          ba[--n] = (c & 63) | 128;
          ba[--n] = (c >> 6) | 192;
        }
        else {
          ba[--n] = (c & 63) | 128;
          ba[--n] = ((c >> 6) & 63) | 128;
          ba[--n] = (c >> 12) | 224;
        }
      }
      ba[--n] = 0;
      var rng = new SecureRandom();
      var x = new Array();
      while(n > 2) { // random non-zero pad
        x[0] = 0;
        while(x[0] == 0) rng.nextBytes(x);
        ba[--n] = x[0];
      }
      ba[--n] = 2;
      ba[--n] = 0;
      return new BigInteger(ba);
    }
    

    如果您希望加密二进制数据,那么您可能必须修改此函数,以便它以您想要的方式转换输入。

    以下是修改为接受十六进制字符串形式的二进制数据的 pkcs1pad2() 示例。如果您使用此版本的 pkcs1pad2(),那么您可以将 CryptoJS.lib.WordArray 转换为十六进制并将该十六进制字符串传递给 rsa.encrypt()。

    function pkcs1pad2(hexPlaintext,n) {
      if(n < hexPlaintext.length/2 + 11) {
        alert("Message too long for RSA");
        return null;
      }
      var ba = new Array();
      var i = hexPlaintext.length;
      while(i >= 2 && n > 0) {
        ba[--n] = parseInt(hexPlaintext.slice(i-2,i),16);
        i-=2;
      }
      ba[--n] = 0;
      var rng = new SecureRandom();
      var x = new Array();
      while(n > 2) { // random non-zero pad
        x[0] = 0;
        while(x[0] == 0) rng.nextBytes(x);
        ba[--n] = x[0];
      }
      ba[--n] = 2;
      ba[--n] = 0;
      return new BigInteger(ba);
    }
    

    或者,您可以修改它以直接获取 WordArray 并将其转换为 JSBN 使用的数组格式,但我将把它留给读者作为练习。

    【讨论】:

    • 太棒了!当然,另一端——pkcs1unpad2——需要进行类似的修改(或扩展)。
    【解决方案2】:

    从javascript转换为java的pkcs1pad2函数:

    public BigInteger pkcs1pad2(String data,int keysize){
        byte[] buffer=new byte[keysize];
        Random rg=new Random();
    
        if(keysize < data.length()+11)
            return null;
    
        int i = data.length() - 1;
        while(i >= 0 && keysize > 0){
            --keysize;
            buffer[keysize] = (byte) data.charAt(i);
            i--;
        }
        --keysize;
        buffer[keysize] = 0;
        while(keysize > 2){
            --keysize;
            buffer[keysize] = (byte) (rg.nextInt(254)+1);
        }
        --keysize;
        buffer[keysize] = 2;
        --keysize;
        buffer[keysize] = 0;
    
        return new BigInteger(buffer);
    }
    

    rsa 加密:

    http://hc.apache.org/downloads.cgi

    //you need httpcomponents-client-4.3.1-bin.zip from apache.org
    //this contains working Base64 encoder!
    import org.apache.commons.codec.binary.Base64;
    public String encrypt(String data,String modulus,String exponent) throws UnsupportedEncodingException{
        byte[] exp=Helper.hexToBytes(exponent.toCharArray());
        byte[] mod=Helper.hexToBytes(modulus.toCharArray());
    
        BigInteger expB=new BigInteger(exp);
        BigInteger modB=new BigInteger(mod);
    
        BigInteger data2=this.pkcs1pad2(data, (modB.bitLength()+7)>>3);
        BigInteger data3=data2.modPow(expB, modB);
    
        byte[] encoding = (new Base64()).encode(Helper.hexToBytes(data3.toString(16).toCharArray()));
        return new String(encoding, "US-ASCII");
    }
    

    还有 Helper.HexToBytes:

     public static byte[] hexToBytes(char[] hex)throws IllegalArgumentException{
         byte[] data = new byte[hex.length / 2];
         for (int i = 0, j = 0; j < data.length; ++j){
             int hi = Character.digit(hex[i++], 16);
             int lo = Character.digit(hex[i++], 16);
             if ((hi < 0) || (lo < 0))
                 throw new IllegalArgumentException();
             data[j] = (byte) (hi << 4 | lo);
         }
         return data;
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      • 2018-01-09
      • 2023-03-17
      • 2013-08-16
      相关资源
      最近更新 更多