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 that contains a double-length TripleDes key. With rsa v1.0 this works. The byte array is correctly decrypted on the server (using Bouncy Castle or a Thales HSM) as a 16 byte array.
e.g.
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 the rsa.js v1.4 this not longer works. Bouncy castle decrypts the data, but instead of a 16 byte array, it is now a 25 byte array.
The key difference I can see in the rsa.js library is in the v1.1 release notes:
Added support for utf-8 encoding of non-ASCII characters when PKCS1 encoding and decoding JavaScript strings.
The PKCS#1 padding in v1.0 is:
// 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);
}
The PKCS#1 padding function in v1.1 and later is:
// 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. Since v1.1 characters are tested to see if they are multi-byte utf-8 or not.
It seems my only options are to either:
- Stick with rsa.js v1.0
- Create a modified version of rsa.js (and rsa2.js) that allow me to disable to utf-8 character detection.
- (Edited) Alter code to use defensivejs.com which supports PKCS#1 v2 (oaep).
Ideas?