Skip to content

Instantly share code, notes, and snippets.

@gquere

gquere/coconut98.py

Created Jun 3, 2020
Embed
What would you like to do?
#!/usr/bin/env python3
# http://lasecwww.epfl.ch/pub/lasec/doc/Vau98a.ps
import sys
from pyfinite import ffield # don't forget to patch to include your field!
# CIPHER CONSTANTS #############################################################
c = 0xb7e15162
S = [
0x8AED2A, 0x6ABF71, 0x58809C, 0x0F4F3C7, 0x62E716, 0x0F38B4, 0x0DA56A7, 0x84D904,
0x5190CF, 0x0EF324E, 0x773892, 0x6CFBE5, 0x0F4BF8D, 0x8D8C31, 0x0D763DA, 0x6C80A,
0x0BB1185, 0x0EB4F7C, 0x7B5757, 0x0F59584, 0x90CFD4, 0x7D7C19, 0x0BB4215, 0x8D9554,
0x0F7B46B, 0x0CED55C, 0x4D79FD, 0x5F24D6, 0x613C31, 0x0C3839A, 0x2DDF8A, 0x9A276B,
0x0CFBFA1, 0x0C877C5, 0x6284DA, 0x0B79CD4, 0x0C2B329, 0x3D20E9, 0x0E5EAF0, 0x2AC60A,
0x0CC93ED, 0x874422, 0x0A52ECB, 0x238FEE, 0x0E5AB6A, 0x0DD835F, 0x0D1A075, 0x3D0A8F,
0x78E537, 0x0D2B95B, 0x0B79D8D, 0x0CAEC64, 0x2C1E9F, 0x23B829, 0x0B5C278, 0x0BF387,
0x37DF8B, 0x0B300D0, 0x1334A0, 0x0D0BD86, 0x45CBFA, 0x73A616, 0x0FFE39, 0x3C48CB,
0x0BBCA06, 0x0F0FF8, 0x0EC6D31, 0x0BEB5CC, 0x0EED7F2, 0x0F0BB08, 0x801716, 0x3BC60D,
0x0F45A0E, 0x0CB1BCD, 0x289B06, 0x0CBBFEA, 0x21AD08, 0x0E1847F, 0x3F7378, 0x0D56CED,
0x94640D, 0x6EF0D3, 0x0D37BE6, 0x7008E1, 0x86D1BF, 0x275B9B, 0x241DEB, 0x64749A,
0x47DFDF, 0x0B96632, 0x0C3EB06, 0x1B6472, 0x0BBF84C, 0x26144E, 0x49C2D0, 0x4C324E,
0x0F10DE5, 0x13D3F5, 0x114B8B, 0x5D374D, 0x93CB88, 0x79C7D5, 0x2FFD72, 0x0BA0AAE,
0x7277DA, 0x7BA1B4, 0x0AF1488, 0x0D8E836, 0x0AF1486, 0x5E6C37, 0x0AB6876, 0x0FE690B,
0x571121, 0x382AF3, 0x41AFE9, 0x4F77BC, 0x0F06C83, 0x0B8FF56, 0x75F097, 0x9074AD,
0x9A787B, 0x0C5B9BD, 0x4B0C59, 0x37D3ED, 0x0E4C3A7, 0x939621, 0x5EDAB1, 0x0F57D0B,
0x5A7DB4, 0x61DD8F, 0x3C7554, 0x0D0012, 0x1FD56E, 0x95F8C7, 0x31E9C4, 0x0D7221B,
0x0BED0C6, 0x2BB5A8, 0x7804B6, 0x79A0CA, 0x0A41D80, 0x2A4604, 0x0C311B7, 0x1DE3E5,
0x0C6B400, 0x0E024A6, 0x668CCF, 0x2E2DE8, 0x6876E4, 0x0F5C500, 0x0F0A9, 0x3B3AA7,
0x0E6342B, 0x302A0A, 0x47373B, 0x25F73E, 0x3B26D5, 0x69FE22, 0x91AD36, 0x0D6A147,
0x0D1060B, 0x871A28, 0x1F978, 0x376408, 0x2FF592, 0x0D9140D, 0x0B1E939, 0x9DF4B0,
0x0E14CA8, 0x0E88EE9, 0x110B2B, 0x0D4FA98, 0x0EED150, 0x0CA6DD8, 0x932245, 0x0EF7592,
0x0C703F5, 0x32CE3A, 0x30CD31, 0x0C070EB, 0x36B419, 0x5FF33F, 0x0B1C66C, 0x7D70F9,
0x391810, 0x7CE205, 0x1FED33, 0x0F6D1DE, 0x9491C7, 0x0DEA6A5, 0x0A442E1, 0x54C8BB,
0x6D8D03, 0x62803B, 0x0C248D4, 0x14478C, 0x2AFB07, 0x0FFE78E, 0x89B9FE, 0x0CA7E30,
0x60C08F, 0x0D61F8, 0x0E36801, 0x0DF66D1, 0x0D8F939, 0x2E52CA, 0x0EF0653, 0x199479,
0x0DF2BE6, 0x4BBAAB, 0x8CA8, 0x0A06FDA, 0x0CE9CE7, 0x48984, 0x5A082B, 0x0A36D61,
0x1E99F2, 0x0FBE724, 0x246D18, 0x0B54E33, 0x5CAC0D, 0x0D1AB9D, 0x0FD7988, 0x0A4B0C4,
0x558AA1, 0x194177, 0x20B6E1, 0x50CE2B, 0x927D48, 0x0D7256E, 0x445E33, 0x3CB757,
0x2B3BD0, 0x0FB274, 0x604318, 0x9CAC11, 0x6CEDC7, 0x0E771AE, 0x358FF, 0x752A3A,
0x6B6C79, 0x0A58A9A, 0x549B50, 0x0C58706, 0x90755C, 0x35E4E3, 0x6B5290, 0x38CA73,
0x3FD1AA, 0x0A8DAB4, 0x133D8, 0x320E0, 0x790968, 0x0C76546, 0x0B993F6, 0xC8FF3B,
]
# UTILS ########################################################################
def split(val):
x = val >> 32
y = val & 0xffffffff
return x, y
# HASH FUNCTION ################################################################
# phi(x) = x + 256.S(x mod 256) mod 2^32
def phi(x):
out = x + 256 * S[x%256]
out = out%(2**32)
return out
def ROL11(x):
result = ((x << 11)%(2**32)) | (x >> 21)
return result
# g(x) = ROL11(phi(x)) + c mod 2^32
def g(x):
return (ROL11(phi(x)) + c) % (2**32)
def f(i, x):
return phi(g(x ^ k[i]))
# DECORRELATION ################################################################
def M(x, y, K):
F = ffield.FField(64)
xy = (x << 32) | y
K56 = (K_i(K, 5) << 32) | K_i(K, 6)
K78 = (K_i(K, 7) << 32) | K_i(K, 8)
#res = (xy ^ K56) * K78
res = F.Multiply(F.Add(xy, K56), K78)
return res
# KEY DERIVATION ###############################################################
def K_i(K, i):
index = (8 - i) * 8 * 4
val = K >> index
return val & 0xffffffff
def derive_K(K):
k = []
# no 0
k.append(0)
# k1 to k4
k.append(K_i(K, 1))
k.append(K_i(K, 1) ^ K_i(K, 3))
k.append(K_i(K, 1) ^ K_i(K, 3) ^ K_i(K, 4))
k.append(K_i(K, 1) ^ K_i(K, 4))
# k5 to k8
k.append(K_i(K, 2))
k.append(K_i(K, 2) ^ K_i(K, 3))
k.append(K_i(K, 2) ^ K_i(K, 3) ^ K_i(K, 4))
k.append(K_i(K, 2) ^ K_i(K, 4))
return k
def get_Kp(K):
F = ffield.FField(64)
Kp1 = F.Add(K_i(K, 2), K_i(K, 4))
Kp2 = F.Add(K_i(K, 1), K_i(K, 4))
Kp3 = (K_i(K, 3))
Kp4 = (K_i(K, 4))
K56 = (K_i(K, 5) << 32) | K_i(K, 6)
K78 = (K_i(K, 7) << 32) | K_i(K, 8)
Kp56 = F.Multiply(K56, K78)
(Kp5, Kp6) = split(Kp56)
Kp78 = F.Inverse(K78)
(Kp7, Kp8) = split(Kp78)
Kp = (Kp1 << 56 * 4) + (Kp2 << 48 * 4) + (Kp3 << 40 * 4) + (Kp4 << 32 * 4) + (Kp5 << 24 * 4) + (Kp6 << 16 * 4) + (Kp7 << 8 * 4) + Kp8
return Kp
# FEISTEL NETWORK ##############################################################
def crypt(pt):
(x, y) = split(pt)
res = f(1, y)
(x, y) = (y, res ^ x)
res = f(2, y)
(x, y) = (y, res ^ x)
res = f(3, y)
(x, y) = (y, res ^ x)
res = f(4, y)
(x, y) = (res ^ x, y)
res = M(x, y, K)
(x, y) = split(res)
res = f(5, y)
(x, y) = (y, res ^ x)
res = f(6, y)
(x, y) = (y, res ^ x)
res = f(7, y)
(x, y) = (y, res ^ x)
res = f(8, y)
(x, y) = (res ^ x, y)
ct = x << 32 | y
return ct
# MAIN #########################################################################
# TEST VECTORS ######################
K = 0x7c44a4ad56f6bb77220e96e8401694e16c469dbc516decc517929e9b226ddd64
pt = 0x6d8779e078ac5f02
expected_ct = 0x3b2ae895037910f8
# TEST VECTORS ######################
# CHALLENGE DESKTOP.INI #############
K = 0x9FA34D35072F53D1D029FBE0B518141CBAE9857AAEC563F3EFDD1B4292D2FC79
pt = 0x80952f0000000026 # good, start of real
expected_ct = 0xDC3AD2135D6C9172
#pt = 0xce11980001d60f4c ^ 0xDC3AD2135D6C9172 # good, next of real
#pt = 0x6c55c60001d6193c ^ 0xaf27807932f45a78
#pt = 0x0000000001d61517 ^ 0x853399a2b0005ac4
# CHALLENGE DESKTOP.INI #############
# crypt
k = derive_K(K)
ct = crypt(pt)
assert(ct == expected_ct)
# decrypt
K = get_Kp(K)
k = derive_K(K)
ct = crypt(ct)
assert(ct == pt)
with open(sys.argv[1], 'rb') as datafile:
data = datafile.read()
prev = 0
for i in range(0, len(data), 8):
ct = int.from_bytes(data[i:i+8], byteorder='little')
pt = crypt(ct) ^ prev
prev = ct
pt_as_hex_string = '{:016x}\t'.format(pt)
print(pt_as_hex_string)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.