给定一个密钥作为种子,如何洗牌然后取消洗牌字节数组
How shuffle and then unshuffle a bytearray, given a key as seed
我正在尝试创建一个加密系统,为此我将采用字节数组,我打算使用
random.Random(seed).shuffle(bytearray)
加密信息的函数。
我在逆转解密过程时遇到了问题,我尝试了类似的方法(没有成功):
random.Random(1/seed).shuffle(encryptedbytearray)
有办法吗?
打乱排序的范围,以便我们可以将打乱的索引与未打乱的索引相匹配。
x = list(range(len(s)))
random.Random(seed).shuffle(x)
对于 12345 的种子,这会产生 [14, 15, 12, 3, 24, 16, 7, 22, 10, 2, 19, 4, 20, 17, 1, 21, 5, 25, 18, 8, 6, 11, 9, 0, 23, 13]
。这表明打乱后列表中第 0 个索引中的值实际上在未打乱列表中的第 14 个索引中,第 1 个索引实际上是第 15 个未打乱等
然后将每个打乱后的索引与打乱后的值进行匹配,然后(根据索引)排序回到它们未打乱的位置。
unshuffled = bytearray(c for i, c in sorted(zip(x, s)))
print(unshuffled)
完整示例:
import random
# setup
s = bytearray(b"abcdefghijklmnopqrstuvxwyz")
seed = 12345
random.Random(seed).shuffle(s)
# shuffle a sorted range, so that we can match the shuffled indicies to the unshuffled indicies
x = list(range(len(s)))
random.Random(seed).shuffle(x)
# match each shuffled index to the shuffled value, and then sort (based on the index) back into their unshuffled positions
unshuffled = bytearray(c for i, c in sorted(zip(x, s)))
print(unshuffled)
上面详述的过程应该适用于任何打乱顺序的序列(例如列表),而不仅仅是字节数组。
这里 a more detailed explanation of this process on crypto.se 涉及更多数学。
您需要使用相同的种子来打乱索引,以便您可以回溯原始位置。 (枚举将允许您避免对该映射进行排序)
import random
def encrypt(decrypted,seed=4):
encrypted = decrypted.copy()
random.Random(seed).shuffle(encrypted)
return encrypted
def decrypt(encrypted,seed=4):
decrypted = encrypted.copy()
indexes = list(range(len(encrypted)))
random.Random(seed).shuffle(indexes)
for e,d in enumerate(indexes):
decrypted[d] = encrypted[e]
return decrypted
示例运行(使用字符列表,但它适用于字节数组或任何其他类型的列表):
clearText = list('ABCDE')
encryptedText = encrypt(clearText)
print(encryptedText)
['D', 'E', 'A', 'C', 'B']
decryptedText = decrypt(encryptedText)
print(decryptedText)
['A', 'B', 'C', 'D', 'E']
如果您希望函数直接在数组上“就地”工作(而不是返回值),您可以这样写:
def encrypt(decrypted,seed=4):
random.Random(seed).shuffle(encrypted)
def decrypt(encrypted,seed=4):
before = encrypted.copy()
indexes = list(range(len(encrypted)))
random.Random(seed).shuffle(indexes)
for e,d in enumerate(indexes):
encrypted[d] = before[e]
我正在尝试创建一个加密系统,为此我将采用字节数组,我打算使用
random.Random(seed).shuffle(bytearray)
加密信息的函数。
我在逆转解密过程时遇到了问题,我尝试了类似的方法(没有成功):
random.Random(1/seed).shuffle(encryptedbytearray)
有办法吗?
打乱排序的范围,以便我们可以将打乱的索引与未打乱的索引相匹配。
x = list(range(len(s)))
random.Random(seed).shuffle(x)
对于 12345 的种子,这会产生 [14, 15, 12, 3, 24, 16, 7, 22, 10, 2, 19, 4, 20, 17, 1, 21, 5, 25, 18, 8, 6, 11, 9, 0, 23, 13]
。这表明打乱后列表中第 0 个索引中的值实际上在未打乱列表中的第 14 个索引中,第 1 个索引实际上是第 15 个未打乱等
然后将每个打乱后的索引与打乱后的值进行匹配,然后(根据索引)排序回到它们未打乱的位置。
unshuffled = bytearray(c for i, c in sorted(zip(x, s)))
print(unshuffled)
完整示例:
import random
# setup
s = bytearray(b"abcdefghijklmnopqrstuvxwyz")
seed = 12345
random.Random(seed).shuffle(s)
# shuffle a sorted range, so that we can match the shuffled indicies to the unshuffled indicies
x = list(range(len(s)))
random.Random(seed).shuffle(x)
# match each shuffled index to the shuffled value, and then sort (based on the index) back into their unshuffled positions
unshuffled = bytearray(c for i, c in sorted(zip(x, s)))
print(unshuffled)
上面详述的过程应该适用于任何打乱顺序的序列(例如列表),而不仅仅是字节数组。
这里 a more detailed explanation of this process on crypto.se 涉及更多数学。
您需要使用相同的种子来打乱索引,以便您可以回溯原始位置。 (枚举将允许您避免对该映射进行排序)
import random
def encrypt(decrypted,seed=4):
encrypted = decrypted.copy()
random.Random(seed).shuffle(encrypted)
return encrypted
def decrypt(encrypted,seed=4):
decrypted = encrypted.copy()
indexes = list(range(len(encrypted)))
random.Random(seed).shuffle(indexes)
for e,d in enumerate(indexes):
decrypted[d] = encrypted[e]
return decrypted
示例运行(使用字符列表,但它适用于字节数组或任何其他类型的列表):
clearText = list('ABCDE')
encryptedText = encrypt(clearText)
print(encryptedText)
['D', 'E', 'A', 'C', 'B']
decryptedText = decrypt(encryptedText)
print(decryptedText)
['A', 'B', 'C', 'D', 'E']
如果您希望函数直接在数组上“就地”工作(而不是返回值),您可以这样写:
def encrypt(decrypted,seed=4):
random.Random(seed).shuffle(encrypted)
def decrypt(encrypted,seed=4):
before = encrypted.copy()
indexes = list(range(len(encrypted)))
random.Random(seed).shuffle(indexes)
for e,d in enumerate(indexes):
encrypted[d] = before[e]