在我的最后一个问题中,在@Reinderien的回答中,他添加了这一行from typing import List,以及类似于这个m: List[List[int]]的东西。这只是为了输入提示吗?
使用numpy数组而不是python列表会更快吗?
除了这些后续的问题,如果你看到任何需要改变的地方,现在就让我来。
import base64
import numpy as np
from randomgen import ChaCha
from getpass import getpass
from typing import List
def add_padding(plain_text: str, block_size: int = 128) -> str:
plain_text = plain_text.encode()
padding = -(len(plain_text) + 1) % block_size # Amount of padding needed to fill block
padded_text = plain_text + b'=' * padding + bytes([padding + 1])
return padded_text
def xor_string(key: bytes, secret: bytes) -> bytes:
xored_secret = b''
for i in range(len(secret) // len(key)):
if i > 0:
key = get_round_key(key)
some_decimals = secret[i * len(key):len(key) + (i * len(key))]
xored_secret = xored_secret + b''.join(bytes([key[i] ^ some_decimals[i]]) for i in range(len(key)))
return xored_secret
def get_round_key(key: bytes) -> bytes:
last_col = key[15::16]
# interweave
last_col = b''.join(x for i in range(len(last_col) // 2) for x in (bytes([last_col[-i - 1]]), bytes([last_col[i]])))
new_key = b''
for current_col in [key[i::16] for i in range(16)]:
current_col = xor_string(last_col, current_col)
new_key = new_key + current_col[len(current_col) // 2:] + current_col[:len(current_col) // 2]
return new_key
def generate_key(key: str) -> bytes:
if len(key) >= 128:
key = key.encode()
return key[:128]
elif len(key) < 128:
key = key.encode()
for i in range(128 - len(key)):
key = key + bytes([(sum(key) // len(key)) ^ sum(1 << (8 - 1 - j) for j in range(8) if key[i] >> j & 1)])
decimal = ''.join(str(i) for i in key)
binary = f'{bin(int(decimal[len(decimal) // 2:] + decimal[:len(decimal) // 2]))[2:]:<01024s}'
key = bin_to_bytes(binary[:1024])
half1 = key[:len(key) // 2]
half2 = key[len(key) // 2:]
key = half2 + half1
return key[:128]
def bytes_to_base64(binary: bytes) -> str:
# ints = [int(binary[i * 8:8 + i * 8], 2) for i in range(len(binary) // 8)]
return base64.b64encode(binary).decode()
def bin_to_decimal(binary: str, length: int = 8) -> List[int]:
b = [
binary[i * length:length + (i * length)]
for i in range(len(binary) // length)
]
decimal = [int(i, 2) for i in b]
return decimal
def decimal_to_binary(decimal: List[int], length: int = 8) -> str:
return ''.join(str(bin(num)[2:].zfill(length)) for num in decimal)
def base64_to_bytes(base: str) -> bytes:
return base64.b64decode(base)
def matrix_to_bytes(m: List[List[int]]) -> bytes:
return b''.join(bytes([m[i][j]]) for i in range(16) for j in range(8))
def obfuscate(secret: bytes, key: bytes, encrypting: bool, loops: int) -> bytes:
shuffled_data = b''
round_key = key
for i in range(len(secret) // 128):
if i > 0:
round_key = get_round_key(round_key)
if encrypting:
m = [
list(secret[j * 8 + i * 128:j * 8 + i * 128 + 8])
for j in range(16)
]
m = shuffle(m, round_key, loops)
m = matrix_to_bytes(m)
m = shift_bits(round_key, m)
shuffled_data += xor_string(round_key, m)
else:
xor = xor_string(round_key, secret[i * 128:i * 128 + 128])
xor = unshift_bits(round_key, xor)
m = [list(xor[j * 8:j * 8 + 8]) for j in range(16)]
m = reverse_shuffle(m, round_key, loops)
shuffled_data += matrix_to_bytes(m)
return xor_string(key, shuffled_data)
def shuffle(m: List[List[int]], key: int, loops: int) -> List[List[int]]:
for j in range(loops):
# move columns to the right
m = [row[-1:] + row[:-1] for row in m]
# move rows down
m = m[-1:] + m[:-1]
shuffled_m = [[0] * 8 for _ in range(16)]
for idx, sidx in enumerate(test(key)):
shuffled_m[idx // 8][idx % 8] = m[sidx // 8][sidx % 8]
m = shuffled_m
# cut in half and flip halves
m = m[len(m) // 2:] + m[:len(m) // 2]
# test
# m = list(map(list, zip(*m)))
return m
def reverse_shuffle(m: List[List[str]], key: int, loops: int) -> List[List[str]]:
for j in range(loops):
# test
# m = list(map(list, zip(*m)))
# cut in half and flip halves
m = m[len(m) // 2:] + m[:len(m) // 2]
shuffled_m = [[0] * 8 for _ in range(16)]
for idx, sidx in enumerate(test(key)):
shuffled_m[sidx // 8][sidx % 8] = m[idx // 8][idx % 8]
m = shuffled_m
# move rows up
m = m[1:] + m[:1]
# move columns to the left
m = [row[1:] + row[:1] for row in m]
return m
def shift_bits(key: bytes, secret: bytes) -> bytes:
"""As you can see I have no idea what I'm doing :)"""
shifted = b''
for idx, byte in enumerate(secret):
byte = byte ^ 255
byte = sum(1 << (8 - 1 - j) for j in range(8) if byte >> j & 1)
byte = byte ^ (key[idx] ^ 255)
shifted = shifted + bytes([byte])
return shifted
def unshift_bits(key: bytes, secret: bytes) -> bytes:
shifted = b''
for idx, byte in enumerate(secret):
byte = byte ^ (key[idx] ^ 255)
byte = sum(1 << (8 - 1 - j) for j in range(8) if byte >> j & 1)
byte = byte ^ 255
shifted = shifted + bytes([byte])
return shifted
def test(seed: bytes) -> List[int]:
rg = np.random.Generator(ChaCha(seed=int.from_bytes(seed, byteorder='big'), rounds=8))
lst = np.arange(128)
rg.shuffle(lst)
return lst
def bin_to_bytes(binary: str) -> bytes:
return int(binary, 2).to_bytes(len(binary) // 8, byteorder='big')
def encrypt(password: str, secret: str, loops: int = 1) -> str:
key = generate_key(password)
secret = add_padding(secret)
secret = xor_string(key, secret)
secret = obfuscate(secret, key, True, loops)
secret = bytes_to_base64(secret)
return secret
def decrypt(password: str, base: str, loops: int = 1) -> str:
key = generate_key(password)
binary = base64_to_bytes(base)
binary = xor_string(key, binary)
binary = obfuscate(binary, key, False, loops)
pad = binary[-1]
binary = binary[:-pad]
return binary.decode()
def main():
while True:
com = input('1) Encrypt Text\n' '2) Decrypt Text\n' '3) Exit\n')
input_text = input('Enter the text: ')
# key = getpass('Enter your key: ')
key = input('Enter your key: ') # getpass doesn't work in pycharm, just for testing
if com == '1':
print(f'Encrypted text: {encrypt(key, input_text)}')
elif com == '2':
print(f'Decrypted text: {decrypt(key, input_text)}')
elif com == '3':
break
print()
if __name__ == '__main__':
# from datetime import datetime
#
# start = datetime.now()
# encrypt('password', 'hello this is a test')
# print(datetime.now() - start)
main()发布于 2021-05-06 05:18:59
这只是为了输入提示吗?
正确,键入模块中的所有内容都用于类型提示。在使用mypy之类的东西时,这些内容很有用,但是python解释器将忽略所有这些。
使用numpy数组而不是python列表会更快吗?
理论上,是的,但这取决于数据的大小。numpy实际上是用来处理大型数据集的,而且我认为您使用它的大多数东西都是非常小的,在这里开销会消除任何加速。
除了这些后续的问题,如果你看到任何需要改变的地方,现在就让我来。
def generate_key(key: str) -> bytes:
if len(key) >= 128:
key = key.encode()
return key[:128]
elif len(key) < 128:
key = key.encode()
for i in range(128 - len(key)):
key = key + bytes([(sum(key) // len(key)) ^ sum(1 << (8 - 1 - j) for j in range(8) if key[i] >> j & 1)])
decimal = ''.join(str(i) for i in key)
binary = f'{bin(int(decimal[len(decimal) // 2:] + decimal[:len(decimal) // 2]))[2:]:<01024s}'
key = bin_to_bytes(binary[:1024])
half1 = key[:len(key) // 2]
half2 = key[len(key) // 2:]
key = half2 + half1
return key[:128]这里的elif是没有必要的。只需在这里省略elif语句,就可以删除部分缩进。
def generate_key(key: str) -> bytes:
if len(key) >= 128:
key = key.encode()
return key[:128]
key = key.encode()
for i in range(128 - len(key)):
key = key + bytes([(sum(key) // len(key)) ^ sum(1 << (8 - 1 - j) for j in range(8) if key[i] >> j & 1)])
decimal = ''.join(str(i) for i in key)
binary = f'{bin(int(decimal[len(decimal) // 2:] + decimal[:len(decimal) // 2]))[2:]:<01024s}'
key = bin_to_bytes(binary[:1024])
half1 = key[:len(key) // 2]
half2 = key[len(key) // 2:]
key = half2 + half1
return key[:128]i,而在没有名称冲突的情况下使用j,这有点奇怪。很奇怪,但也不可怕。128放入一个称为块大小的常量中,并将其放在这个文件的顶部。BLOCK_SIZE = 128。然后用这个常量替换128的所有实例,如果块大小发生变化,您只需要在一个地方更新它。_使其“私有”。https://codereview.stackexchange.com/questions/260171
复制相似问题