开发者

Encrypting 30 bit Number into 6 Character Alphanumeric String

I'm looking for an approach to encrypt/obfuscate a 30 bit number.

The results will be grouped into sets of 3 and visible to users as a 6 character alphanumeric encoded with a base32 alphabet, but the user should not be able to pick up a pattern in the alphnumeric strings. For example, the users could see 3 strings: ASDFGH, LKJHGF, ZXCVBN and those might map to the numbers 1073741821, 1073741822, 1073741823. But, it is a pattern they should not be able to easily figure out.

I've looked at a few encryption algorithms, like DES. Here is a bad and naive attempt:

import struct
from Crypto.Cipher import DES
from .baseconv import base32_urlsafe

_KEY = '\x81\x98\xe1\x14<\xb3\xe8\x10'
_encryptor = DES.new(_KEY)

def encrypt_number(number):
    encrypted_i64 = struct.unpack(
        '!Q', _encryptor.encrypt(struct.pack('!Q', number))
    )[0]
    encrypted_i30 = encrypted_i64 >> 34
    return base32_urlsafe.encode(encrypted_i30)

But obviously I won't be able to decrypt the开发者_StackOverflow中文版 string if ever needed and uniqueness is lost with this approach. Also looked at using XOR, but that is too predictable, since more often then not the numbers will be in a consecutive sequence.

I've never had to encode something like this. So, I'm looking for some encryption algorithms/approaches to research and consider. I'm using python, but ideas or examples using other languages are welcome.


Format preserving encryption might be helpful here.

For example, the cycle-walking method described in the paper "Ciphers with Arbitrary Finite Domains" by Black and Rogaway seems like a potential solution. E.g. use a 32-bit cipher (Skip32 by Greg Rose is an example). Encrypt your 30-bit input with the cipher. If the result is a 30-bit integer (i.e. the leading 2 bits are 0) then your are done, otherwise keep encrypting with the cipher until you get a 30-bit result. Decryption is done accordingly.

If you don't need a very secure solution then the Hasty Pudding cipher might be a alternative. It can encrypt inputs of arbitrary size. It was submitted to the AES competition, however did not make it very far and hence is not well analyzed. Still I would expect it to be far more appropriate than any ad hoc solutions proposed here on stackoverflow.


One approach would be to have a table with 1B (2^30) unique random numbers - and use your 30 bit number as an index into that table.

If that table is too large, you could make a smaller one - with say 32768 entries and index the bottom half and the upper half separately.

To avoid the upper half not changing for consecutive values, add the encrypted value of the bottom half to the upper half before looking it up in the table.

encryption

t = table of 32768 random values    
upper15 = input_value >> 15    
lower15 = input_value & 0x7FFF    
lowercoded = t[lower15]    
uppercoded = t[ ( lowercoded + upper15 ) % 32768 ]    
result = uppercoded << 15 + lowercoded

decryption

upper15 = input_value >> 15    
lower15 = input_value & 0x7FFF    
lowereddecoded = t.index(lower15)    
tmp = t.index(upper15)    
tmp -= lower15    
if tmp< 0:   tmp += 32768    
upperdecoded = tmp    
result = upperdecoded << 15 + lowerdecoded


Just roll your own 30-bit block cipher using the Luby-Rackoff construction.

Use any hash function you want for the "F" boxes (e.g., the low 15 bits from a murmurhash of your data plus a secret key) and run as many rounds as you like, and the result will be an invertible pseudo-random permutation on 30 bit numbers.

Sure, it won't be "cryptographically strong", but nothing could be with 30 bits.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜