Reputation: 136
I'm writing code to read/write to NTAG424 DNA NFC tags. I'm doing this completely in javascript, because I want to be able to use it in a react native app.
In NTAG 424 DNA and NTAG 424 DNA TagTamper features and hints they show the results you should be getting for every step. But they use a python solution.
The input message is A55A0001008013C56268A548D8FBBF237CCCAA20EC7E6E48C3DEF9A4C675360F
and the output (according to the manual) is 1309C877509E5A215007FF0ED19CA564
. Whereas I get 7CCEF6FEB32F34CA48CB685ECAA0F32C
.
Because I need to be able to use this code commercially, I cannot just use any library.
function generateSubkeys(key) {
const cipher = crypto.createCipheriv("aes-128-ecb", key, "");
const cryptedKey = cipher.update(iv);
let subkey1 = bt.bitShiftLeft(cryptedKey);
if (msb(cryptedKey[0]) & 0x80) {
subkey1 = xor(subkey1, 0x87);
}
let subkey2 = bt.bitShiftLeft(subkey1);
if (msb(subkey1[0]) & 0x80) {
subkey2 = xor(subkey2, 0x87);
}
return { subkey1: subkey1, subkey2: subkey2 };
}
function msb(bytes) {
return bytes >>> 31;
}
function aes(key, message) {
const cipher = crypto.createCipheriv(
"aes-" + key.length * 8 + "-cbc",
key,
iv
);
var result = cipher.update(message);
cipher.final();
return result;
}
function aesCmac(key, message) {
const { subkey1, subkey2 } = generateSubkeys(Buffer.from(key, "hex"));
let numBlocks = Math.ceil(message.length / blockSize);
var lastBlockRemainder = message.length % blockSize;
if (numBlocks === 0) {
numBlocks = 1;
}
var messageArray = getMessageArray(message, numBlocks, lastBlockRemainder);
if (lastBlockRemainder === 0) {
messageArray[numBlocks - 1] = xor(messageArray[numBlocks - 1], subkey1);
} else {
messageArray[numBlocks - 1] = xor(messageArray[numBlocks - 1], subkey2);
}
var c = aes(
key,
Buffer.concat(messageArray.slice(0, messageArray.length - 1))
);
let c_xor_m = xor(c, messageArray[messageArray.length - 1]);
c = aes(key, c_xor_m);
return c;
}
function getMessageArray(message, numBlocks, lastBlockRemainder) {
var index = 0;
var messageArray = [];
if (lastBlockRemainder !== 0) {
let padding = "80" + "00".repeat(16 - lastBlockRemainder - 1);
let appendToMessage = Buffer.from(padding, "hex");
message = Buffer.concat([message, appendToMessage]);
}
for (index = 0; index < numBlocks; index++) {
let messageBlock = message.slice(
index * blockSize,
(index + 1) * blockSize
);
messageArray.push(messageBlock);
}
return messageArray;
}
I already tried the one mentioned here AES-CMAC module for Node.js? and completely rewriting the code to my own version of an AES-CMAC algorithm. In both the one I tried and the one I made (with the help of NIST Special Publication 800-38B), I get the same results.
Now I'm stuck between thinking either my code is wrong, or the python crypto library (where I don't completely understand the code) is wrong.
Can anyone help me figure out which of the two is true? And in case my code is wrong, help me fix it.
Upvotes: 2
Views: 530
Reputation: 136
I found the answer: The Crypto library in javascript has an aes-cbc cipher, that says (and it does) accepts buffers and arrays. But the outcomes of both are different.
When I used a UInt8Array I got the right outcome. I completely rewrote an aes-cmac algorithm, just to figure out this what all I needed.
Upvotes: 0