Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from binascii import hexlify, unhexlify
- ROUNDS = 8
- KEYLEN = (6 * ROUNDS + 4)
- # For example: bytelist_to_debugstr([255, 0, 192]) -> "[FF 00 C0]".
- def bytelist_to_debugstr(bytelist):
- assert isinstance(bytelist, (list, tuple))
- return "[" + " ".join(f"{b:02X}" for b in bytelist) + "]"
- # Returns x + y modulo 2^16. Inputs and output are uint16.
- def add(x, y):
- assert 0 <= x <= 0xFFFF
- assert 0 <= y <= 0xFFFF
- return (x + y) & 0xFFFF
- # Returns x * y modulo (2^16 + 1), where 0x0000 is treated as 0x10000.
- # Inputs and output are uint16. Note that 2^16 + 1 is prime..
- def multiply(x, y):
- assert 0 <= x <= 0xFFFF
- assert 0 <= y <= 0xFFFF
- if x == 0x0000:
- x = 0x10000
- if y == 0x0000:
- y = 0x10000
- z = (x * y) % 0x10001
- if z == 0x10000:
- z = 0x0000
- assert 0 <= z <= 0xFFFF
- return z
- # Returns the additive inverse of x modulo 2^16.
- # Input and output are uint16. Only used by _invert_key_schedule().
- def negate(x):
- assert 0 <= x <= 0xFFFF
- return (-x) & 0xFFFF
- # Returns the multiplicative inverse of x modulo (2^16 + 1), where 0x0000 is
- # treated as 0x10000. Input and output are uint16. Only used by _invert_key_schedule().
- def reciprocal(x):
- assert 0 <= x <= 0xFFFF
- if x == 0:
- return 0
- else:
- return pow(x, 0xFFFF, 0x10001) # By Fermat's little theorem
- def make_enc_keys(key):
- bigKey = 0
- for byte in key:
- bigKey = (bigKey << 8) | byte
- bigKey = (bigKey << 16) | (bigKey >> 112)
- enc_keys = []
- for i in range(KEYLEN):
- offset = (i * 16 + i // 8 * 25) % 128
- enc_keys.append((bigKey >> (128 - offset)) & 0xffff)
- return tuple(enc_keys)
- def make_dec_keys(enc_keys):
- dec_keys = []
- dec_keys.append(reciprocal(enc_keys[-4]))
- dec_keys.append(negate(enc_keys[-3]))
- dec_keys.append(negate(enc_keys[-2]))
- dec_keys.append(reciprocal(enc_keys[-1]))
- dec_keys.append(enc_keys[-6])
- dec_keys.append(enc_keys[-5])
- for i in range(1, ROUNDS):
- j = i * 6
- dec_keys.append(reciprocal(enc_keys[-j - 4]))
- dec_keys.append(negate(enc_keys[-j - 2]))
- dec_keys.append(negate(enc_keys[-j - 3]))
- dec_keys.append(reciprocal(enc_keys[-j - 1]))
- dec_keys.append(enc_keys[-j - 6])
- dec_keys.append(enc_keys[-j - 5])
- dec_keys.append(reciprocal(enc_keys[0]))
- dec_keys.append(negate(enc_keys[1]))
- dec_keys.append(negate(enc_keys[2]))
- dec_keys.append(reciprocal(enc_keys[3]))
- return tuple(dec_keys)
- def idea_crypt(block, key, mode, printdebug = False):
- # Check input arguments
- assert isinstance(block, list) and len(block) == 8
- assert isinstance(key, list) and len(key) == 16
- assert mode in ("encrypt", "decrypt")
- if printdebug: print(f"ideacipher.{mode}(block = {bytelist_to_debugstr(block)}, key = {bytelist_to_debugstr(key)})")
- # Compute and handle the key schedule
- keyschedule = make_enc_keys(key)
- if mode == "decrypt":
- keyschedule = make_dec_keys(keyschedule)
- # print(keys)
- # Pack block bytes into variables as uint16 in big endian
- w = block[0] << 8 | block[1]
- x = block[2] << 8 | block[3]
- y = block[4] << 8 | block[5]
- z = block[6] << 8 | block[7]
- # Perform 8 rounds of encryption/decryption
- for i in range(ROUNDS):
- if printdebug: print(f" Round {i}: block = [{w:04} {x:04} {y:04} {z:04}]")
- j = i * 6
- w = multiply(w, keyschedule[j + 0])
- x = add(x, keyschedule[j + 1])
- y = add(y, keyschedule[j + 2])
- z = multiply(z, keyschedule[j + 3])
- u = multiply(w ^ y, keyschedule[j + 4])
- v = multiply(add(x ^ z, u), keyschedule[j + 5])
- u = add(u, v)
- w ^= v
- x ^= u
- y ^= v
- z ^= u
- x, y = y, x
- # Perform final half-round
- if printdebug: print(f" Round {ROUNDS}: block = [{w:04} {x:04} {y:04} {z:04}]")
- x, y = y, x
- w = multiply(w, keyschedule[-4])
- x = add(x, keyschedule[-3])
- y = add(y, keyschedule[-2])
- z = multiply(z, keyschedule[-1])
- # Serialize the final block as a bytelist in big endian
- return [
- w >> 8, w & 0xFF,
- x >> 8, x & 0xFF,
- y >> 8, y & 0xFF,
- z >> 8, z & 0xFF]
- #1000, 2000, 3000, 4000, 4000, 3000, 2000, 1000 = b'\x03\xe8\x07\xd0\x0b\xb8\x0f\xa0\x0f\xa0\x0b\xb8\x07\xd0\x03\xe8'
- key = b'\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08'
- block = b'\x00\x00\x00\x01\x00\x02\x00\x03'
- cipher = idea_crypt(list(block), list(key), "encrypt", True)
- print(f"block = [{cipher[0]:04} {cipher[1]:04} {cipher[2]:04} {cipher[3]:04}]")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement