Austria passed a law recently which requires all invoices for cash-transactions to carry a QR-Code, that is signed by a government-registered certificate-authority.

Each code contains public information (the invoice data) and links the invoice to the previously issued invoice to prevent a company from tampering with their accounting.

For the chaining to work each code contains the cash-register balance after the invoice was issued. For privacy-reasons that counter is encrypted and only readable by the shop or the department of finance.

I'm a software-engineer and implemented this using provided instructions and unit-tests. For that reason, I'm posting Kotlin/Java-Code now, instead of pseudo-code so that I don't accidentally omit information.

val cashRegisterId: String = "TEST-REGISTER"      // public information
val receiptIdentifier: String = "Invoice No. ABC" // public information, no incrementing values or structure
val invoiceTotal:Int = 2323                       // public information

val currentBalance: Int = ..                        // private 
val secretKey: SecretKey = ...                      // private AES-256 

val COUNTER_BYTELENGTH = 8     // public, can be parameterized later version of the code


/* hash cashRegisterId and receiptIdentifier and take first 16 bytes */
val mdSha256 = MessageDigest.getInstance("SHA-256")
val IV = mdSha256.digest("$cashRegisterId$receiptIdentifier").copyOfRange(0, 16)

/* calculate newBalance and put it in 16 byte buffer
val balanceByteArray = ByteBuffer.allocate(16)
    .putLong(currentBalance + invoiceTotal)

/* init crypto */
val cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC")
     .init(1, secretKey, IvParameterSpec(IV))

/* encrypt the counter, take 8 bytes from it and BASE64 it */
val encrypted = cipher.doFinal(balanceByteArray)
    .copyOfRange(0, COUNTER_BYTELENGTH)

Then the code is generated:

  • Public Fields first
  • EncryptedCounter
  • Chainvalue: if first invoice then first 8 bytes of cashregister-ID, in subsequent invoices first 8 bytes of signature of entire code of previous invoice.

This code is signed by the authority as stated above and printed on the Invoice.

My question is whether if there are chances of finding the AES256 key and decrypt the balance counter, using the information in the code:

  • The counter tends to increase (credit will be negative)
  • Using multiple invoices, it should be possible to know by how much it has increased
  • The IV is built using the publicly available register-ID and receipt-identifier

Any other thoughts on attacking this scheme?

Disclaimer: I don't know much about cryptography and I don't plan on using this to commit tax-crimes, I'm merely an interested engineer.

  • 1
    $\begingroup$ it is one of the required encryption properties that even you would know the plaintext (counter) and cipher (encrypted value) the key itself must be irrecoverable assuming the IV is unique. imho the best attack option would be some side channel ( timing, power,..) so until you use mature libraries you could be safe (not considering blackmailing or extortion to get the key) $\endgroup$ – gusto2 Sep 14 '17 at 20:48
  • $\begingroup$ What happens when a receipt is cancelled ? Can the same "$cashRegisterId$receiptIdentifier" be re-used is such a case ? If so then the encryption could be broken without knowing the secret key. Another issue I can spot with the code, is the lack of a MAC (message authentication code). After the cleartext is encrypted, you should use something like SHA512-256 to protect the integrity of your resulting ciphertext and include it in the generated code, so that the other party can verify its integrity. Even better would be to use an encryption mode which supports AEAD. $\endgroup$ – Silenteh Sep 19 '17 at 19:22
  • $\begingroup$ A cancellation is simply another receipt with a negative amount that get's a new identifier. $\endgroup$ – Fabian Zeindl Oct 7 '17 at 7:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.