I use AES256 for various purposes in my app. However, the purpose I am now trying to achieve is the following:

Input is for example AU00000001 and I would like a hashed or encrypted output of this with the same length (10 characters). I need to keep the output as small as possible, to convert it into a simple (minimal dots) QR code. And I do need the ability to reverse that output back to the original input.

I've read a few posts around here but I can’t find what I am looking for. Can you give me a hint or maybe point me to some references?


See “format-preserving encryption” at WikiPedia.

Depending on the size of the message space, one can get such a scheme by:

Nota bene: we also have a tag that points to related questions and answers.


Simplest is to use a stream cipher. You will not get authentication, but that would be impossible with format preserving encryption anyway.

Does the encrypted string need have the same character set (e.g. hex or base 64)?

In that case:

  1. Transform to binary.
  2. Encrypt with stream cipher.
  3. Transform back.

AES CTR would work, as would any other stream cipher. You need a single-use key per encrypted input or else a unique IV/nonce for every plaintext that you can transmit some other way since you can't include it with the ciphertext.


I think OP doesn't know much about crypto we can't just say use this use that without proper explanation.

I'm not certain but I think I understand what OP really mean.
While OP doesn't know what he should asked; others also answer as everything the question imply.

OP said 10 characters not 10 bytes that why Mr.Demer came up with format-preserving encryption. I believe OP actually mean 10 bytes since he attempt to use AES by himself at first and QR code is capable of storing binary information.

Basically OP just try to encrypt 10 bytes data into 10 bytes data.
otus understand this point so he suggest OP to use stream cipher but that's not a good explanation because OP still doesn't know what wrong with his current approach.

To answer your (OP's) question. You should understand that AES is something we called block cipher which operate on block of data. In AES case it took 16 bytes plaintext block as input and output 16 bytes ciphertext block.

AES can't operate on input less than 16 bytes. The input less than 16 bytes will be padded before begin AES operation. Fortunately block cipher can also be used to generate keystream to use as stream cipher. Thus you can use AES to encrypt your data and output 10 bytes data just by picking the right mode of operation. (Or more obvious choice: use stream cipher)

Your implementation may has other pitfalls that you don't aware of. For example in mode of operation I mentioned or other generic stream ciphers. If you encrypt it without MAC I can change what you encrypted without knowing your key?
For example I can change encrypted AU00000001 to AU11100001 just by flipping correct location of bit.

I suggest before continue your app development you should play around with crypto a little more or find someone else that did. For this particular case if the values you encrypted "AU00000001" is unique I think pad it to 16 bytes and encrypt it using AES in ECB mode should be adequate security with minimal size overhead. No MAC needed since you can validate the correctness with regular expression
eg. ^[A-Za-z]{2}[0-9]{8}$ and I can't arbitrary independently flip any bit at my will.


Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.