Шифр "Кузнечика"
Всем доброго дня! Пишу алгоритмы шифрования "Кузнечик" для Клиент-Сервера, но получается не оч. Я Бы сказал, никак.
До этого делал ключ Хеллмана, шифр Цезаря и Виженера ( +- рабоатет)
Пишу всё на Python, кто-нибудь делал и с чего вообще можно начать. Или какие-нибудь библиотеки там.
Всем большое спасибо за ответы и предложения!
Ответы (1 шт):
Автор решения: jitco co
→ Ссылка
Программа сыра. Вот результат ее исполнения:
Введите ключ: 23456789087654FFFF
Введите сообщение: РАК
Шифр текст (зашифрованное сообщение с помощью ключа):
1b026ae958130e363bf60c8ed1cc3f53
Расшифрованное сообщение в виде байт:
b'#%\xc7\x02\x7f\xc9k\x90\x8cx\x80UTN\xd6\xac'
Расшифрованное сообщение:
Не удается декодировать сообщение.
>>>
BLOCK_SIZE = 16 # длина блока
КОД:
# таблица прямого нелинейного преобразования
Pi = [
0xFC, 0xEE, 0xDD, 0x11, 0xCF, 0x6E, 0x31, 0x16,
0xFB, 0xC4, 0xFA, 0xDA, 0x23, 0xC5, 0x04, 0x4D,
0xE9, 0x77, 0xF0, 0xDB, 0x93, 0x2E, 0x99, 0xBA,
0x17, 0x36, 0xF1, 0xBB, 0x14, 0xCD, 0x5F, 0xC1,
0xF9, 0x18, 0x65, 0x5A, 0xE2, 0x5C, 0xEF, 0x21,
0x81, 0x1C, 0x3C, 0x42, 0x8B, 0x01, 0x8E, 0x4F,
0x05, 0x84, 0x02, 0xAE, 0xE3, 0x6A, 0x8F, 0xA0,
0x06, 0x0B, 0xED, 0x98, 0x7F, 0xD4, 0xD3, 0x1F,
0xEB, 0x34, 0x2C, 0x51, 0xEA, 0xC8, 0x48, 0xAB,
0xF2, 0x2A, 0x68, 0xA2, 0xFD, 0x3A, 0xCE, 0xCC,
0xB5, 0x70, 0x0E, 0x56, 0x08, 0x0C, 0x76, 0x12,
0xBF, 0x72, 0x13, 0x47, 0x9C, 0xB7, 0x5D, 0x87,
0x15, 0xA1, 0x96, 0x29, 0x10, 0x7B, 0x9A, 0xC7,
0xF3, 0x91, 0x78, 0x6F, 0x9D, 0x9E, 0xB2, 0xB1,
0x32, 0x75, 0x19, 0x3D, 0xFF, 0x35, 0x8A, 0x7E,
0x6D, 0x54, 0xC6, 0x80, 0xC3, 0xBD, 0x0D, 0x57,
0xDF, 0xF5, 0x24, 0xA9, 0x3E, 0xA8, 0x43, 0xC9,
0xD7, 0x79, 0xD6, 0xF6, 0x7C, 0x22, 0xB9, 0x03,
0xE0, 0x0F, 0xEC, 0xDE, 0x7A, 0x94, 0xB0, 0xBC,
0xDC, 0xE8, 0x28, 0x50, 0x4E, 0x33, 0x0A, 0x4A,
0xA7, 0x97, 0x60, 0x73, 0x1E, 0x00, 0x62, 0x44,
0x1A, 0xB8, 0x38, 0x82, 0x64, 0x9F, 0x26, 0x41,
0xAD, 0x45, 0x46, 0x92, 0x27, 0x5E, 0x55, 0x2F,
0x8C, 0xA3, 0xA5, 0x7D, 0x69, 0xD5, 0x95, 0x3B,
0x07, 0x58, 0xB3, 0x40, 0x86, 0xAC, 0x1D, 0xF7,
0x30, 0x37, 0x6B, 0xE4, 0x88, 0xD9, 0xE7, 0x89,
0xE1, 0x1B, 0x83, 0x49, 0x4C, 0x3F, 0xF8, 0xFE,
0x8D, 0x53, 0xAA, 0x90, 0xCA, 0xD8, 0x85, 0x61,
0x20, 0x71, 0x67, 0xA4, 0x2D, 0x2B, 0x09, 0x5B,
0xCB, 0x9B, 0x25, 0xD0, 0xBE, 0xE5, 0x6C, 0x52,
0x59, 0xA6, 0x74, 0xD2, 0xE6, 0xF4, 0xB4, 0xC0,
0xD1, 0x66, 0xAF, 0xC2, 0x39, 0x4B, 0x63, 0xB6
]
# таблица обратного нелинейного преобразования
reverse_Pi = [
0xA5, 0x2D, 0x32, 0x8F, 0x0E, 0x30, 0x38, 0xC0,
0x54, 0xE6, 0x9E, 0x39, 0x55, 0x7E, 0x52, 0x91,
0x64, 0x03, 0x57, 0x5A, 0x1C, 0x60, 0x07, 0xE0,
0x98, 0x06, 0x4F, 0xB2, 0xD3, 0x1D, 0xAA, 0xE5,
0x3E, 0xFD, 0xC3, 0x80, 0x0B, 0x0D, 0x87, 0xA7,
0x6D, 0x82, 0x7A, 0x7C, 0x95, 0xCA, 0xA0, 0x35,
0xE8, 0x55, 0x21, 0xE2, 0xFF, 0x99, 0x49, 0xAE,
0x65, 0x80, 0xF4, 0x00, 0x03, 0xA1, 0x98, 0x6D,
0x0B, 0xBF, 0xD6, 0x6A, 0x97, 0x71, 0x63, 0xDF,
0xC6, 0x57, 0x3D, 0xC7, 0xC1, 0x3F, 0x1A, 0x12,
0xEB, 0x2A, 0x8A, 0x96, 0xA4, 0x92, 0x1E, 0x7B,
0x9C, 0x80, 0x83, 0x62, 0x8B, 0x78, 0xA9, 0xF3,
0x99, 0x2A, 0xB0, 0x1C, 0x9F, 0xE3, 0x14, 0x19,
0x21, 0xA8, 0x3A, 0x61, 0x7F, 0x26, 0x40, 0xFB,
0xEE, 0x3E, 0xD9, 0x24, 0xC5, 0xF0, 0xE7, 0x05,
0x5F, 0x49, 0x56, 0x6F, 0x3B, 0x1D, 0x77, 0x6C,
0x0C, 0xD5, 0x45, 0x11, 0xA3, 0x48, 0xFC, 0x47,
0x2C, 0xC2, 0x37, 0xB3, 0x84, 0xAA, 0x76, 0x27,
0x79, 0x36, 0xC9, 0x4D, 0x58, 0x50, 0x1B, 0x1F,
0x28, 0x02, 0x41, 0xAD, 0x6E, 0x51, 0xC4, 0x1E,
0xAB, 0x93, 0xD4, 0x88, 0xF2, 0x3C, 0x7D, 0xB8,
0xD7, 0xCB, 0xDE, 0xB5, 0x33, 0xCE, 0xD8, 0x0D,
0x5B, 0xCD, 0x6B, 0x90, 0xF6, 0x53, 0xBE, 0x4A,
0x3A, 0xFA, 0x7A, 0xDA, 0x85, 0x8D, 0x75, 0x43,
0x8C, 0x66, 0x25, 0xC8, 0xA6, 0x4E, 0xDD, 0xEF,
0x8E, 0x67, 0x13, 0x0F, 0x23, 0xF9, 0x81, 0x74,
0x42, 0x04, 0x0A, 0xB1, 0xDC, 0x5E, 0x22, 0x86,
0x09, 0x68, 0xF8, 0x70, 0xEC, 0x94, 0x8C, 0xBC,
0xF7, 0xF5, 0xCF, 0x29, 0x4B, 0x2E, 0xED, 0xAC,
0x46, 0x72, 0x44, 0x69, 0x17, 0xF1, 0xD1, 0x18,
0xB4, 0xE4, 0x73, 0x5D, 0xD0, 0x15, 0x20, 0x59,
0x2F, 0x89, 0x10, 0x31, 0xE1, 0xBA, 0xEA, 0x1A,
0xFF, 0xE9, 0x9B, 0x16, 0x34, 0xBB, 0xB7, 0x9A,
0xBD, 0x6C, 0xA2, 0x2B, 0x05, 0xA9, 0xFE, 0xC2,
0x58, 0x33, 0x4C, 0x08, 0xB9, 0xEB, 0x50, 0x4A
]
# Вектор линейного преобразования
l_vec = [1, 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148]
# Массив для хранения констант
iter_C = [[0] * BLOCK_SIZE for _ in range(32)]
# Массив для хранения ключей
iter_key = [[0] * 64 for _ in range(10)]
def kuz_x(a, b):
if len(a) != len(b):
# Выравнивание массивов до одинаковой длины
max_len = max(len(a), len(b))
a += bytearray(max_len - len(a))
b += bytearray(max_len - len(b))
c = bytearray(len(a))
for i in range(len(a)):
c[i] = a[i] ^ b[i]
return c
# Функция S
def kuz_s(in_data):
out_data = bytearray(BLOCK_SIZE)
for i in range(BLOCK_SIZE):
out_data[i] = Pi[in_data[i]]
return bytes(out_data)
# Функция L
def kuz_l(in_data):
out_data = bytearray(in_data)
for _ in range(16):
a_15 = out_data[-1]
for i in range(BLOCK_SIZE - 1, 0, -1):
out_data[i] = out_data[i - 1]
a_15 ^= gf_mul(out_data[i], l_vec[i])
# Ограничение значения a_15 до диапазона от 0 до 255
a_15 %= 256
out_data[0] = a_15
return bytes(out_data)
# Функция обратного преобразования S
def reverse_kuz_s(in_data):
out_data = bytearray(BLOCK_SIZE)
for i in range(BLOCK_SIZE):
out_data[i] = reverse_Pi[in_data[i]]
return bytes(out_data)
# Функция обратного преобразования L
def reverse_kuz_l(in_data):
out_data = bytearray(in_data)
for _ in range(16):
a_0 = out_data[0]
for i in range(1, BLOCK_SIZE):
out_data[i - 1] = out_data[i]
a_0 ^= gf_mul(out_data[i], l_vec[i])
# Ограничение значения a_0 до диапазона от 0 до 255
a_0 %= 256
out_data[-1] = a_0
return bytes(out_data)
# Функция умножения в поле Галуа
def gf_mul(a, b):
c = 0
for _ in range(8):
if b & 1:
c ^= a
hi_bit = a & 0x80
a <<= 1
if hi_bit:
a ^= 0xc3 # Полином x^8 + x^7 + x^6 + x + 1
b >>= 1
return c
# Функция расчета констант
def get_iter_C():
iter_num = [[0] * BLOCK_SIZE for _ in range(32)]
for i in range(32):
iter_num[i][0] = i + 1
for i in range(32):
iter_C[i] = kuz_l(iter_num[i])
# Функция, выполняющая преобразования ячейки Фейстеля
def kuz_f(in_key_1, in_key_2, iter_const):
internal = kuz_x(in_key_1, iter_const)
internal = kuz_s(internal)
internal = kuz_l(internal)
out_key_1 = kuz_x(internal, in_key_2)
out_key_2 = in_key_1
return out_key_1, out_key_2
# Функция расчета раундовых ключей
def expand_key(key_1, key_2):
get_iter_C()
iter_key[0] = key_1
iter_key[1] = key_2
iter12 = [key_1, key_2]
for i in range(4):
iter34 = kuz_f(iter12[0], iter12[1], iter_C[0 + 8 * i])
iter12 = kuz_f(iter34[0], iter34[1], iter_C[1 + 8 * i])
iter34 = kuz_f(iter12[0], iter12[1], iter_C[2 + 8 * i])
iter12 = kuz_f(iter34[0], iter34[1], iter_C[3 + 8 * i])
iter34 = kuz_f(iter12[0], iter12[1], iter_C[4 + 8 * i])
iter12 = kuz_f(iter34[0], iter34[1], iter_C[5 + 8 * i])
iter34 = kuz_f(iter12[0], iter12[1], iter_C[6 + 8 * i])
iter12 = kuz_f(iter34[0], iter34[1], iter_C[7 + 8 * i])
iter_key[2 * i + 2] = iter12[0]
iter_key[2 * i + 3] = iter12[1]
def kuz_encrypt_block(blk):
out_blk = blk
for i in range(9):
out_blk = kuz_x(iter_key[i], out_blk)
out_blk = kuz_s(out_blk)
out_blk = kuz_l(out_blk)
out_blk = kuz_x(out_blk, iter_key[9])
return out_blk
def kuz_decrypt_block(blk):
out_blk = blk
out_blk = kuz_x(out_blk, iter_key[9])
for i in range(8, -1, -1):
out_blk = reverse_kuz_l(out_blk)
out_blk = reverse_kuz_s(out_blk)
out_blk = kuz_x(iter_key[i], out_blk)
return out_blk
def main():
key = input("Введите ключ: ")
message = input("Введите сообщение: ")
encrypted_message = encrypt_message(key, message)
print("Шифр текст (зашифрованное сообщение с помощью ключа):")
print(encrypted_message)
decrypted_message = decrypt_message(key, encrypted_message)
print("Расшифрованное сообщение в виде байт:")
print(decrypted_message)
try:
print("Расшифрованное сообщение:")
print(decrypted_message.decode('ascii')) # Попытка декодировать как ASCII
except UnicodeDecodeError:
print("Не удается декодировать сообщение.")
def encrypt_message(key, message):
key_bytes = bytes.fromhex(key)
message_bytes = message.encode('windows-1251') # Используем кодировку windows-1251
if len(message_bytes) % BLOCK_SIZE != 0:
message_bytes += bytes(BLOCK_SIZE - len(message_bytes) % BLOCK_SIZE)
expand_key(key_bytes[:32], key_bytes[32:])
encrypted_message = b''
for i in range(0, len(message_bytes), BLOCK_SIZE):
block = message_bytes[i:i+BLOCK_SIZE]
encrypted_block = kuz_encrypt_block(block)
encrypted_message += encrypted_block
return encrypted_message.hex()
def decrypt_message(key, encrypted_message):
key_bytes = bytes.fromhex(key)
encrypted_message_bytes = bytes.fromhex(encrypted_message)
decrypted_message = b''
for i in range(0, len(encrypted_message_bytes), BLOCK_SIZE):
block = encrypted_message_bytes[i:i+BLOCK_SIZE]
decrypted_block = kuz_decrypt_block(block)
decrypted_message += decrypted_block
decrypted_message = decrypted_message.rstrip(b'\x00') # Удаление нулевых байтов после декодирования
return decrypted_message
if __name__ == "__main__":
main()
Вот еще один вариант:
import binascii
# Функция XOR для двух строк
def xor_func (input1AsString, input2AsString, in_code = 16):
input1AsInteger = int(input1AsString, in_code)
input2AsInteger = int(input2AsString, in_code)
result = input1AsInteger ^ input2AsInteger
resultAsHex = hex(result)
resultAsHex = resultAsHex.upper()
resultAsHex = resultAsHex[2:]
if len(resultAsHex) != len(input1AsString):
for i in range(len(input1AsString) - len(resultAsHex)):
resultAsHex = '0' + resultAsHex
return resultAsHex
# Пример:
# xor_func('101', '10', in_code = 2)
# Функция перевода между системами счисления
def convert_base(num, to_base = 10, from_base = 10):
# Преобразование в десятичное число
if isinstance(num, str):
n = int(num, from_base)
else:
n = int(num)
# Преобразование десятичного числа в необходимую систему счисления
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
if n < to_base:
return alphabet[n]
else:
return convert_base(n // to_base, to_base) + alphabet[n % to_base]
# Пример:
# convert_base('AC', from_base=16)
# Ряд Галуа
galua_coef = [148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148, 1]
galua_coef_reverse = [1, 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148]
# Таблица степеней двойки
galua_fields = [
1, 2, 4, 8, 16, 32, 64, 128, 195, 69, 138, 215, 109, 218, 119, 238,
31, 62, 124, 248, 51, 102, 204, 91, 182, 175, 157, 249, 49, 98, 196,
75, 150, 239, 29, 58, 116, 232, 19, 38, 76, 152, 243, 37, 74, 148,
235, 21, 42, 84, 168, 147, 229, 9, 18, 36, 72, 144, 227, 5, 10, 20,
40, 80, 160, 131, 197, 73, 146, 231, 13, 26, 52, 104, 208, 99, 198,
79, 158, 255, 61, 122, 244, 43, 86, 172, 155, 245, 41, 82, 164, 139,
213, 105, 210, 103, 206, 95, 190, 191, 189, 185, 177, 161, 129, 193,
65, 130, 199, 77, 154, 247, 45, 90, 180, 171, 149, 233, 17, 34, 68,
136, 211, 101, 202, 87, 174, 159, 253, 57, 114, 228, 11, 22, 44, 88,
176, 163, 133, 201, 81, 162, 135, 205, 89, 178, 167, 141, 217, 113,
226, 7, 14, 28, 56, 112, 224, 3, 6, 12, 24, 48, 96, 192, 67, 134, 207,
93, 186, 183, 173, 153, 241, 33, 66, 132, 203, 85, 170, 151, 237, 25,
50, 100, 200, 83, 166, 143, 221, 121, 242, 39, 78, 156, 251, 53, 106,
212, 107, 214, 111, 222, 127, 254, 63, 126, 252, 59, 118, 236, 27, 54,
108, 216, 115, 230, 15, 30, 60, 120, 240, 35, 70, 140, 219, 117, 234,
23, 46, 92, 184, 179, 165, 137, 209, 97, 194, 71, 142, 223, 125, 250,
55, 110, 220, 123, 246, 47, 94, 188, 187, 181, 169, 145, 225, 1]
# Линейное преобразование для блока длины 32
def linear_transformation(num, move = 'straight'):
# Подставляемое число, если число, образованное 2-мя подряд
# идущими цифрами в 16-ой системе счисления, равно 0
numIfNull = 257
# Линейная функция выполняется 16 раз
for i in range(16):
# Массив индексов таблицы степеней двойки `galua_fields` коэффициентов ряда Галуа
coefs = []
# Массив индексов таблицы степеней двойки `galua_fields`,
# полученных от чисел, образованных 2-мя подряд идущими
# цифрами в 16-ой системе счисления
nums = []
# Заполнение массивов
for j in range(len(galua_coef)):
if move == 'reverse':
coefs.append(galua_fields.index(galua_coef_reverse[ len(galua_coef_reverse) - j - 1 ]))
else:
coefs.append(galua_fields.index(galua_coef[ len(galua_coef) - j - 1 ]))
if int(convert_base(num[j * 2 : j * 2 + 2], from_base=16)) == 0:
nums.append(numIfNull)
else:
nums.append(galua_fields.index(int(convert_base(num[j * 2 : j * 2 + 2], from_base=16))))
# Массив значений, полученных из таблицы степеней двойки `galua_fields`
galua = []
# Заполнение массива
for j in range(len(galua_coef)):
if nums[j] != numIfNull:
# Проверка, что сумма индексов не более длины таблицы степеней двойки `galua_fields`
if nums[j] + coefs[j] <= 255:
galua.append(galua_fields[nums[j] + coefs[j]])
else:
galua.append(galua_fields[(nums[j] + coefs[j]) % 255])
# Подсчитывание числа, которое необходимо прибавить к концу входного блока
galua_num = galua[0]
if len(galua) != 1:
for j in range(len(galua) - 1):
# XOR массива значений, полученных из таблицы степеней двойки `galua_fields`
galua_num = int(xor_func(str(galua_num), str(galua[j + 1]), in_code = 10), 16) % 256
galua_num = hex(galua_num)[2:]
# Проверка, если длина полученного числа равна 1
if len(str(galua_num)) == 1:
galua_num = '0' + str(galua_num)
# Сдвиг с добавлением полученного числа
if move == 'reverse':
num = galua_num + num[:len(num)-2]
else:
num = num[2:] + galua_num
return num
# Пример:
# linear_transformation('02000000000000000000000000000000')
# Таблица для прямого хода (straight)
nonlinear_coef = [
252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4,
77, 233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205,
95, 193, 249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1,
142, 79, 5, 132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127,
212, 211, 31, 235, 52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162,
253, 58, 206, 204, 181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71,
156, 183, 93, 135, 21, 161, 150, 41, 16, 123, 154, 199, 243, 145, 120,
111, 157, 158, 178, 177, 50, 117, 25, 61, 255, 53, 138, 126, 109, 84,
198, 128, 195, 189, 13, 87, 223, 245, 36, 169, 62, 168, 67, 201, 215,
121, 214, 246, 124, 34, 185, 3, 224, 15, 236, 222, 122, 148, 176, 188,
220, 232, 40, 80, 78, 51, 10, 74, 167, 151, 96, 115, 30, 0, 98, 68,
26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70, 146, 39, 94, 85, 47,
140, 163, 165, 125, 105, 213, 149, 59, 7, 88, 179, 64, 134, 172, 29,
247, 48, 55, 107, 228, 136, 217, 231, 137, 225, 27, 131, 73, 76, 63,
248, 254, 141, 83, 170, 144, 202, 216, 133, 97, 32, 113, 103, 164, 45,
43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166, 116, 210,
230, 244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182]
# Таблица для обратного хода (reverse)
nonlinear_coef_reverse = [
165, 45, 50, 143, 14, 48, 56, 192, 84, 230, 158, 57, 85, 126, 82, 145,
100, 3, 87, 90, 28, 96, 7, 24, 33, 114, 168, 209, 41, 198, 164, 63,
224, 39, 141, 12, 130, 234, 174, 180, 154, 99, 73, 229, 66, 228, 21,
183, 200, 6, 112, 157, 65, 117, 25, 201, 170, 252, 77, 191, 42, 115,
132, 213, 195, 175, 43, 134, 167, 177, 178, 91, 70, 211, 159, 253,
212, 15, 156, 47, 155, 67, 239, 217, 121, 182, 83, 127, 193, 240, 35,
231, 37, 94, 181, 30, 162, 223, 166, 254, 172, 34, 249, 226, 74, 188,
53, 202, 238, 120, 5, 107, 81, 225, 89, 163, 242, 113, 86, 17, 106,
137, 148, 101, 140, 187, 119, 60, 123, 40, 171, 210, 49, 222, 196, 95,
204, 207, 118, 44, 184, 216, 46, 54, 219, 105, 179, 20, 149, 190, 98,
161, 59, 22, 102, 233, 92, 108, 109, 173, 55, 97, 75, 185, 227, 186,
241, 160, 133, 131, 218, 71, 197, 176, 51, 250, 150, 111, 110, 194,
246, 80, 255, 93, 169, 142, 23, 27, 151, 125, 236, 88, 247, 31, 251,
124, 9, 13, 122, 103, 69, 135, 220, 232, 79, 29, 78, 4, 235, 248, 243,
62, 61, 189, 138, 136, 221, 205, 11, 19, 152, 2, 147, 128, 144, 208,
36, 52, 203, 237, 244, 206, 153, 16, 68, 64, 146, 58, 1, 38, 18, 26,
72, 104, 245, 129, 139, 199, 214, 32, 10, 8, 0, 76, 215, 116]
# Нелинейное преобразование (шифр простой замены)
def nonlinear_transformation(num, move = 'straight'):
for i in range(16):
# Выбор таблицы для хода
if move == 'reverse':
nonlinear_table = nonlinear_coef_reverse
else:
nonlinear_table = nonlinear_coef
# Выборка пары цифр, которые будут заменены в соответствии
# с таблицей `nonlinear_coef` или `nonlinear_coef_reverse`
num_for_replace = num[i * 2 : i * 2 + 2]
# Преобразование числа через таблицы хода
convert_num = convert_base(num_for_replace, to_base = 10, from_base = 16)
num_for_replace = convert_base(nonlinear_table[int(convert_num)], to_base = 16, from_base = 10)
if len(num_for_replace) == 1:
num_for_replace = '0' + num_for_replace
# Возврат числа
num = num[: i * 2] + num_for_replace + num[i * 2 + 2:]
return num
X = xor_func # операция XOR
S = nonlinear_transformation # нелинейное преобразование в режиме простой замены
L = linear_transformation # линейное преобразование
# Ключ шифрования должен быть задан в 16-ричной системе счисления
# key = '7766554433221100FFEEDDCCBBAA9988EFCDAB89674523011032547698BADCFE'
#
def utf8ToHex(text):
text = binascii.hexlify(text.encode('utf8')).decode('utf8')
return text
def transformKey(key):
key = binascii.hexlify(key.encode('utf8')).decode('utf8')
count = 64 - len(key) % 64
while len(key) < 64:
key += key
return key[:64]
# turn text from hex to utf8
def hexToUtf8(text):
try:
text = binascii.unhexlify(text).decode('utf8')
except:
pass
return text
def getKeys(key):
C = [] # константы
F = [] # ячейки Фейстеля
K = [key[:int(len(key) / 2)], key[int(len(key) / 2) :]]
for i in range(32):
if len(hex(i + 1)[2:]) == 1:
C.append(L('0' + hex(i + 1)[2:] + '000000000000000000000000000000').upper())
else:
C.append(L(hex(i + 1)[2:] + '000000000000000000000000000000').upper())
# формирование ячеек Фейстеля
F.append([ K[1], X(L(S(X( K[0], C[0]))), K[1])])
for i in range(32):
K = [ F[i][1], X(L(S(X( F[i][0], C[i]))), F[i][1])]
F.append(K)
# разбиение заданного ключа пополам
K = [key[:int(len(key) / 2)], key[int(len(key) / 2) :]]
# формирование новых ключей из ячеек Фейстеля
for i in range(len(F)):
if (i + 1) % 8 == 0:
K.append(F[i][0])
K.append(F[i][1])
return (K)
# Расшифровка текста
def encrypt(text, K):
text = utf8ToHex(text)
count = 32 - len(text) % 32
if count != 0 and count != 32:
for i in range(count):
text += '0'
textArray = []
for i in range(int(len(text) / 32)):
textArray.append(text[i * 32 : i * 32 + 32])
textEncrypt = []
for j in textArray:
# шифрование текста
textEncrypted = j
for i in range(9):
textEncrypted = L(S(X(textEncrypted, K[i])))
textEncrypted = X(textEncrypted, K[9])
textEncrypt.append(textEncrypted)
return(''.join(textEncrypt))
# Шифрование текста
def decrypt(text, K):
textArray = []
for i in range(int(len(text) / 32)):
textArray.append(text[i * 32 : i * 32 + 32])
textDecrypt = []
for j in textArray:
# расшифровка текста
textDecrypted = j
for i in range(9, 0, -1):
textDecrypted = S(L(X(textDecrypted, K[i]), 'reverse'), 'reverse')
textDecrypted = X(textDecrypted, K[0])
textDecrypt.append(textDecrypted)
return(hexToUtf8(''.join(textDecrypt)))
# Функция text_to_hex принимает текстовую строку и кодирует ее
# в формат UTF-8, а затем преобразует в шестнадцатеричное представление.
def text_to_hex(text):
hex_value = text.encode('utf-8').hex()
return hex_value
# Функция add_padding добавляет нули к шестнадцатеричной строке до тех пор,
# пока ее длина не станет равной 32 символам, что соответствует 128 битам.
def add_padding(hex_value):
while len(hex_value) < 32:
hex_value += '0'
return hex_value
# Функция hex_to_text принимает шестнадцатеричную строку и декодирует ее
# обратно в текстовую строку.
def hex_to_text(hex_value):
text = bytes.fromhex(hex_value).decode('utf-8')
return text
# Функция main является точкой входа в программу.
# Она запрашивает у пользователя ввод текста, затем преобразует его
# в шестнадцатеричное представление,
# добавляет нули при необходимости, выводит исходную шестнадцатеричную строку,
# количество добавленных нулей, а затем конвертирует обратно в текст и выводит его.
def main():
text = input("Введите текст: ")
hex_value = text_to_hex(text)
original_length = len(hex_value)
padded_hex_value = add_padding(hex_value)
padded_length = len(padded_hex_value)
if padded_length > 32:
excess = padded_length - 32
padded_hex_value = padded_hex_value[:-excess]
padded_length = len(padded_hex_value)
converted_text = hex_to_text(padded_hex_value)
textInput = padded_hex_value # Ввод исходного текста
print( "Сообщение в 16ичной системе: \n",textInput)
#password = "strongPassword" # Ввод пароля
# Получение ключей для шифрования и расшифрования
K = getKeys('8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef')
K= input("Введите ключ: ")
print( "Ключ: \n",K)
# Шифрование
textEncrypt = encrypt(textInput, K)
print(" \n Зашифрованный текст: \n", textEncrypt)
print(" \n Исходный текст в шестнадцатеричном формате: \n", padded_hex_value)
# Расшифрование
textDecrypt = decrypt(textEncrypt, K)
converted_text = hex_to_text(textDecrypt)
print("\n Расшифрованный текст: \n", converted_text)
if __name__ == "__main__":
main()
Ссылки:
Информация которая помогла в написании кода и пример на java