Commit | Line | Data |
---|---|---|
b1d7b424 MW |
1 | #! /usr/bin/python |
2 | ||
3 | import catacomb as CAT | |
4 | ||
5 | I = 1 | |
6 | A = 2 | |
7 | C = 4 | |
8 | T = 8 | |
9 | M = 16 | |
10 | INIT = 256 | |
11 | ||
12 | def dump_keccak_state(what, state): | |
13 | buf = CAT.ReadBuffer(state + CAT.ByteString.zero(200 - len(state))) | |
14 | print ";; %s [round 0]" % what | |
15 | print ";; uncomplemented state..." | |
16 | for i in xrange(5): | |
17 | print ";;\t%s" % " ".join(["%016x" % buf.getu64l() for j in xrange(5)]) | |
18 | ||
19 | ||
20 | class Strobe (object): | |
21 | def __init__(me, sec = 128, _copy = None): | |
22 | if _copy is None: | |
23 | me.k = CAT.Keccak1600() | |
24 | me.r = (1600 - 2*sec)/8 | |
25 | me.f = 0 | |
26 | me.p0 = 0 | |
27 | buf = CAT.WriteBuffer() | |
28 | buf.putu8(1).putu8(me.r) | |
29 | buf.putu8(1).putu8(0) | |
30 | buf.putu8(1).putu8(12*8).put('STROBEv1.0.2') | |
31 | ##dump_keccak_state("init", buf.contents) | |
32 | me.k.mix(buf.contents).step() | |
33 | me.buf = CAT.WriteBuffer() | |
34 | me.mask = me.k.extract(me.r - 2) | |
35 | ##dump_keccak_state("final", me.mask) | |
36 | else: | |
37 | me.k = _copy.k.dup() | |
38 | me.r = _copy.r | |
39 | me.f = _copy.f | |
40 | me.p0 = _copy.p0 | |
41 | me.buf = CAT.WriteBuffer().put(_copy.buf.contents) | |
42 | me.mask = me._copy.mask | |
43 | ||
44 | def _crank(me): | |
45 | me.buf.putu8(me.p0); me.p0 = 0 | |
46 | if me.buf.size == me.r - 1: me.buf.putu8(0x84) | |
47 | else: me.buf.putu8(0x04).zero(me.r - me.buf.size - 1).putu8(0x80) | |
48 | ##dump_keccak_state("buffer", me.buf.contents) | |
49 | ##dump_keccak_state("init", me.buf.contents ^ me.k.extract(me.r)) | |
50 | me.k.mix(me.buf.contents).step() | |
51 | me.mask = me.k.extract(me.r - 2) | |
52 | ##dump_keccak_state("final", me.mask) | |
53 | me.buf = CAT.WriteBuffer() | |
54 | ||
55 | def process(me, op, input): | |
56 | if not op&T: | |
57 | opf = op | |
58 | else: | |
59 | if not me.f&INIT: me.f |= INIT | (op&I) | |
60 | opf = op ^ (me.f&255) | |
61 | me.buf.putu8(me.p0); me.p0 = me.buf.size | |
62 | if me.buf.size >= me.r - 2: me._crank() | |
63 | me.buf.putu8(opf) | |
64 | if op&C or me.buf.size >= me.r - 2: me._crank() | |
65 | ||
66 | if op&(I | T) == I or op&(I | A) == 0: buf = CAT.ByteString.zero(input) | |
67 | else: buf = CAT.ByteString(input) | |
68 | out = CAT.WriteBuffer() | |
69 | i, j, sz = 0, me.buf.size, len(buf) | |
70 | ||
71 | while i < sz: | |
72 | spare = me.r - j - 2 | |
73 | n = min(spare, sz - i); x = buf[i:i + n]; i += n | |
74 | if not op&C: out.put(x); me.buf.put(x) | |
75 | else: | |
76 | y = x ^ me.mask[j:j + n]; out.put(y) | |
77 | if op&I or not op&T: me.buf.put(y) | |
78 | else: me.buf.put(x) | |
79 | if n == spare: me._crank(); j = 0 | |
80 | ||
81 | if op&(I | A | C | T) != (I | C | T): return out.contents | |
82 | elif out.contents == CAT.ByteString.zero(out.size): return me | |
83 | else: raise ValueError, 'verify failed' | |
84 | ||
85 | st0 = Strobe() | |
86 | st1 = Strobe() | |
87 | ||
88 | st0.process(A | M, 'testing') | |
89 | st1.process(A | M, 'testing') | |
90 | ||
91 | print 'prf(10) -> %s' % hex(st0.process(I | A | C, 10)) | |
92 | st1.process(I | A | C, 10) | |
93 | ||
94 | print 'ad("Hello")' | |
95 | st0.process(A, 'Hello') | |
96 | st1.process(A, 'Hello') | |
97 | ||
98 | c0 = st0.process(A | C | T, 'World'); | |
99 | st1.process(I | A | C | T, c0) | |
100 | print 'encout("World") -> %s' % hex(c0) | |
101 | ||
102 | print 'clrout("foo")' | |
103 | st0.process(A | T, 'foo'); | |
104 | st1.process(I | A | T, 'foo') | |
105 | ||
106 | print 'clrin("bar")' | |
107 | st1.process(A | T, 'bar') | |
108 | st0.process(I | A | T, 'bar') | |
109 | ||
110 | m1 = st0.process(I | A | C | T, 'baz') | |
111 | st1.process(A | C | T, m1) # backwards in time | |
112 | print 'encin("baz") -> %s' % hex(m1) | |
113 | ||
114 | for i in xrange(200): | |
115 | c = st0.process(A | C | T, i*'X') | |
116 | m = st1.process(I | A | C | T, c) | |
117 | print " 0 encout\n\t=%s\n\t!%s;" % (i*'X', hex(c)) | |
118 | print " 1 encin\n\t!%s\n\t=%s;" % (hex(c), i*'X') | |
119 | ||
120 | r0 = st0.process(I | A | C, 123) | |
121 | r1 = st1.process(I | A | C, 123) | |
122 | print 'prf(123) -> %s' % hex(r0) | |
123 | assert r0 == r1 | |
124 | ||
125 | t = st0.process(C | T, 16) | |
126 | print 'macout(16) -> %s' % hex(t) | |
127 | st1.process(I | C | T, t) | |
128 | ||
129 | k = 'this is my super-secret key' | |
130 | print 'key("%s")' % k | |
131 | st0.process(A | C, k) | |
132 | st1.process(A | C, k) | |
133 | ||
134 | r0 = st0.process(I | A | C, 32) | |
135 | r1 = st1.process(I | A | C, 32) | |
136 | print 'prf(32) -> %s' % hex(r0) | |
137 | assert r0 == r1 | |
138 | ||
139 | print 'ratchet(32)' | |
140 | st0.process(C, 32) | |
141 | st1.process(C, 32) | |
142 | ||
143 | t0 = CAT.bytes('b2084ebdfabd50768c91eebc190132cc') | |
144 | st0.process(I | C | T, t0) | |
145 | t1 = st1.process(C | T, 16) | |
146 | assert t1 == t0 | |
147 | print 'macin(%s)' % hex(t0) |