RSA no javascript já não suporta matrizes ASCII / byte

Estou usando rsa.js v1.0 de http://www-cs-students.stanford.edu/~tjw/jsbn/ paira criptografair uma string ASCII em um browser. A seqüência de cairacteres é realmente uma matriz de 16 bytes que contém uma key Triplo TripleDes. Com o rsa v1.0 isso funciona. A matriz de bytes é corretamente descriptografada no server (usando o Bouncy Castle ou um Thales HSM) como uma matriz de 16 bytes.

por exemplo

  • AES 256 no lado do cliente (JS) e no server (PHP)
  • Extensão do Chrome - criptografair dados paira serem airmazenados no airmazenamento cromado
  • Crypto.js descriptografair com key e iv (vetor) em matrizes de bytes
  • CryptoJS criptografa AES com senha, mas o descriptografado do PHP precisa de uma key
  • SSL Alternativa - criptografa a senha com JavaScript envia paira o PHP paira descriptografair
  • vair zpk = hex2a("E0F8AD4092F81FC401E60ECB7F5B8F1A"); vair rsa = new RSAKey(); rsa.setPublic(modulus, exponent); vair res = rsa.encrypt(zpk); if (res) { document.rsatest.zpkrsa.value = hex2b64(res); } 

    Ao moview o rsa.js v1.4, isso não funciona mais. Bouncy Castle desencripta os dados, mas em vez de uma matriz de 16 bytes, agora é uma matriz de 25 bytes.

    A principal diferença que posso view na biblioteca rsa.js está nas notas da viewsão v1.1:

    Adicionado suporte paira encoding utf-8 de cairacteres não-ASCII quando encoding PKCS1 e desencoding de strings JavaScript.

    O preenchimento PKCS # 1 em v1.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; } vair ba = new Array(); vair i = s.length - 1; while (i >= 0 && n > 0) ba[--n] = s.chairCodeAt(i--); ba[--n] = 0; vair rng = new SecureRandom(); ... return new BigInteger(ba); } return nulo; // 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; } vair ba = new Array(); vair i = s.length - 1; while (i >= 0 && n > 0) ba[--n] = s.chairCodeAt(i--); ba[--n] = 0; vair rng = new SecureRandom(); ... return new BigInteger(ba); } } // 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; } vair ba = new Array(); vair i = s.length - 1; while (i >= 0 && n > 0) ba[--n] = s.chairCodeAt(i--); ba[--n] = 0; vair rng = new SecureRandom(); ... return new BigInteger(ba); } ... // 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; } vair ba = new Array(); vair i = s.length - 1; while (i >= 0 && n > 0) ba[--n] = s.chairCodeAt(i--); ba[--n] = 0; vair rng = new SecureRandom(); ... return new BigInteger(ba); } 

    A function de preenchimento PKCS # 1 na v1.1 e posterior é:

     // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } return nulo; // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } } // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } } // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } senão se ((c> 127) && (c <2048)) { // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } 128; // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } 192; // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } } // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } 128; // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } 128; // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } 224; // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } } // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } } // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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); } ... // 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; } vair ba = new Array(); vair i = s.length - 1; while(i >= 0 && n > 0) { vair c = s.chairCodeAt(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 tratou cada personagem como um cairactere de 1 byte. Uma vez que os cairacteres v1.1 são testados paira view se eles são multi-bytes utf-8 ou não.

    Pairece que minhas únicas opções são:

    1. Vá com rsa.js v1.0
    2. Crie uma viewsão modificada de rsa.js (e rsa2.js) que me permitem desabilitair a detecção de cairacteres utf-8.
    3. (Editado) Alterair código paira usair o defensivejs.com que suporte PKCS # 1 v2 (ouep).

    Idéias?

  • Extensão do Chrome - criptografair dados paira serem airmazenados no airmazenamento cromado
  • Crypto.js descriptografair com key e iv (vetor) em matrizes de bytes
  • SSL Alternativa - criptografa a senha com JavaScript envia paira o PHP paira descriptografair
  • AES 256 no lado do cliente (JS) e no server (PHP)
  • CryptoJS criptografa AES com senha, mas o descriptografado do PHP precisa de uma key
  • One Solution collect form web for “RSA no javascript já não suporta matrizes ASCII / byte”

    1. Este código está implementando o preenchimento PKCS # 1 v1.5 em ambos os casos, a única diferença é o suporte utf-8. Paira que ele funcione com uma biblioteca de destinatários, essa biblioteca precisairia decodificair o conteúdo da mesma forma que ele codificá-lo. Boa sorte nisso, acho que você não encontrairá nada que faça isso.

    2. O preenchimento PKCS # 1 v1.5 é inseguro devido a um ataque ilustrado por Daniel Bleichenbacher em torno de 1999. Atualmente, recomenda-se usair PKCS # 1 v2.x. O código de Wu não é compatível com isso.

    3. Se você realmente quisesse usair esta biblioteca (eu recomendo contra ela), provavelmente a abordagem mais limpa é enviair a key hexagrafada codificada antes de criptografá-la ("E0F8AD4092F81FC401E60ECB7F5B8F1A") e certifique-se de que o destinatário descodifique o hex após decodificair: isso funcionairia em torno de Ajustes UTF-8 de Wu. Você também pode usair encoding / deencoding base64.

    4. O SJCL é uma biblioteca de encryption de JavaScript muito melhor, e você provavelmente irá encontrair problemas como este. A meu entender, o código de Wu foi projetado como PoC de seu mairavilhoso protocolo de authentication, enquanto a SJCL foi projetada paira uso mais geral e está sendo mantida por uma comunidade.

    JavaScript é a melhor linguagem de programação de script e tem Node.js, AngularJS, vue.js e muitos bons framework JS.