def rotate_right(word, n, word_size=64): mask = 2**word_size - 1 return ((word >> n) & mask) | ((word << (word_size - n) & mask)) def next_keystate(keystate): return rotate_right(keystate ^ 0x3, 16, 64) def add_roundkey(word, keystate): return word ^ (keystate & 0xFFFFFFFF) def get_rows(word): row_0 = (word >> 48) & 0xFFFF row_1 = (word >> 32) & 0xFFFF row_2 = (word >> 16) & 0xFFFF row_3 = (word >> 0) & 0xFFFF return row_0, row_1, row_2, row_3 def mix_columns(c2): row_0, row_1, row_2, row_3 = get_rows(c2) c3 = row_0 << 48 c3 |= (row_0 ^ row_1) << 32 c3 |= (row_0 ^ row_1 ^ row_2) << 16 c3 |= (row_0 ^ row_1 ^ row_2 ^ row_3)<< 0 return c3 def rot_nib(c1): c2=(c1 << 16) | (c1 >> 48) & 0xFFFFFFFFFFFFFFFF return c2 def asbox(pt, sbox): c1 = 0 for i in range(16): nib = (pt >> (i*4)) & 0xF c1 |= (sbox[nib] << i*4) return c1 def encrypt(plaintext, key, rounds=8): sbox = [0x0,0x3,0x5,0x8,0x6,0xA,0xF,0x4,0xE,0xD,0x9,0x2,0x1,0x7,0xC,0xB] word = add_roundkey(plaintext, key) for i in range(rounds): plaintext = asbox(plaintext, sbox) plaintext = rot_nib(plaintext) plaintext = mix_columns(plaintext) plaintext = add_roundkey(plaintext, key) key = next_keystate(key) return plaintext if __name__ == "__main__": import sys import random if len(sys.argv) not in [3, 4]: print("Error occured %d"%(len(sys.argv))) exit() key = int(sys.argv[1], 16) rounds = int(sys.argv[2]) if len(sys.argv) == 4: delta_in = int(sys.argv[3], 16) nrof_pairs = 2**10 print("# %s %d rounds"%(sys.argv[0], rounds)) for i in range(nrof_pairs): word = random.getrandbits(64) cipher = encrypt(word, key, rounds=rounds) if len(sys.argv) == 3: print("%016X %016X"%(word, cipher)) else: word_2 = word ^ delta_in cipher_2 = encrypt(word_2, key, rounds=rounds) print("%016X %016X %016X %016X"%(word, word_2, cipher, cipher_2))