#! /usr/bin/python
from sys import argv
-from struct import pack
+from struct import unpack, pack
from itertools import izip
import catacomb as C
return C.ByteString(m) ^ C.ByteString(y)[:len(m)]
###--------------------------------------------------------------------------
+### GCM.
+
+def gcm_mangle(x):
+ y = C.WriteBuffer()
+ for b in x:
+ b = ord(b)
+ bb = 0
+ for i in xrange(8):
+ bb <<= 1
+ if b&1: bb |= 1
+ b >>= 1
+ y.putu8(bb)
+ return C.ByteString(y)
+
+def gcm_mul(x, y):
+ w = len(x)
+ p = poly(8*w)
+ u, v = C.GF.loadl(gcm_mangle(x)), C.GF.loadl(gcm_mangle(y))
+ z = (u*v)%p
+ return gcm_mangle(z.storel(w))
+
+def gcm_pow(x, n):
+ w = len(x)
+ p = poly(8*w)
+ u = C.GF.loadl(gcm_mangle(x))
+ z = pow(u, n, p)
+ return gcm_mangle(z.storel(w))
+
+def gcm_ctr(E, m, c0):
+ y = C.WriteBuffer()
+ pre = c0[:-4]
+ c, = unpack('>L', c0[-4:])
+ while y.size < len(m):
+ c += 1
+ y.put(E.encrypt(pre + pack('>L', c)))
+ return C.ByteString(m) ^ C.ByteString(y)[:len(m)]
+
+def g(what, x, m, a0 = None):
+ n = len(x)
+ if a0 is None: a = Z(n)
+ else: a = a0
+ i = 0
+ for b in blocks0(m, n)[0]:
+ a = gcm_mul(a ^ b, x)
+ if VERBOSE: print '%s[%d] = %s -> %s' % (what, i, hex(b), hex(a))
+ i += 1
+ return a
+
+def gcm_pad(w, x):
+ return C.ByteString(x + Z(-len(x)%w))
+
+def gcm_lens(w, a, b):
+ if w < 12: n = w
+ else: n = w/2
+ return C.ByteString(C.MP(a).storeb(n) + C.MP(b).storeb(n))
+
+def ghash(whata, whatb, x, a, b):
+ w = len(x)
+ ha = g(whata, x, gcm_pad(w, a))
+ hb = g(whatb, x, gcm_pad(w, b))
+ if a:
+ hc = gcm_mul(ha, gcm_pow(x, (len(b) + w - 1)/w)) ^ hb
+ if VERBOSE: print '%s || %s -> %s' % (whata, whatb, hex(hc))
+ else:
+ hc = hb
+ return g(whatb, x, gcm_lens(w, 8*len(a), 8*len(b)), hc)
+
+def gcmenc(E, n, h, m, tsz = None):
+ w = E.__class__.blksz
+ x = E.encrypt(Z(w))
+ if VERBOSE: print 'x = %s' % hex(x)
+ if len(n) + 4 == w: c0 = C.ByteString(n + pack('>L', 1))
+ else: c0 = ghash('?', 'n', x, EMPTY, n)
+ if VERBOSE: print 'c0 = %s' % hex(c0)
+ y = gcm_ctr(E, m, c0)
+ t = ghash('h', 'y', x, h, y) ^ E.encrypt(c0)
+ return y, t
+
+def gcmdec(E, n, h, y, t):
+ w = E.__class__.blksz
+ x = E.encrypt(Z(w))
+ if VERBOSE: print 'x = %s' % hex(x)
+ if len(n) + 4 == w: c0 = C.ByteString(n + pack('>L', 1))
+ else: c0 = ghash('?', 'n', x, EMPTY, n)
+ if VERBOSE: print 'c0 = %s' % hex(c0)
+ m = gcm_ctr(E, y, c0)
+ tt = ghash('h', 'y', x, h, y) ^ E.encrypt(c0)
+ if t == tt: return m,
+ else: return None,
+
+def gcmgen(bc):
+ return [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1),
+ (bc.blksz, 3*bc.blksz, 3*bc.blksz),
+ (bc.blksz - 4, bc.blksz + 3, 3*bc.blksz + 9),
+ (bc.blksz - 1, 3*bc.blksz - 5, 3*bc.blksz + 5)]
+
+###--------------------------------------------------------------------------
+### CCM.
+
+def stbe(n, w): return C.MP(n).storeb(w)
+
+def ccm_fmthdr(blksz, n, hsz, msz, tsz):
+ b = C.WriteBuffer()
+ if blksz == 8:
+ q = blksz - len(n) - 1
+ f = 0
+ if hsz: f |= 0x40
+ f |= (tsz - 1) << 3
+ f |= q - 1
+ b.putu8(f).put(n).put(stbe(msz, q))
+ elif blksz == 16:
+ q = blksz - len(n) - 1
+ f = 0
+ if hsz: f |= 0x40
+ f |= (tsz - 2)/2 << 3
+ f |= q - 1
+ b.putu8(f).put(n).put(stbe(msz, q))
+ else:
+ q = blksz - len(n) - 2
+ f0 = f1 = 0
+ if hsz: f1 |= 0x80
+ f0 |= tsz
+ f1 |= q
+ b.putu8(f0).putu8(f1).put(n).put(stbe(msz, q))
+ b = C.ByteString(b)
+ if VERBOSE: print 'hdr = %s' % hex(b)
+ return b
+
+def ccm_fmtctr(blksz, n, i = 0):
+ b = C.WriteBuffer()
+ if blksz == 8 or blksz == 16:
+ q = blksz - len(n) - 1
+ b.putu8(q - 1).put(n).put(stbe(i, q))
+ else:
+ q = blksz - len(n) - 2
+ b.putu8(0).putu8(q).put(n).put(stbe(i, q))
+ b = C.ByteString(b)
+ if VERBOSE: print 'ctr = %s' % hex(b)
+ return b
+
+def ccmaad(b, h, blksz):
+ hsz = len(h)
+ if not hsz: pass
+ elif hsz < 0xfffe: b.putu16(hsz)
+ elif hsz <= 0xffffffff: b.putu16(0xfffe).putu32(hsz)
+ else: b.putu16(0xffff).putu64(hsz)
+ b.put(h); b.zero((-b.size)%blksz)
+
+def ccmenc(E, n, h, m, tsz = None):
+ blksz = E.__class__.blksz
+ if tsz is None: tsz = blksz
+ b = C.WriteBuffer()
+ b.put(ccm_fmthdr(blksz, n, len(h), len(m), tsz))
+ ccmaad(b, h, blksz)
+ b.put(m); b.zero((-b.size)%blksz)
+ b = C.ByteString(b)
+ a = Z(blksz)
+ v, _ = blocks0(b, blksz)
+ i = 0
+ for x in v:
+ a = E.encrypt(a ^ x)
+ if VERBOSE:
+ print 'b[%d] = %s' % (i, hex(x))
+ print 'a[%d] = %s' % (i + 1, hex(a))
+ i += 1
+ y = ctr(E, a + m, ccm_fmtctr(blksz, n))
+ return C.ByteString(y[blksz:]), C.ByteString(y[0:tsz])
+
+def ccmdec(E, n, h, y, t):
+ blksz = E.__class__.blksz
+ tsz = len(t)
+ b = C.WriteBuffer()
+ b.put(ccm_fmthdr(blksz, n, len(h), len(y), tsz))
+ ccmaad(b, h, blksz)
+ mm = ctr(E, t + Z(blksz - tsz) + y, ccm_fmtctr(blksz, n))
+ u, m = C.ByteString(mm[0:tsz]), C.ByteString(mm[blksz:])
+ b.put(m); b.zero((-b.size)%blksz)
+ b = C.ByteString(b)
+ a = Z(blksz)
+ v, _ = blocks0(b, blksz)
+ i = 0
+ for x in v:
+ a = E.encrypt(a ^ x)
+ if VERBOSE:
+ print 'b[%d] = %s' % (i, hex(x))
+ print 'a[%d] = %s' % (i + 1, hex(a))
+ i += 1
+ if u == a[:tsz]: return m,
+ else: return None,
+
+def ccmgen(bc):
+ bsz = bc.blksz
+ return [(bsz - 5, 0, 0, 4), (bsz - 5, 1, 0, 4), (bsz - 5, 0, 1, 4),
+ (bsz/2 + 1, 3*bc.blksz, 3*bc.blksz),
+ (bsz/2 + 1, 3*bc.blksz - 5, 3*bc.blksz + 5)]
+
+###--------------------------------------------------------------------------
### EAX.
def eaxenc(E, n, h, m, tsz = None):
MODEMAP = { 'eax-enc': (eaxgen, 3*[binarg] + [intarg], eaxenc),
'eax-dec': (dummygen, 4*[binarg], eaxdec),
- 'cmac': (cmacgen, [binarg], cmac) }
+ 'ccm-enc': (ccmgen, 3*[binarg] + [intarg], ccmenc),
+ 'ccm-dec': (dummygen, 4*[binarg], ccmdec),
+ 'cmac': (cmacgen, [binarg], cmac),
+ 'gcm-enc': (gcmgen, 3*[binarg] + [intarg], gcmenc),
+ 'gcm-dec': (dummygen, 4*[binarg], gcmdec) }
mode = argv[1]
bc = None