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?