[PYTHON] Positive number encryption

Positive number encryption

Encrypts positive numbers starting from 0. If you specify numbers that are incremented obediently as 1, 2, 3 for user ID etc., it will be easy to do brute force hacking. The motivation for this case is to generate an ID. An execution example is shown below.


0 -> 052C5C223627156D7
1 -> 1572257C261D2C376
2 -> 252C1C627627952D3
3 -> 352CEC223627156D7
4 -> 452C1C627627452D3
5 -> 552C1C627627F52D3
6 -> 6512253C662D2C772
7 -> 75D2257C261D2C376
8 -> 8512253C663D2C772
9 -> 953D25C726726C1C2
10 -> A53D258726726C1C2

As mentioned above, the numbers that are just incremented from 0 to 10 are converted to the encrypted ID like that. Below, it is assumed that a 16-digit ID is created with a hexadecimal character string.

Swap digits using prime numbers

Convert the number you want to encrypt to a hexadecimal character string, and exchange the digits using the remainder of the index of the character string divided by the prime number as the corresponding digit.

n = 9999
PrimeTable = [61, 31, 53, 29, 37, 5, 23, 47, 7, 59, 43, 3, 17, 13, 19, 41, 11]
mod = n % 16 # mod = 15
mod = int(enc[0], 16)
prime = PrimeTable[mod] # prime = 41
for i in range(16):
    dig = (i * prime) % 16
#Corresponding digit=> 0, 9, 2, 11, 4 ,13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7

Normally, the lower position starts from the right and the large position starts on the left, but shuffling the corresponding digits avoids easy increments.

important point

As a caveat, you may not select the same prime number as the number of digits. If you want to use a 17-digit ID and try to shuffle the number of digits using 17, all will be the 0th digit.

>dig = (i * prime) % 16
↓
>dig = (i * 17) % 17
Whatever the value of i, dig can only be 0

Replacing a hexadecimal string with a random number table

Even if you shuffle the digits, if the number of each digit starts from 0 and ends with F, you can estimate the ID to some extent, so replace 0 to F with the result of the corresponding table. Create a table like the one below and make it correspond to each digit. I thought it would be possible to automate things such as dynamically generating a table, but I couldn't think of any further processing, so I implemented it by embedding the table.


digitsTable = [
    [5, 3, 15, 14, 11, 7, 6, 2, 12, 8, 10, 13, 4, 1, 9, 0],
    [6, 5, 13, 7, 15, 11, 14, 12, 0, 8, 2, 9, 3, 4, 1, 10],
    [7, 0, 11, 15, 2, 13, 12, 6, 4, 10, 9, 5, 1, 3, 14, 8],
    [3, 6, 13, 7, 5, 10, 14, 0, 1, 9, 15, 4, 11, 8, 2, 12],
    [12, 10, 2, 3, 4, 5, 6, 15, 7, 11, 13, 0, 14, 9, 1, 8],
    [2, 10, 13, 14, 0, 1, 12, 6, 3, 15, 11, 5, 9, 7, 8, 4],
    [13, 8, 9, 14, 0, 15, 1, 3, 2, 11, 5, 12, 7, 4, 10, 6],
    [1, 10, 15, 7, 14, 6, 12, 11, 2, 8, 4, 5, 13, 0, 9, 3],
    [6, 4, 7, 1, 12, 8, 10, 0, 15, 14, 9, 13, 5, 11, 3, 2],
    [2, 14, 13, 15, 6, 11, 10, 7, 3, 8, 1, 4, 5, 0, 9, 12],
    [12, 4, 2, 5, 10, 3, 0, 11, 8, 14, 13, 1, 7, 6, 15, 9],
    [7, 1, 14, 5, 0, 2, 9, 12, 8, 6, 4, 3, 11, 10, 15, 13],
    [5, 8, 4, 2, 11, 10, 7, 14, 3, 0, 12, 6, 9, 13, 1, 15],
    [2, 4, 14, 13, 15, 10, 7, 6, 9, 11, 1, 0, 12, 3, 8, 5],
    [2, 14, 9, 11, 5, 3, 6, 1, 12, 13, 8, 4, 15, 7, 0, 10],
    [5, 7, 9, 14, 4, 15, 2, 13, 3, 12, 8, 1, 10, 6, 11, 0],
]

Experimental source code


digitsTable = [
    [5, 3, 15, 14, 11, 7, 6, 2, 12, 8, 10, 13, 4, 1, 9, 0],
    [6, 5, 13, 7, 15, 11, 14, 12, 0, 8, 2, 9, 3, 4, 1, 10],
    [7, 0, 11, 15, 2, 13, 12, 6, 4, 10, 9, 5, 1, 3, 14, 8],
    [3, 6, 13, 7, 5, 10, 14, 0, 1, 9, 15, 4, 11, 8, 2, 12],
    [12, 10, 2, 3, 4, 5, 6, 15, 7, 11, 13, 0, 14, 9, 1, 8],
    [2, 10, 13, 14, 0, 1, 12, 6, 3, 15, 11, 5, 9, 7, 8, 4],
    [13, 8, 9, 14, 0, 15, 1, 3, 2, 11, 5, 12, 7, 4, 10, 6],
    [1, 10, 15, 7, 14, 6, 12, 11, 2, 8, 4, 5, 13, 0, 9, 3],
    [6, 4, 7, 1, 12, 8, 10, 0, 15, 14, 9, 13, 5, 11, 3, 2],
    [2, 14, 13, 15, 6, 11, 10, 7, 3, 8, 1, 4, 5, 0, 9, 12],
    [12, 4, 2, 5, 10, 3, 0, 11, 8, 14, 13, 1, 7, 6, 15, 9],
    [7, 1, 14, 5, 0, 2, 9, 12, 8, 6, 4, 3, 11, 10, 15, 13],
    [5, 8, 4, 2, 11, 10, 7, 14, 3, 0, 12, 6, 9, 13, 1, 15],
    [2, 4, 14, 13, 15, 10, 7, 6, 9, 11, 1, 0, 12, 3, 8, 5],
    [2, 14, 9, 11, 5, 3, 6, 1, 12, 13, 8, 4, 15, 7, 0, 10],
    [5, 7, 9, 14, 4, 15, 2, 13, 3, 12, 8, 1, 10, 6, 11, 0],
]

#Create a reverse lookup table for decryption
digitsReverseTable = []
for tbl in digitsTable:
    a = [0] * 16
    for i, v in enumerate(tbl):
        a[v] = i
    digitsReverseTable.append(a)

PrimeTable = [61, 31, 53, 29, 37, 5, 23, 47, 7, 59, 43, 3, 17, 13, 19, 41, 11]
def encodeNumber(n):
    hexStr = "00000000000000000000" + "{:X}".format(n)
    hexStr = hexStr[-16:]
    mod = n % 16
    prime = PrimeTable[mod]
    enc = [""] * 16
    for i in range(16):
        c = hexStr[i]
        dig = (i * prime) % 16
        idx = int(c, 16)
        m = digitsTable[i][idx]
        enc[dig] = "{:X}".format(m)
    #Leave the mod in the ID for decryption
    return "{:X}".format(mod) + "".join(enc)

def decodeNumber(enc):
    mod = int(enc[0], 16)
    prime = PrimeTable[mod]
    enc = enc[1:]
    numArr = [0] * 16
    for i in range(16):
        dig = (i * prime) % 16
        ridx = int(enc[dig], 16)
        m = digitsReverseTable[i][ridx]
        numArr[i] = m
    numArr = list(reversed(numArr))
    n = 0
    for i in range(16):
        n += numArr[i] * 16 ** i
    return n

def main():
    for i in range(0, 100):
        enc = encodeNumber(i)
        print(i, enc, decodeNumber(enc))

if __name__ == "__main__":
    main()
# python encode_counter.py

Execution result

0 052C5C223627156D7 0
1 1572257C261D2C376 1
2 252C1C627627952D3 2
3 352CEC223627156D7 3
4 452C1C627627452D3 4
5 552C1C627627F52D3 5
6 6512253C662D2C772 6
7 75D2257C261D2C376 7
8 8512253C663D2C772 8
9 953D25C726726C1C2 9
10 A53D258726726C1C2 10
11 B57D651726322C1C2 11
12 C5673C2D162C7522A 12
13 D52C6C223627156D7 13

Omitted on the way

89 953D25C726736C1C2 89
90 A53D258726736C1C2 90
91 B57D651726332C1C2 91
92 C5673C2D162C7523A 92
93 D52C6C233627156D7 93
94 E57D651726332CBC2 94
95 F5277C2D066C35231 95
96 052C5C263627156D7 96
97 1576257C261D2C376 97
98 252C1C667627952D3 98
99 352CEC263627156D7 99

About actual use

I think that it is better to randomly insert a dummy character string every 2 to 4 characters rather than using it as it is, but of course, avoid using the sample source described as it is.

Easier and easier way

By issuing an ID in advance, you can avoid using complicated logic like this case. If you can assume the upper limit such as "10,000 is enough" in the system you are trying to create, when you create and use a table linked to 0 to 9999 by issuing 10,000 IDs in advance with a random character string Use that corresponding table. As a caveat, don't forget to perform a check to ensure that your ID is unique.

Already likely

This kind of processing seems to be in high demand, so I made it while thinking that it seems to be in the existing library, but I did not know what to say this concept and I could not think of a search word, so I made it myself, comment if there is a library that does the same thing Please tell me. that's all.

Recommended Posts

Positive number encryption
Prime number
Base number