Created
April 12, 2012 19:06
-
-
Save islamgulov/2370185 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding:utf-8 -*- | |
class GostCrypt(object): | |
def __init__(self, key, sbox): | |
assert self._bit_length(key) <= 256 | |
self._key = None | |
self._subkeys = None | |
self.key = key | |
self.sbox = sbox | |
@staticmethod | |
def _bit_length(value): | |
return len(bin(value)[2:]) #удаляем '0b' в начале, кастыль | |
@property | |
def key(self): | |
return self._key | |
@key.setter | |
def key(self, key): | |
assert self._bit_length(key) <= 256 | |
#Для генераций подключей исходный 256-битный ключ разбивается на восемь 32-битных блоков: K1…K8. | |
self._key = key | |
self._subkeys = [(key >> (32 * i)) & 0xFFFFFFFF for i in range(8)] #8 кусков | |
def _f(self, part, key): | |
"""Функция шифрования (выполняется в раудах)""" | |
assert self._bit_length(part) <= 32 | |
assert self._bit_length(part) <= 32 | |
temp = part ^ key #складываем по модулю | |
if temp >= 2**32: | |
temp -= 2**32 | |
output = 0 | |
#разбиваем по 4бита | |
#в рез-те sbox[i][j] где i-номер шага, j-значение 4битного куска i шага | |
#выходы всех восьми S-блоков объединяются в 32-битное слово | |
for i in range(8): | |
output |= ((self.sbox[i][(temp >> (4 * i)) & 0b1111]) << (4 * i)) | |
#всё слово циклически сдвигается влево (к старшим разрядам) на 11 битов. | |
return ((output >> 11) | (output << (32 - 11))) & 0xFFFFFFFF | |
def _decrypt_round(self, left_part, right_part, round_key): | |
return left_part, right_part ^ self._f(left_part, round_key) | |
def _split(self, data): | |
"""делит data на блоки по 64 бита""" | |
result = [] | |
i = 0 | |
while self._bit_length(data) > 64*i: | |
t = (data>>64*i) & (2**64-1) | |
result.append(t) | |
i += 1 | |
return result | |
def encrypt(self, plain_msg): | |
"""Шифрование исходного сообщения""" | |
def _encrypt_round(left_part, right_part, round_key): | |
result = right_part, left_part ^ self._f(right_part, round_key) | |
#print (result[0] << 32) | result[1] | |
return result | |
assert isinstance(plain_msg, (int, long)) | |
if self._bit_length(plain_msg) > 64: | |
result = 0 | |
res_test = 0 | |
for i, msg in enumerate(self._split(plain_msg)): | |
t = self.encrypt(msg) | |
result |= t << 64*i | |
print 'encrypt part', i, t | |
return result | |
#открытый текст сначала разбивается на две половины | |
#(младшие биты — rigth_path, старшие биты — left_path) | |
left_part = plain_msg >> 32 | |
right_part = plain_msg & 0xFFFFFFFF | |
#Выполняем 32 рауда со своим подключом Ki | |
#Ключи K1…K24 являются циклическим повторением ключей K1…K8 (нумеруются от младших битов к старшим). | |
for i in range(24): | |
left_part, right_part = _encrypt_round(left_part, right_part, self._subkeys[i % 8]) | |
#Ключи K25…K32 являются ключами K1…K8, идущими в обратном порядке. | |
for i in range(8): | |
left_part, right_part = _encrypt_round(left_part, right_part, self._subkeys[7 - i]) | |
return (left_part << 32) | right_part #сливаем половинки вместе | |
def decrypt(self, crypted_msg): | |
"""Дешифрование криптованого сообщения | |
Расшифрование выполняется так же, как и зашифрование, но инвертируется порядок подключей Ki.""" | |
def _decrypt_round(left_part, right_part, round_key): | |
return right_part ^ self._f(left_part, round_key), left_part | |
assert isinstance(crypted_msg, (int, long)) | |
if self._bit_length(crypted_msg) > 64: | |
result = 0 | |
for i, msg in enumerate(self._split(crypted_msg)): | |
t = self.decrypt(msg) | |
print 'decrypt part', i , t | |
result |= t <<64*i | |
return result | |
left_part = crypted_msg >> 32 | |
right_part = crypted_msg & 0xFFFFFFFF | |
for i in range(8): | |
left_part, right_part = _decrypt_round(left_part, right_part, self._subkeys[i]) | |
for i in range(24): | |
left_part, right_part = _decrypt_round(left_part, right_part, self._subkeys[(7 - i) % 8]) | |
return (left_part << 32) | right_part #сливаем половинки вместе | |
def main(): | |
sbox = ( | |
(4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3), | |
(14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9), | |
(5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11), | |
(7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3), | |
(6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2), | |
(4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14), | |
(13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12), | |
(1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12), | |
) | |
key = 18318279387912387912789378912379821879387978238793278872378329832982398023031 | |
text = 11223344556677788991 | |
gost = GostCrypt(key, sbox) | |
text = (text<<64) | 88888888888881112341 | |
print 'plain text', text | |
print 'first 64bits:', text & 2**64-1 | |
print 'second 64bits', text>> 64 | |
crypted_text = gost.encrypt(text) | |
print 'crypted text', crypted_text | |
encrypted_text = gost.decrypt(crypted_text) | |
assert text == encrypted_text | |
print 'encrypted text', encrypted_text | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment