How to encrypt numeric data on a ticket I have a customer with an existing ticketing system that generates tickets for events like theaters, movies, football and so on.

The information in each ticket is encoded in a 16 decimal digit numeric string. The information contains fixed positions for event date, event identifier, seat row, seat number and so on.
This system has a numeric barcode on each ticket with room for 20 decimal digits. (https://en.wikipedia.org/wiki/Interleaved_2_of_5)

The main problem is that it is too easy for adversaries to generate false tickets with valid barcodes.

My customer now wants to encrypt the information in the barcode to make it more difficult to generate false tickets.

The requirements are as follows:


The plaintext is a 16 decimal digit (0-9) string.
The ciphertext is a 20 decimal digit (0-9) string.
Consecutive ticket numbers might differ only in a single digit position in the cleartext, the ciphertext for consecutive tickets must still be completely different.
It should be impossible to calculate the encryption key even if you have access to many valid tickets.
The encryption key is the same for all tickets for a certain event.
It must be difficult for an adversary to generate a valid ticket number, especially for a specific event.
Barcode readers used for validating tickets should work completely offline - it is not possible to have a complete database of valid ticket numbers available to the barcode readers.
Note that the 20-digit encrypted barcode after decryption must contain the full 16-digit plaintext. This means that we only have room for a 4-digit hash.


What kind of encryption and authentication should we use in this case? As I see it, the main problem is that the space in the barcode is very limited, so we can not use a real HMAC.

Any suggestions?
Given that we can add only 4 digits (13.3 bits) of redundancy, there is no way to use asymmetric cryptography. We'll have to use a secret key in the verification terminals.

This is an application for Format Preserving Encryption. It can act like a block cipher, except we can decide the block width, and deal with decimal rather than binary or hexadecimal digits. Methods for FPE are given in NIST&nbsp;SP&nbsp;800-38G. The previous link leads to references with other methods.

Take the 16-digit plaintext, append four zeroes, yielding 20 digits. Encipher that using FPE, yielding 20 digits, put that on the ticket.

On reading a ticket, check that it is 20 digits, decipher per FPE (yielding 20 digits), and consider the result valid when it ends with four zeroes; remove these.