首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加密/解密算法#2

加密/解密算法#2
EN

Code Review用户
提问于 2021-04-27 15:39:02
回答 1查看 140关注 0票数 2

这是 one的后续问题.

我试着在答案中实现所有推荐的内容(除了注释,而且不是操作系统特定的)。再次,如果你看到任何需要改进,或会使它更快,请告诉我!

这是密码。这次只有222行:)。

代码语言:javascript
复制
#!/usr/bin/env python 
# not sure if I did this right

import base64
import random
import os


def add_padding(plain_text, block_size=128):
    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 decimal_to_binary(padded_text)


def xor_string(key, secret):
    xored_secret = ''

    for i in range(len(secret) // len(key)):
        if i > 0:
            key = get_round_key(key)

        xored_secret += decimal_to_binary([bin_to_decimal(key, len(key))[0] ^ bin_to_decimal(secret[i * len(key):len(key) + (i * len(key))], len(key))[0]], len(key))

    return xored_secret


def generate_key(key):
    if len(key) >= 128:
        key = decimal_to_binary(key.encode())
        return key[:1024]
    elif len(key) < 128:

        key = key.encode()

        for i in range(128 - len(key)):
            b = decimal_to_binary([key[i]])
            b = xor_string(decimal_to_binary([sum(key) // len(key)]), b[::-1])

            key += bytes([int(b, 2)])

        new_key = ''.join(str(i) for i in key)

        half1 = new_key[:len(new_key) // 2]
        half2 = new_key[len(new_key) // 2:]
        new_key = decimal_to_binary([int(half1 + half2)])
        new_key = new_key[:1024]
        return new_key


def bin_to_base64(binary):
    return base64.b64encode(bytes([int(binary[i * 8:8 + i * 8], 2) for i in range(len(binary) // 8)])).decode()


def bin_to_decimal(binary, length=8):
    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, length=8):
    return ''.join(str(bin(num)[2:].zfill(length)) for num in decimal)


def base64_to_bin(base):
    decoded = ''
    for letter in base64.b64decode(base):
        decoded += bin(letter)[2:].zfill(8)

    return decoded


def matrix_to_str(m):
    return ''.join(str(m[i][j]) for i in range(32) for j in range(32))


def obfuscate(binary, key, encrypting, loops):
    shuffled_binary = ''
    round_key = key

    for i in range(len(binary) // 1024):
        if i > 0:
            round_key = get_round_key(round_key)

        if encrypting:
            m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
            m = shuffle(m, bin_to_decimal(round_key, 1024)[0], loops)
            shuffled_binary += xor_string(round_key, matrix_to_str(m))
        else:
            xor = xor_string(round_key, binary[i * 1024:i * 1024 + 1024])
            m = [list(xor[j * 32:j * 32 + 32]) for j in range(32)]
            m = reverse_shuffle(m, bin_to_decimal(round_key, 1024)[0], loops)
            shuffled_binary += matrix_to_str(m)

    return xor_string(key, shuffled_binary)


def shuffle(m, key, loops):
    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] * 32 for _ in range(32)]

        for idx, sidx in enumerate(test(key)):
            shuffled_m[idx // 32][idx % 32] = m[sidx // 32][sidx % 32]

        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, key, loops):
    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] * 32 for _ in range(32)]

        for idx, sidx in enumerate(test(key)):
            shuffled_m[sidx // 32][sidx % 32] = m[idx // 32][idx % 32]

        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 test(seed):
    random.seed(seed)
    lst = list(range(1024))
    random.shuffle(lst)

    return lst


def get_round_key(key):
    key = [[key[(j * 32 + n)] for n in range(32)] for j in range(32)]
    # get the last column
    col = [i[-1] for i in key]
    # interweave
    col = [x for i in range(len(col) // 2) for x in (col[-i - 1], col[i])]
    new_key = ''
    for i in range(32):
        cols = ''
        for row in key:
            cols += row[i]

        cols = cols[16:] + cols[:16]
        new_key += xor_string(''.join(str(ele) for ele in col), cols)

    return new_key


def bin_to_bytes(binary):
    return int(binary, 2).to_bytes(len(binary) // 8, byteorder='big')


def encrypt(password, secret, loops):
    key = generate_key(password)
    secret = add_padding(secret)
    secret = xor_string(key, secret)
    secret = obfuscate(secret, key, True, loops)
    secret = bin_to_base64(secret)
    return secret


def decrypt(password, base, loops):
    key = generate_key(password)
    binary = base64_to_bin(base)
    binary = xor_string(key, binary)
    binary = obfuscate(binary, key, False, loops)
    binary = bin_to_bytes(binary)
    pad = binary[-1]
    binary = binary[:-pad]
    return binary.decode()


if __name__ == '__main__':
    while True:
        os.system('cls')
        com = input('1)Encrypt Text \n2)Decrypt Text\n3)Exit\n')

        if com == '1':
            os.system('cls')
            secret = input('Enter the text you wish to encrypt: ')
            os.system('cls')
            key = input('Enter your key: ')
            os.system('cls')
            print(f'Encrypted text: {encrypt(key, secret, 1)}')
            input()
        elif com == '2':
            os.system('cls')
            b64 = input('Enter the text you wish to decrypt: ')
            os.system('cls')
            key = input('Enter your key: ')
            os.system('cls')
            print(f'Decrypted text: {decrypt(key, b64, 1)}')
            input()
        elif com == '3':
            break
EN

回答 1

Code Review用户

回答已采纳

发布于 2021-04-27 22:03:13

  • 考虑添加PEP484类型提示。我需要通过这个来理解你正在传递的值。
  • 不是操作系统特有的-确实。您对cls的调用具有可疑的安全价值,如果您认为它具有这样的价值,最好调用一个跨平台库来完成同样的任务。目前,您是与Windows挂钩,这是不好的。你离拥有一个交叉兼容的应用程序如此之近;如果让这仍然是你唯一的障碍,那将是一件遗憾的事。现在,在这个示例中,我只是删除了您的cls调用。如果它们只是为了美学的目的,你应该保持它的方式。
  • 更高的安全值是getpass而不是input,以防止密码的过度使用。
  • 对于对称密码函数来说,obfuscate不是一个特别好的名称;只有当encrypting=True出现时,它才会“混淆”。名字很难命名;也许叫这个process_crypto或者一些名字。
  • 一个0和1个字符的字符串--或者更糟糕的是,长度为1的字符串列表(每个字符串都是0或1个字符)--是二进制数据的一个非常低效率和不切实际的内部表示形式。这比我愿意做的工作要多,但是对于一个超越表面的、初级的教学代码的应用程序来说,重构使用bytes数组(在不可变数据的情况下)或bytearray() (在可变数据的情况下)是至关重要的。
  • 与上述相关--携带超过300位数字的任意长度整数可能不是一个好主意(!!)。同样,bytes是一种更好的表示形式。
  • 避免循环O(n^2)中字符串的增量级联。
  • 你得用单线机放松一下。xored_secret += decimal_to_binary([bin_to_decimal(key,len(key)) ^bin_to_decimal(秘,len(key))],len(key))

我看到其中至少有三个不同的表达式,它们应该在一个单独的行上接收它们自己的独立的临时变量。

  • key重新分配到不同类型的值( strbytes )是不可取的;请创建不同的变量名。
  • 拥有__main__保护不足以创建作用域。要将主要变量放入函数范围,需要一个实际的函数。
  • 调用到random对您的密码的安全性是有害的,而且可能是每个密码新手都会犯的错误之一。代之以调用secrets

涵盖上述一些(当然不是全部):

代码语言:javascript
复制
#!/usr/bin/env python
# not sure if I did this right

import base64
import random
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 decimal_to_binary(padded_text)


def xor_string(key: str, secret: str) -> str:
    xored_secret = ''

    for i in range(len(secret) // len(key)):
        if i > 0:
            key = get_round_key(key)

        some_decimals = bin_to_decimal(secret[i * len(key):len(key) + (i * len(key))], len(key))

        some_values = [
            bin_to_decimal(key, len(key))[0] ^ some_decimals[0]
        ]

        xored_secret += decimal_to_binary(some_values, len(key))

    return xored_secret


def generate_key(key: str) -> str:
    if len(key) >= 128:
        key = decimal_to_binary(key.encode())
        return key[:1024]
    elif len(key) < 128:

        key = key.encode()

        for i in range(128 - len(key)):
            b = decimal_to_binary([key[i]])
            b = xor_string(decimal_to_binary([sum(key) // len(key)]), b[::-1])

            key += bytes([int(b, 2)])

        new_key = ''.join(str(i) for i in key)

        half1 = new_key[:len(new_key) // 2]
        half2 = new_key[len(new_key) // 2:]
        new_key = decimal_to_binary([int(half1 + half2)])
        new_key = new_key[:1024]
        return new_key


def bin_to_base64(binary: str) -> str:
    ints = [
        int(binary[i * 8:8 + i * 8], 2)
        for i in range(len(binary) // 8)
    ]
    return base64.b64encode(bytes(ints)).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_bin(base: str) -> str:
    decoded = ''
    for letter in base64.b64decode(base):
        decoded += bin(letter)[2:].zfill(8)

    return decoded


def matrix_to_str(m: List[List[str]]) -> str:
    return ''.join(
        str(m[i][j])
        for i in range(32) for j in range(32)
    )


def obfuscate(binary: str, key: str, encrypting: bool, loops: int) -> str:
    shuffled_binary = ''
    round_key = key

    for i in range(len(binary) // 1024):
        if i > 0:
            round_key = get_round_key(round_key)

        if encrypting:
            m = [list(binary[j * 32 + i * 1024:j * 32 + i * 1024 + 32]) for j in range(32)]
            m = shuffle(m, bin_to_decimal(round_key, 1024)[0], loops)
            shuffled_binary += xor_string(round_key, matrix_to_str(m))
        else:
            xor = xor_string(round_key, binary[i * 1024:i * 1024 + 1024])
            m = [list(xor[j * 32:j * 32 + 32]) for j in range(32)]
            m = reverse_shuffle(m, bin_to_decimal(round_key, 1024)[0], loops)
            shuffled_binary += matrix_to_str(m)

    return xor_string(key, shuffled_binary)


def shuffle(m: List[List[str]], key: int, loops: int) -> List[List[str]]:
    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] * 32 for _ in range(32)]

        for idx, sidx in enumerate(test(key)):
            shuffled_m[idx // 32][idx % 32] = m[sidx // 32][sidx % 32]

        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] * 32 for _ in range(32)]

        for idx, sidx in enumerate(test(key)):
            shuffled_m[sidx // 32][sidx % 32] = m[idx // 32][idx % 32]

        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 test(seed: int) -> List[int]:
    random.seed(seed)
    lst = list(range(1024))
    random.shuffle(lst)

    return lst


def get_round_key(key):
    key = [[key[(j * 32 + n)] for n in range(32)] for j in range(32)]
    # get the last column
    col = [i[-1] for i in key]
    # interweave
    col = [x for i in range(len(col) // 2) for x in (col[-i - 1], col[i])]
    new_key = ''
    for i in range(32):
        cols = ''
        for row in key:
            cols += row[i]

        cols = cols[16:] + cols[:16]
        new_key += xor_string(''.join(str(ele) for ele in col), cols)

    return new_key


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 = bin_to_base64(secret)
    return secret


def decrypt(password: str, base: str, loops: int = 1) -> str:
    key = generate_key(password)
    binary = base64_to_bin(base)
    binary = xor_string(key, binary)
    binary = obfuscate(binary, key, False, loops)
    binary = bin_to_bytes(binary)
    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: ')

        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__':
    main()

一般说来,为了教育和娱乐目的,编写这样的代码是很有趣的。然而,密码实现很难得到正确的实现,有时甚至更难证明它们是正确的。在真实的生产世界中,请不要使用这个,只需调用一个库。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/260077

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档