Как зашифровать UTF-8 за пределами A-Z в python?

#python #encryption #utf-8 #hex

#python #шифрование #utf-8 #шестнадцатеричный

Вопрос:

Много лет назад я создал программу на C # в Windows, которая «шифрует» текстовые файлы, используя (как я думал) caeser chipher.

Тогда я хотел больше символов, чем просто A-Z, 0-9 и сделал это возможным, но никогда не думал о реальной теории, стоящей за этим.

Глядя на некоторые файлы и сравнивая их с этим веб-сайтом, кажется, что UTF-8 смещается.


Я запустил виртуальную машину Windows (потому что сейчас я использую Linux) и набрал это: abcdefghijklmnopqrstuvwxyz

Он сгенерировал текст, который выглядит примерно так в шестнадцатеричных числах (сдвинут в 15 раз):

 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f c280 c281 c282 c283 c284 c285 c286 c287 c288 c289
  

Как я могу изменить шестнадцатеричные значения, чтобы они выглядели так?

 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a
  

Или есть какие-либо более простые / лучшие методы для этого?


Обновить

Я использую Python 3.5.3, и это код, который у меня есть на данный момент:

 import sys

arguments = sys.argv[1:]
file = ""

for arg in arguments:
    if arg[0] != "-":
        file = arg

lines = []
with open(file) as f:
    lines = f.readlines()

for line in lines:
    result = 0
    for value in list(line):
        #value = "0x" value
        temp=value.encode('utf-8').hex()
        temp =15
        if(temp>0x7a):
            temp-=0x7a
        elif(temp<=0):
            temp =0x7a
        #result = result   temp
    print (result)
  

К сожалению, на данный момент у меня нет доступного исходного кода C #. Я могу попытаться найти это

Комментарии:

1. Я не уверен, что понимаю, в чем заключается основная проблема. Почему вы не можете просто вычесть из каждого символа значение 15?

Ответ №1:

Предполагая, что ваш ввод представляет собой текст в формате ASCII, самым простым решением является кодирование / декодирование в формате ASCII и использование встроенных методов ord() и chr() для преобразования из символа в байтовое значение и наоборот.

Обратите внимание, что temp значение не может быть меньше 0, поэтому второй оператор if можно удалить.

ПРИМЕЧАНИЕ: Это выходит за рамки вопроса, но я также заметил, что вы сами выполняете синтаксический анализ аргументов. Я настоятельно рекомендую использовать argparse вместо этого, так как это очень просто и дает вам много дополнительных бесплатных (т. Е. Он выполняет проверку ошибок и выводит приятное справочное сообщение, если вы запускаете свое приложение с опцией ‘—help’). Смотрите пример кода ниже:

 import argparse

parser = argparse.ArgumentParser()
parser.add_argument(dest='filenames', metavar='FILE', type=str, nargs=' ',
                    help='file(s) to encrypt')
args = parser.parse_args()

for filename in args.filenames:
    with open(filename, 'rt', encoding='ascii') as file:
        lines = file.readlines()
    for line in lines:
        result = ""
        for value in line:
            temp = ord(value)  # character to int value
            temp  = 15
            if temp > 0x7a:
                temp -= 0x7a
            result  = chr(temp)  # int value to character
        print(result)
  

Ответ №2:

Вы можете конвертировать шестнадцатеричные числа между целыми числами и шестнадцатеричными числами, используя int() и hex() . Однако hex() метод работает только с целыми числами. Итак, сначала вам нужно преобразовать в целое число, используя base= 16 .

 hex_int = int(hex_str, 16)
cipher = hex_int - 15
hex_cipher = hex(cipher)
  

Теперь примените это в цикле, и вы можете сдвигать свои результаты влево или вправо по желанию. И вы, конечно, могли бы также сжать код.

 result = hex(int(hex_string, 16) - 15)

#in a loop
hexes = ['70', '71', 'c280']
ciphered = []
for n in hexes:
    ciphered.append(hex(int(n, 16) - 15))
  

Ответ №3:

Вы можете использовать int('somestring'.encode('utf-8').hex(),16) , чтобы получить точные значения на этом веб-сайте. Если вы хотите применить одни и те же правила к каждому символу, вы можете сделать это в списке символов. Вы можете использовать

 import codecs

def myencode(character,diff):
    temp=int(character.encode('utf-8').hex(),16)
    temp =diff
    if(temp>0x7a):
        temp-=0x7a
    elif(temp<=0):
        temp =0x7a
    result=codecs.decode(hex(temp)[2:],"hex").decode("utf-8")
    return result
  

diff должен быть сдвиг для шифрования (это может быть целое число). encode('utf-8') преобразует строку в массив байтов и .hex() отображает байты как шестнадцатеричные. Вы должны передавать этой функции только один символ строки за раз, чтобы не возникало проблем с переносом всего.

После того, как вы закончите с кодировкой, вам нужно декодировать ее в новый символ, который вы можете сделать с помощью библиотеки codecs для преобразования из integer в byte ( char ), а затем вернуть его обратно в строку с decode("utf-8")

Редактировать: обновлено, теперь это работает.

Комментарии:

1. Что должно diff быть? Я бы предположил, что это целое число (сдвиг), но я получаю сообщение об ошибке: TypeError: cannot concatenate 'str' and 'int' objects . Кроме того, это должно быть .hex() или .encode("hex") ?

2. @Typewar diff это сдвиг, как вы уже догадались. Я обновляю свой ответ, чтобы объяснить его более подробно.

3. Теперь я получаю эту ошибку TypeError: Can't convert 'int' object to str implicitly . Я попытался добавить 0x перед строкой, подобной этой temp=str("0x" character).encode('utf-8').hex() но это не помогло. Я вижу, что при добавлении 0x впереди значение int изменяется с 70 на 307870

4. Вам не нужно добавлять 0x в начале в виде строки. Все, что возвращает эта функция, уже является шестнадцатеричным

5. И, пожалуйста, обратите внимание, что я разработал этот шифр в диапазоне от 0 до 7a. Возможно, вы также захотите это изменить. (путем изменения значений 0 и 7a)