tablas - obtener datos de una tabla html javascript
¿Cómo puedo generar CMAC-AES en javascript? (2)
Podrías echarle un vistazo e implementarlo tú mismo. Implementar CMAC debería ser factible si tienes un bloque primitivo AES encriptando el trabajo. La parte más difícil es, probablemente, asegurarse de usar bytes reales en lugar de cualquier otro tipo que esté dentro de JavaScript.
AES CMAC está aprobado por el NIST para que pueda realizar pruebas en contra de los factores de prueba .
Estoy intentando utilizar la biblioteca de cifrado de JavaScript de Stanford para generar un token de CMAC-AES para una afirmación de OAuth 2.0, pero estoy lejos de ser un experto en criptografía. ¿Alguien puede dar un ejemplo usando sjcl o cualquier biblioteca de licencia abierta js por ahí? Ni siquiera estoy seguro de que sea posible usar las funciones existentes de sjcl.
Intenté usar un objeto de opciones como vi en esta pregunta , pero no entiendo los modos u otras opciones, y no pude encontrar ninguna documentación sobre esto. Me imagino que la sal y iv (para ser un MAC reproducible) tendrían que ser estáticos, pero no sé qué valores deberían tener.
// is there a way that works?
var token = sjcl.encrypt(secret,assertion,{salt:foo,iv:bar});
Un poco de historia ... esto es para una reescritura de aplicaciones móviles nativas (iOS y Android) a una sola aplicación híbrida (Cordova, HTML, CSS y JavaScript), y me gustaría mantener la mayor cantidad de código compartido en JavaScript como sea posible . Esto no se ejecutará en un entorno de navegador "inseguro", sino en las WebViews nativas. Si conoce otros problemas de seguridad, me gustaría escucharlos.
De lo contrario, supongo que tendré que escribir un complemento para pasar el CMAC de las implementaciones nativas.
Olvidé mencionar, también estoy usando Dojo y conozco dojox.encoding.crypto, pero el problema es el mismo para mí. No estoy seguro si puede hacer CMAC o cuánta modificación tomaría para que funcione.
Pasé demasiado tiempo este fin de semana con esta solución, pero finalmente lo hice funcionar. Es sorprendente cuántos lugares puede salir mal. Este es un módulo AMD de Dojo por lo que se puede cargar fácilmente usando un "requerir". El uso se demuestra mediante los vectores de prueba que siguen (ignore las pruebas de subclaves en el uso normal). Una peculiaridad: asegúrese de pasar la clave y los mensajes como cadenas codificadas hexadecimales. Planeo hacer que sea un poco más amigable y aceptar cadenas codificadas con utf8String también, pero con sjcl.codec es bastante fácil hacerlo por tu cuenta.
Agradecería cualquier comentario, especialmente para la función de relleno y mi uso de los métodos bitArray.
// in crypto/AesCmac.js
define([
"dojo/_base/declare"
], function(declare) {
return declare(null, {
/**
* This mostly follows the AES-128 CMAC algorithm found here.
*
* @see http://tools.ietf.org/html/rfc4493
*
*
* This module has a dependency on The Stanford Javascript Crypto Library. If using the
* minified build, be sure to add sjcl.mode.cbc object into the namespace since I guess it''s
* too "dangerous" to include.
*
* @see http://crypto.stanford.edu/sjcl/
*
*
* In JavaScript, all numbers are 64 bit floating point. The bitwise operators treat numbers
* as 32bit integers. But we''re not guaranteed all 32 bits. ~0=-1 instead of 4,294,967,295.
* So for most of these bit operations we''re using sjcl.bitArray to do the dirty work.
*
* @see http://www.hunlock.com/blogs/The_Complete_Javascript_Number_Reference
*
*
* The padding function is described here.
* @see http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#chap5_6_3_1
*/
const_Bsize : 128, // in bits! not octets (16)
const_Zero : sjcl.codec.hex.toBits("0x00000000000000000000000000000000"),
const_Rb : sjcl.codec.hex.toBits("0x00000000000000000000000000000087"),
aesCipher : {},
init : function(key) {
var keyBits = sjcl.codec.hex.toBits(key);
this.aesCipher = new sjcl.cipher.aes(keyBits);
},
xor4Words : function(x, y) {
return [
x[0] ^ y[0], x[1] ^ y[1], x[2] ^ y[2], x[3] ^ y[3]
];
},
simpleShiftLeft : function(a, shift) {
return sjcl.bitArray.bitSlice(sjcl.bitArray.concat(a, [
0
]), shift, this.const_Bsize + shift);
},
iso7816d4Padding : function(m) {
var bitLength = sjcl.bitArray.bitLength(m);
m = this.xor4Words(m, this.const_Zero);
var gap = this.const_Bsize - bitLength;
if (gap < 8)
return m;
var startWord = Math.floor(bitLength / 32);
var startByte = Math.ceil((bitLength % 32) / 8); // 0,1,2,3,4
if (startByte == 4) {
console.log("rolled over into next word");
startWord++;
startByte = 0;
if (startWord == 4) {
// this should have been caught above on gap check
console.warn("this shouldn''t ever happen");
return m;
}
}
var last32 = m[startWord];
// startByte: 0->2^31, 1->2^23, 2->2^15, 3->2^7
var bitmask = Math.pow(2, (4 - startByte) * 8 - 1)
last32 |= bitmask;
m[startWord] = last32;
return m;
},
_encrypt : function(m) {
return sjcl.bitArray.clamp(sjcl.mode.cbc.encrypt(this.aesCipher, m, this.const_Zero),
this.const_Bsize);
},
generateSubkeys : function() {
// Step 1
var L = this._encrypt(this.const_Zero);
// Step 2
var msbNeg = L[0] & 0x80000000;
var K1 = this.simpleShiftLeft(L, 1, 0);
if (msbNeg) {
K1 = this.xor4Words(K1, this.const_Rb);
}
// Step 3
msbNeg = K1[0] & 0x80000000;
var K2 = this.simpleShiftLeft(K1, 1, 0);
if (msbNeg) {
K2 = this.xor4Words(K2, this.const_Rb);
}
// Step 4
return {
"K1" : K1,
"K2" : K2
};
},
generateCmac : function(plainText) {
// Step 1
var subkeys = this.generateSubkeys();
// Step 2
var M = sjcl.codec.hex.toBits(plainText);
var len = sjcl.bitArray.bitLength(M); // in bits! not octets
var n = Math.ceil(len / this.const_Bsize);
// Step 3
var lastBlockComplete;
if (n == 0) {
n = 1;
lastBlockComplete = false;
} else {
if (len % this.const_Bsize == 0)
lastBlockComplete = true;
else
lastBlockComplete = false;
}
// Step 4
var lastStart = (n - 1) * this.const_Bsize;
var M_last = sjcl.bitArray.bitSlice(M, lastStart);
if (lastBlockComplete) {
M_last = this.xor4Words(M_last, subkeys["K1"]);
} else {
M_last = this.iso7816d4Padding(M_last);
M_last = this.xor4Words(M_last, subkeys["K2"]);
}
// Step 5
var X = this.const_Zero;
var Y;
// Step 6
for ( var i = 1; i <= n - 1; i++) {
var start = (i - 1) * this.const_Bsize;
var end = i * this.const_Bsize;
var M_i = sjcl.bitArray.bitSlice(M, start, end);
Y = this.xor4Words(X, M_i);
X = this._encrypt(Y);
}
Y = this.xor4Words(M_last, X);
// Step 7
return this._encrypt(Y);
}
});
});
Aquí están los vectores de prueba
function testAesCmac() {
/**
* <pre>
* Subkey Generation
* K 2b7e1516 28aed2a6 abf71588 09cf4f3c
* AES-128(key,0) 7df76b0c 1ab899b3 3e42f047 b91b546f
* K1 fbeed618 35713366 7c85e08f 7236a8de
* K2 f7ddac30 6ae266cc f90bc11e e46d513b
* </pre>
*/
var AesCmac = require("crypto/AesCmac");
var cmac = new AesCmac();
cmac.init("0x2b7e151628aed2a6abf7158809cf4f3c");
// Test AES-128 on zero initialization vector
var t_0 = cmac._encrypt(cmac.const_Zero);
var aes_0 = sjcl.codec.hex.toBits("0x7df76b0c1ab899b33e42f047b91b546f");
sjcl.bitArray.equal(t_0, aes_0) ? console.log("AES test passed!") : console
.error("AES test failed!");
// Test subkey equality
var subkeys = cmac.generateSubkeys();
var K1 = sjcl.codec.hex.toBits("0xfbeed618357133667c85e08f7236a8de");
sjcl.bitArray.equal(subkeys["K1"], K1) ? console.log("K1 test passed!") : console
.error("K1 test failed!");
var K2 = sjcl.codec.hex.toBits("0xf7ddac306ae266ccf90bc11ee46d513b");
sjcl.bitArray.equal(subkeys["K2"], K2) ? console.log("K2 test passed!") : console
.error("K2 test failed!");
/**
* <pre>
* Example 1: len = 0
* M <empty string>
* AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746
* </pre>
*/
var m1 = "";
var cmac1 = cmac.generateCmac(m1);
var ex1 = sjcl.codec.hex.toBits("0xbb1d6929e95937287fa37d129b756746")
sjcl.bitArray.equal(ex1, cmac1) ? console.log("cmac1 test passed!") : console
.error("cmac1 test failed!");
if (sjcl.codec.hex.fromBits(cmac1) !== "bb1d6929e95937287fa37d129b756746")
console.error(sjcl.codec.hex.fromBits(cmac1) + " !== bb1d6929e95937287fa37d129b756746");
/**
* <pre>
* Example 2: len = 16
* M 6bc1bee2 2e409f96 e93d7e11 7393172a
* AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c
* </pre>
*/
var m2 = "0x6bc1bee22e409f96e93d7e117393172a";
var cmac2 = cmac.generateCmac(m2);
var ex2 = sjcl.codec.hex.toBits("0x070a16b46b4d4144f79bdd9dd04a287c")
sjcl.bitArray.equal(ex2, cmac2) ? console.log("cmac2 test passed!") : console
.error("cmac2 test failed!");
/**
* <pre>
* Example 3: len = 40
* M 6bc1bee2 2e409f96 e93d7e11 7393172a
* ae2d8a57 1e03ac9c 9eb76fac 45af8e51
* 30c81c46 a35ce411
* AES-CMAC dfa66747 de9ae630 30ca3261 1497c827
* </pre>
*/
var m3 = "0x6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411";
var cmac3 = cmac.generateCmac(m3);
var ex3 = sjcl.codec.hex.toBits("0xdfa66747de9ae63030ca32611497c827")
sjcl.bitArray.equal(ex3, cmac3) ? console.log("cmac3 test passed!") : console
.error("cmac3 test failed!");
/**
* <pre>
* Example 4: len = 64
* M 6bc1bee2 2e409f96 e93d7e11 7393172a
* ae2d8a57 1e03ac9c 9eb76fac 45af8e51
* 30c81c46 a35ce411 e5fbc119 1a0a52ef
* f69f2445 df4f9b17 ad2b417b e66c3710
* AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe
* </pre>
*/
var m4 = "0x6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
var cmac4 = cmac.generateCmac(m4);
var ex4 = sjcl.codec.hex.toBits("0x51f0bebf7e3b9d92fc49741779363cfe")
sjcl.bitArray.equal(ex4, cmac4) ? console.log("cmac4 test passed!") : console
.error("cmac4 test failed!");
}