1

For the communication with a ACR1255U-J1 NFC Reader an authentication is needed. Connection is via bluetooth by using Hex-Strings.

These are my two methods for encryption and decryption:

encrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value =  CryptoJS.enc.Hex.parse(valueStringHex);
    const key  = CryptoJS.enc.Hex.parse(keyStringHex);
    const encryptedStringHex = CryptoJS.AES.encrypt(value, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.ZeroPadding}).ciphertext.toString();
    return encryptedStringHex;
    }

decrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value = CryptoJS.enc.Hex.parse(valueStringHex);
    const key = CryptoJS.enc.Hex.parse(keyStringHex);
    const decryptedStringHex = CryptoJS.AES.decrypt({ciphertext: value}, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding});
    return decryptedStringHex.toString();
    }

With the reader comes a demo app from which I recorded the bluetooth traffic during the authentication. I checked this with Wireshark. Based on the communication seen in Wireshark I tried to proof my coding of the authentication process in my app.

ACR1255 documentation says:
In Step 1: I receive from the ACR reader a sequence of 16-byte random numbers encrypted using the Customer Master Key. I should decrypt it using the correct Customer Master Key (41435231323535552d4a312041757468).

According to Wireshark this is what I received from the ACR1255 reader (key part in bold) in the first step: 83001500000021E1000045005ff58680541c5a5903f4833dfaa428bf1c0a

decrypt('5ff58680541c5a5903f4833dfaa428bf', '41435231323535552d4a312041757468')
=> Result is 6064a82b7edf62986b0a2ec79e922aad

In Step 2: According to the documentation I have to sent the following.
abAuthData[0:15] – 16 bytes of random number generated by me
abAuthData[16:31] – 16 bytes of decrypted random number received from ACR1255U-J1 (which would be the result from first step 6064a82b7edf62986b0a2ec79e922aad, I guess)
The overall 32-byte random numbers will be decrypted using the Customer Master Key and returned to ACR1255U-J1 reader.

According to Wireshark this is what the demo app now sends to the ACR1255 reader (key part in bold):
6B0025000000EAE0000046007088e66af57bf04e66a8b2e83614f288 c8ed5005b914b51e50285a93408e14922c0a

Of course, this is the already decrypted key. To proof my understanding of the workflow, I encrypted it and expected to see the result of step 1 as the second part of the key. But it is not.

encrypt('7088e66af57bf04e66a8b2e83614f288c8ed5005b914b51e50285a93408e1492', '41435231323535552d4a312041757468')
=> Result is 493aa0c5476f551d3b2bce664cfe4305*3b61bce6e4c0837be30453ddad165180*

What do I misunderstand in the workflow described in the documentation? Is one able to describe it differently to the documentation?

Documentation can also be found here. Page 32 to 35.

Ps. I know, the documentation says AES CBC mode. But a IV is not used and as far as I know the usage of ECB mode is than the same.

somanyquestions
  • 81
  • 1
  • 1
  • 8
  • 2
    The equivalence of CBC with `0`-IV and ECB applies only to the _first_ block (16 bytes for AES) of the ciphertext. The plaintext used in the second step has a length of 2 blocks (32 bytes for AES) and generates a 2-block ciphertext (assuming no padding). In this case CBC with `0`-IV must therefore **not** be replaced by ECB, because the second block would be encrypted differently. By the way, `NoPadding` and not `ZeroPadding` should probably be used in `encrypt`, shouldn't it (although this has no effect on plaintexts whose length is an integer multiple of the blocksize)? – Topaco May 17 '20 at 15:19
  • @Topaco Depends, some zero based padding implementations (such as Java's Bouncy Castle) do *always* pad, just like PKCS#5/7. I would not expect that to be the general default though, most would only pad when necessary (also because of the generic use case of encrypting text, which for C environments is already zero padded itself). Doesn't seem the case here though, but it is something to keep an eye on. – Maarten Bodewes May 17 '20 at 16:50
  • 1
    @MaartenBodewes - Well, that's right, there are different Zero padding variants and some care must be taken. In my comment (`CryptoJS.pad.`) `ZeroPadding` denotes the CryptoJS implementation which does _not_ pad if the length of the plaintext is already an integer multiple of the blocksize. – Topaco May 17 '20 at 22:04

1 Answers1

0

For the sake of completeness I would like to add the solution.
According to @Topaco's comment I was wrong with the ECB mode. I changed it to CBC and added the 0-IV and it is now working.

decrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value = CryptoJS.enc.Hex.parse(valueStringHex);
    const key = CryptoJS.enc.Hex.parse(keyStringHex);
    const ivvar   = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
    const decryptedStringHex = CryptoJS.AES.decrypt({ciphertext: value}, key, {iv: ivvar, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.NoPadding});
    return decryptedStringHex.toString();
    }

// in Step 1: 
// decrypt('5ff58680541c5a5903f4833dfaa428bf', '41435231323535552d4a312041757468')
// returns 6064a82b7edf62986b0a2ec79e922aad
encrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value =  CryptoJS.enc.Hex.parse(valueStringHex);
    const key  = CryptoJS.enc.Hex.parse(keyStringHex);
    const ivvar   = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
    const encryptedStringHex = CryptoJS.AES.encrypt(value, key, {iv: ivvar, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.NoPadding}).ciphertext.toString();
    return encryptedStringHex;
    }

// in Step 2:
// encrypt('7088e66af57bf04e66a8b2e83614f288c8ed5005b914b51e50285a93408e1492', '41435231323535552d4a312041757468')
// this is the decrypted string sent to the reader, which has to be encrypted here to proof that the key contains the result of step 1 in second 16 Byte block
// returns => 493aa0c5476f551d3b2bce664cfe43056064a82b7edf62986b0a2ec79e922aad (which is the return of Step 1 (in the second half))
somanyquestions
  • 81
  • 1
  • 1
  • 8