# Generate a list of valid ASCII codes

I have read many pages about encryption but I am really stuck on this. For access control to a building I want to print a 10 character ASCII code on a ticket (as a barcode).

The barcode reader (controlled by an Arduino or mini PC) is not connected to the PC which creates and prints the barcodes.

When both server and client have the same keys, is it possible to validate the codes?

EDIT: My first attempt was to convert the current date in to binary, and then to ASCII with base64. The problem was that I ended up with a too big code (11 characters).

Considerating everything I came to the conclusion that it would be better too convert the date and time directly into ASCII characters. ASCII characters become readable at position 33, so year 2015 becomes 15 + 33 = ASCII character 0

In this way Year + Month + Day + Hour + Second + Validtime only takes 7 characters.

EDIT2: I tried different encryptions en base encodings. Because year and month don't vary much, the generated code before encryption looks very much alike. When I use ARC4 encryption, the generated codes are also very similar.

Using DES3 the generated codes are not alike. I have included the two encryption methods in the code below. Because I use Python 2.7 I have to use the base85 module from the mom package. In Python v3 base85 is included.

Here is the code:

from datetime import datetime
from Crypto.Cipher import DES3
from Crypto.Cipher import ARC4
import base64
from mom.codec import base85

sleutel="Dsdfk3#$294ddkwlsslwEefm" now = datetime.now() year = chr((now.year - 2000)+33) month = chr((now.month)+33) day = chr((now.day)+33) hour = chr((now.hour)+33) minute = chr((now.minute)+33) seconds = chr((now.second)+33) #validtime from 0 till 9 in this case just a random 4. So 0 would be a few hours and 5 a week etc. validtime = chr(4+33) key = ''.join([year,month,day,hour,minute,seconds,validtime]) print key obj1 = ARC4.new(sleutel) obj2 = DES3.new(sleutel) cipher_text = obj1.encrypt(key) cipher_text1 = obj2.encrypt(key+ 'a') print "Base64 ARC4 encrypted:", base64.b64encode(cipher_text) print "Base64 DES3 encrypted:", base64.b64encode(cipher_text1) print "Base85 ARC4 encrypted:", base85.b85encode(cipher_text) print "Base85 DES3 encrypted:", base85.b85encode(cipher_text1) Because I added seconds, every code is unique (as long as it is impossible to print two tickets in one second) • You want a message authentication code (MAC). May 13, 2015 at 9:42 • Thank you! Knowing the correct term is already a great help. May 13, 2015 at 9:49 • @yyyyyyy When I read about MAC (or HMAC) it is all about a message and a signature. So when I have a 10 digit code I have 5 digits for the message and 5 digits for the signature? May 13, 2015 at 11:32 • You can control that yourself. A MAC output is usually the full block size (in case of a cipher based MAC) or hash output. You can use the x leftmost bits from that output. Anything less that 64 bits is a risk though. In case of access control systems you can however mitigate by only allowing a certain number of tries (and then take some well thought out counter measures). PS there's a quite a difference between printable ASCII characters and digits, i.e. 0..9. Five digits amounts to about$5 \times 10 / 3 = ~17\$ bits of authentication data - that's not much. May 13, 2015 at 12:25
• For barcode 128B there seem to be 95 characters in the set. That translates to 65 full bits you can store if you have 10 characters. So you can store the barcodes for 2 employees without worrying about security of the scheme :P May 14, 2015 at 13:31

## 1 Answer

If you really can use all 95 printable ASCII characters, you're better off encoding everything in binary (however you want) into 64 bits, then encrypting that with your secret key (using a cipher with a 64-bit block size, such as 3DES), then turn the result of that into 10 characters using an encoding from binary into base-95. You can actually encode 64 bits into 10 characters using only 85 characters, so you could omit some that might be a problem (e.g. SPACE). Since you're encrypting only one block, and they're guaranteed to be unique, you can simply use it in ECB mode (no IV, no chaining modes).

Then just turn it into a 10 digit base-85 number (the same way you'd convert binary to base 10), then map each of the 85 possible values for a digit (0-84) into an ASCII character (either with a lookup table or something as simple as adding 0x21).

You'll want to make the data as well-structured as you can so that you can detect any tampering, including perhaps a (small) checksum of some sort, and verify all 64 bits as being valid/well-formed.

• I think I found the right way for me, using base85 and DES3 encryption. Thank you for the hints. My method is mayby not as secure as yours, but for our application I think it is ok. May 16, 2015 at 13:33
• Well, if you encode the date/time as ASCII as in your latest proposal, that will add quite a bit of structure/redundancy to the message, so simply verifying that all of those digits are valid will make it relatively secure (under the conditions given, especially the value of what is being protected and the low frequency (and the consequences) of any attempt). May 16, 2015 at 22:18