def GHASH64(H, A, C, X, i): n = len(C) m = len(A) if i <= m: # A1 = A[1-1] return gz2.poly_mult_mod_2( bm.bytes_to_int(bm.b_op(X, A[i - 1], "XOR")), H, p) if i <= m + n: return gz2.poly_mult_mod_2( bm.bytes_to_int(bm.b_op(X, C[i - m - 1], "XOR")), H, p) if i == m + n + 1: return gz2.poly_mult_mod_2( a=bm.bytes_to_int( bm.b_op( b1=gz2.poly_mult_mod_2( bm.bytes_to_int(bm.b_op(X, lenb(A), "XOR")), H, p).to_bytes(8, "big"), b2=lenb(C), ope="XOR", )), b=H, mod=p, )
def FO(pKO, pKI, arr): if len(arr) != 4: raise ValueError("FO takes 32 bits as 4 bytes array in input") arr = bm.splitBytes(arr, 2) left = arr[0] right = arr[1] for i in range(0, 3): left = right right = bm.b_op(right, FI(bm.b_op(left, pKO[i], "XOR"), pKI[i]), "XOR") return left + right
def kasumi(arr, encrypt=True): if len(arr) > 8: raise ValueError("Error: Kasumi takes 64 bits as 8 bytes array in input") config.WATCH_KASUMI_NUMBER += 1 exTime = time.time() arr = bm.splitBytes(arr, 4) left = arr[0] right = arr[1] for i in range(0, 8): if not encrypt: i = 7 - i KO = [config.KO1[i], config.KO2[i], config.KO3[i]] KI = [config.KI1[i], config.KI2[i], config.KI3[i]] KL = [config.KL1[i], config.KL2[i]] lp = left if i % 2 == 0: left = FL(KL, FO(KO, KI, left)) else: left = FO(KO, KI, FL(KL, left)) left = bm.b_op(left, right, "XOR") right = lp config.WATCH_GLOBAL_KASUMI += time.time() - exTime return right + left
def FL(pKL, arr): if len(arr) != 4: raise ValueError("FL takes 32 bits as 4 bytes array in input") arr = bm.splitBytes(arr, 2) left = arr[0] right = arr[1] rp = bm.b_op(bm.circularRotation(bm.b_op(left, pKL[0], "AND"), 0, 1), right, "XOR") lp = bm.b_op(bm.circularRotation(bm.b_op(rp, pKL[1], "OR"), 0, 1), left, "XOR") # Inverted in Galois Field lp = invertGalois2(lp) rp = invertGalois2(rp) return lp + rp
def FI(b1, pKI): b1 = bm.circularRotation(b1, 1, 2) z = bm.splitBytes(pKI, 1) subZ1 = S1[int.from_bytes(z[0], "big")].to_bytes(1, "big") subZ2 = S2[int.from_bytes(z[1], "big")].to_bytes(1, "big") return bm.b_op(b1, subZ1 + subZ2, "XOR")
def CBC(arr, encrypt=True): """In CBC mode, each block of plaintext is XORed with the previous ciphertext block before being encrypted. """ # Initialisation Vector if encrypt: iv = IV(arr) else: iv = IV_action(arr) res = [] for i, message in enumerate(arr): config.WATCH_PERCENTAGE = ((len(arr) - (len(arr) - i)) / len(arr)) * 100 exTime = time.time() if i == 0: # Initialization if encrypt: res.append(kasu.kasumi(bm.b_op(iv, message, "XOR"))) else: res.append(bm.b_op(kasu.kasumi(message, False), iv, "XOR")) else: if encrypt: res.append(kasu.kasumi(bm.b_op(res[i - 1], message, "XOR"))) else: res.append( bm.b_op(kasu.kasumi(message, False), arr[i - 1], "XOR")) config.WATCH_GLOBAL_CIPHER += time.time() - exTime config.WATCH_BLOC_CIPHER = config.WATCH_GLOBAL_CIPHER / (i + 1) config.WATCH_BLOC_KASUMI = config.WATCH_GLOBAL_KASUMI / (i + 1) if encrypt: # Adding the IV to the encrypted data res = IV_action(res, iv, "store") return res
def CTR(arr, encrypt=True): """ Counter Mode is xoring the message with a encrypted counter (IV + incr(0)) arr: array of bytearray of 8 bytes of data to encrypt/decrypt encrypt: true to encrypt """ if encrypt: iv = IV(arr) else: iv = IV_action(arr) res = [] for i, message in enumerate(arr): config.WATCH_PERCENTAGE = ((len(arr) - (len(arr) - i)) / len(arr)) * 100 exTime = time.time() noc = bm.b_op(iv, (i + 1).to_bytes(8, "big"), "XOR") kas = kasu.kasumi(noc, True) coded = bm.b_op(message, kas, "XOR") res.append(coded) config.WATCH_GLOBAL_CIPHER += time.time() - exTime config.WATCH_BLOC_CIPHER = config.WATCH_GLOBAL_CIPHER / (i + 1) config.WATCH_BLOC_KASUMI = config.WATCH_GLOBAL_KASUMI / (i + 1) if encrypt: # Adding the IV to the encrypted data IV_action(res, iv, "store") return res
def sponge(N: bytearray, d: int): """ Sponge construction for hash functions. N: Thing to hash \n d: size of hash wanted \n return bytearray """ def pad(N, r): iN = bm.bytes_to_int(N) lN = int.bit_length(iN) # Number of 0 to add b = (r - ((lN + 3) % r)) % r # Padding using the SHA-3 pattern 10*1: a 1 bit, followed by zero or more 0 bits (maximum r − 1) and a final 1 bit. op = ((iN | (1 << b + lN + 1)) << 1) ^ 1 return bm.mult_to_bytes(op) r = 8 d = int(d / 8) blocks = bm.splitBytes(pad(N, r * 8), r) S = bytearray(16) # Absorbing for block in blocks: S[:r] = bm.b_op(S[:r], block) S = md5(S) O = bytearray() # Squeezing while len(O) < d: O += S[:r] S = md5(S) # Truncating with the desired length return O[:d]
def set_key(km=config.KEY): """Kasumi's keyscheduler.""" # Chosen as a "nothing up my sleeve" number nums = b"\x124Vx\x9a\xbc\xde\xff\xed\xcb\xa9\x87eC!\x00" # Additionally a modified key K', similarly divided into 16-bit sub keys K'i, is used. kp = bm.b_op(km, nums, "XOR") # The 128-bit key K is divided into eight 16-bit sub keys Ki skm, skp = bm.splitBytes(km, 2), bm.splitBytes(kp, 2) config.KL1 = [bytearray(bm.circularRotation(skm[x], 0, 1)) for x in range(0, 8)] config.KL2 = [skp[(x + 2) % 8] for x in range(0, 8)] config.KO1 = [bytearray(bm.circularRotation(skm[(x + 1) % 8], 0, 5)) for x in range(0, 8)] config.KO2 = [bytearray(bm.circularRotation(skm[(x + 5) % 8], 0, 8)) for x in range(0, 8)] config.KO3 = [bytearray(bm.circularRotation(skm[(x + 6) % 8], 0, 13)) for x in range(0, 8)] config.KI1 = [skp[(x + 4) % 8] for x in range(0, 8)] config.KI2 = [skp[(x + 3) % 8] for x in range(0, 8)] config.KI3 = [skp[(x + 7) % 8] for x in range(0, 8)] # SBoxes initialization considering the given master key ! initRC4(km)
def GCM(arr, encrypt=True, aad=""): """ GCM is CTR mode with authentification of additional data (AAD) authenticated with multiplication in a Galois Field arr: array of bytearray of 8 bytes of data to encrypt/decrypt encrypt: boolean, true to encypt aad: string of additional authenticated data """ if encrypt: iv = IV(arr) else: iv = IV_action(arr) # Integrity Check Balue icv = IV_action(arr) # Additional authenticated data (AAD), which is denoted as A A = [] if encrypt: if aad != "": aadc = aad.encode() if len(aadc) > 1 << 64: raise Exception("Too much AAD") A = bm.splitBytes(aadc, 8) A[-1] = bm.zfill_b(A[-1], 8) else: header = arr[0] epos = int.from_bytes(header, "big") A = arr[1:epos] arr = arr[epos:] # Encrypted message C = [] # 1 + α + α3 + α4 + α64 - 64 field polynomial p = int( "10000000000000000000000000000000000000000000000000000000000001111", 2) def lenb(i): return (len(i) * 8).to_bytes(8, "big") def GHASH64(H, A, C, X, i): n = len(C) m = len(A) if i <= m: # A1 = A[1-1] return gz2.poly_mult_mod_2( bm.bytes_to_int(bm.b_op(X, A[i - 1], "XOR")), H, p) if i <= m + n: return gz2.poly_mult_mod_2( bm.bytes_to_int(bm.b_op(X, C[i - m - 1], "XOR")), H, p) if i == m + n + 1: return gz2.poly_mult_mod_2( a=bm.bytes_to_int( bm.b_op( b1=gz2.poly_mult_mod_2( bm.bytes_to_int(bm.b_op(X, lenb(A), "XOR")), H, p).to_bytes(8, "big"), b2=lenb(C), ope="XOR", )), b=H, mod=p, ) H = bm.bytes_to_int(kasu.kasumi(b"\x00" * 8)) Y = GHASH64(H, b"", [iv], b"\x00", 1).to_bytes(8, "big") E0 = kasu.kasumi(Y) n = len(arr) m = len(A) # equivalent of CTR mode for i in range(n): config.WATCH_PERCENTAGE = (((n * 2 + m + 1) - ((n * 2 + m + 1) - i)) / (n * 2 + m + 1)) * 100 exTime = time.time() # treats the rightmost 32bits of its argument as a nonnegative integer with the least significant bit on the right, and increments this value modulo 2^32 Y = Y[:4] + ( (int.from_bytes(Y[-4:], "big") + 1) % 1 << 32).to_bytes(4, "big") E = kasu.kasumi(Y) C.append(bm.b_op(arr[i], E, "XOR")) config.WATCH_GLOBAL_CIPHER += time.time() - exTime config.WATCH_BLOC_CIPHER = config.WATCH_GLOBAL_CIPHER / (i + 1) config.WATCH_BLOC_KASUMI = config.WATCH_GLOBAL_KASUMI / (i + 1) res = C # plaintext is in C when we decrypt, me must replace it with the ciphertext if not encrypt: C = arr # first init of X = GHASH64(i=0) = b'\x00' X = b"\x00" for i in range(n + m + 1): config.WATCH_PERCENTAGE = (((n * 2 + m + 1) - ((n * 2 + m + 1) - (i + n))) / (n * 2 + m + 1)) * 100 exTime = time.time() X = GHASH64(H, A, C, X, i + 1).to_bytes(8, "big") config.WATCH_GLOBAL_CIPHER += time.time() - exTime config.WATCH_BLOC_CIPHER = config.WATCH_GLOBAL_CIPHER / (i + 1) icvc = bm.b_op(E0, X, "XOR") if not encrypt: if icv != icvc: print( "\nYELLOW: INTEGRITY CHECK CONTROL INCORRECT, AAD HAVE BEEN MODIFIED !!" ) if encrypt: IV_action(res, icvc, "store") # Adding the IV to the encrypted data IV_action(res, iv, "store") header = (1 + len(A)).to_bytes(8, "big") res = [header] + A + res return res