aes-cmac в javascript не дает таких же результатов, как в python

Я пишу код для чтения/записи в теги NTAG424 DNA NFC. Я делаю это полностью в javascript, потому что хочу использовать его в нативном приложении для реагирования.

В функциях и подсказках NTAG 424 DNA и NTAG 424 DNA TagTamper они показывают результаты, которые вы должны получить для каждого шага. Но они используют решение Python.

Входное сообщение — A55A0001008013C56268A548D8FBBF237CCCAA20EC7E6E48C3DEF9A4C675360F, а выходное (согласно руководству) — 1309C877509E5A215007FF0ED19CA564. В то время как я получаю 7CCEF6FEB32F34CA48CB685ECAA0F32C.

Поскольку мне нужно иметь возможность использовать этот код в коммерческих целях, я не могу просто использовать любую библиотеку.

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;
}

Я уже пробовал упомянутый здесь модуль AES-CMAC для Node.js? и полностью переписать код на мою собственную версию алгоритма AES-CMAC. Как в том, что я пробовал, так и в том, который я сделал (с помощью Специальная публикация NIST 800-38B), я получаю те же результаты.

Теперь я застрял между мыслью, что мой код неверен, или криптобиблиотека python (где я не совсем понимаю код) неверна.

Может ли кто-нибудь помочь мне понять, какое из двух верно? И в случае, если мой код неверен, помогите мне исправить это.


person Zen Zac    schedule 16.01.2021    source источник
comment
Я собираюсь спуститься в ту же кроличью нору, у вас есть репо, которое я могу раскошелиться?   -  person Bill    schedule 25.01.2021
comment
@Bill gitlab.com/Zzac/nfc-ntag424-authenticator вы можете найти мое решение здесь   -  person Zen Zac    schedule 26.01.2021


Ответы (1)


Я нашел ответ: библиотека Crypto в javascript имеет шифр aes-cbc, который говорит (и действительно) принимает буферы и массивы. Но результаты у обоих разные.

Когда я использовал UInt8Array, я получил правильный результат. Я полностью переписал алгоритм aes-cmac, просто чтобы понять, что мне нужно.

person Zen Zac    schedule 26.01.2021