How do I encrypt Crypto-JS keys with JSBN?

自闭症网瘾萝莉.ら 提交于 2019-12-11 02:22:49

问题


I'm using JSBN to encrypt/decrypt data using public/private keypairs. It works great for text data, including hex strings.

My problem is now I have binary data, specifically Crypto-JS Word Arrays, that I need to encrypt with a public key and send along to another platform.

So consider this:

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

This works but it means 'encrypted_key' is infact a hex string that's been encrypted, not the actual key. I need to encrypt the actual key.

So I see two challenges here:

1) I'm not 100% sure how to get the actual bytes out of a CryptoJS.lib.WordArray -- though that doesn't seem totally insurmountable.

2) I have no idea if it's even possible to encrypt binary data using JSBN. I'd love pointers to figure out how to do it.

Any thoughts?


回答1:


The JSBN library contains a function, namely pkcs1pad2(), wherein it converts the text to numeric values using JavaScript's charCodeAt() function. You'll see that conversion code in the first while() loop:

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);
}

If you wish to encrypt binary data then you'll likely have to modify this function so it converts the input in the way you want it.

Below is an example of pkcs1pad2() modified to accept binary data in the form of a hex string. If you use this version of pkcs1pad2() then you can convert your CryptoJS.lib.WordArray into hex and pass that hex string to 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);
}

Alternatively, you could modify it to take the WordArray directly and convert that to the array format that is used by JSBN, but I'll leave that as an exercise for the reader.




回答2:


the pkcs1pad2 function converted from javascript to java:

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);
}

the rsa encription:

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");
}

and the 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;
 }


来源:https://stackoverflow.com/questions/16680631/how-do-i-encrypt-crypto-js-keys-with-jsbn

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!