2

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.

Zen Zac
  • 136
  • 1
  • 9

1 Answers1

0

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.

Zen Zac
  • 136
  • 1
  • 9