RSA in javascript no longer supports ASCII / byte arrays

I am using rsa.js v1.0 from http://www-cs-students.stanford.edu/~tjw/jsbn/ to encrypt an ASCII string in a browser. The string is actually a 16-byte array containing the TripleDes key of double length. With rsa v1.0 this works. The byte array is correctly decrypted on the server (using Bouncy Castle or Thales HSM) as an array of 16 bytes in size.

eg.

var zpk = hex2a("E0F8AD4092F81FC401E60ECB7F5B8F1A"); var rsa = new RSAKey(); rsa.setPublic(modulus, exponent); var res = rsa.encrypt(zpk); if (res) { document.rsatest.zpkrsa.value = hex2b64(res); } 

When moving rsa.js v1.4 it no longer works. Bouncy castle decrypts the data, but instead of a 16-byte array, it now constitutes a 25-byte array.

The key difference that I see in the rsa.js library is in the v1.1 release notes:

Added support for encoding utf-8 characters other than ASCII when PKCS1 encodes and decodes JavaScript strings.

Filling PKCS # 1 in version 1.0:

 // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint function pkcs1pad2(s, n) { if (n < s.length + 11) { alert("Message too long for RSA"); return null; } var ba = new Array(); var i = s.length - 1; while (i >= 0 && n > 0) ba[--n] = s.charCodeAt(i--); ba[--n] = 0; var rng = new SecureRandom(); ... return new BigInteger(ba); } 

PKCS # 1 fill function in version 1.1 and later:

 // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint function pkcs1pad2(s,n) { if(n < s.length + 11) { // TODO: fix for utf-8 console.error("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; ... return new BigInteger(ba); } 

rsa.js v1.0 treated each character as a 1-byte character. Because characters v1.1 are tested to see if they are multibyte utf-8 or not.

It seems my only options are:

  • Stick with rsa.js v1.0
  • Create a modified version of rsa.js (and rsa2.js) that allows me to disable utf-8 character recognition.
  • (Edited) Change the code to use defensivejs.com, which supports PKCS # 1 v2 (oaep).

Ideas?

+6
source share
1 answer
  • This code implements the PKCS # 1 v1.5 add-on in both cases, the only difference is utf-8 support. For it to work with the destination library, this library will have to decode the content in the same way that it encodes it. Good luck with this, I donโ€™t think you will find anything that does this.

  • PKCS # 1 v1.5 padding is unsafe due to the attack illustrated by Daniel Bleichenbacher in 1999. PKCS # 1 v2 is currently recommended. X. Wu code does not support this.

  • If you really wanted to use this library (I recommend against it), perhaps the cleanest approach is to send a hexadecimal key before you encrypt it ("E0F8AD4092F81FC401E60ECB7F5B8F1A") and make sure the recipient's hex code decodes it after decrypt: this will work with Wu UTF-8 settings. You can also use base64 encoding / decoding.

  • SJCL is a much better JavaScript cryptographic code library, and you are unlikely to encounter such problems. As far as I know, Wu code was designed as the PoC of its wonderful authentication protocol, while SJCL is for more general use and is supported by the community.

+3
source

All Articles