symm/ccm.h, symm/ccm-def.h: Implement the CCM authenticated encryption mode.
[catacomb] / utils / advmodes
index 42fd38b..62b4cde 100755 (executable)
@@ -377,6 +377,106 @@ def gcmgen(bc):
           (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):
@@ -433,6 +533,8 @@ intarg = struct(mk = lambda x: x, parse = int, show = None)
 
 MODEMAP = { 'eax-enc': (eaxgen, 3*[binarg] + [intarg], eaxenc),
             'eax-dec': (dummygen, 4*[binarg], eaxdec),
+            '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) }