3

我正在使用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 加密二进制数据。我很想知道如何做到这一点。

有什么想法吗?

4

2 回答 2

3

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 使用的数组格式,但我将把它作为练习留给读者。

于 2013-05-23T03:51:58.110 回答
0

从 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;
 }
于 2013-11-19T09:57:53.957 回答