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 // ENCRYPTION: /* 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) .base64
Then the code is generated:
- Public Fields first
- 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.