Commit | Line | Data |
---|---|---|
43c09851 | 1 | # -*-python-*- |
2 | ||
3 | import catacomb as _C | |
4 | import gdbm as _G | |
5 | import struct as _S | |
6 | ||
7 | class DecryptError (Exception): | |
8 | pass | |
9 | ||
10 | class Crypto (object): | |
11 | def __init__(me, c, h, m, ck, mk): | |
12 | me.c = c(ck) | |
13 | me.m = m(mk) | |
14 | me.h = h | |
15 | def encrypt(me, pt): | |
16 | if me.c.__class__.blksz: | |
17 | iv = _C.rand.block(me.c.__class__.blksz) | |
18 | me.c.setiv(iv) | |
19 | else: | |
20 | iv = '' | |
21 | y = iv + me.c.encrypt(pt) | |
22 | t = me.m().hash(y).done() | |
23 | return t + y | |
24 | def decrypt(me, ct): | |
25 | t = ct[:me.m.__class__.tagsz] | |
26 | y = ct[me.m.__class__.tagsz:] | |
27 | if t != me.m().hash(y).done(): | |
28 | raise DecryptError | |
29 | iv = y[:me.c.__class__.blksz] | |
30 | if me.c.__class__.blksz: me.c.setiv(iv) | |
31 | return me.c.decrypt(y[me.c.__class__.blksz:]) | |
b2687a0a | 32 | |
43c09851 | 33 | class PPK (Crypto): |
34 | def __init__(me, pp, c, h, m, salt = None): | |
35 | if not salt: salt = _C.rand.block(h.hashsz) | |
36 | tag = '%s\0%s' % (pp, salt) | |
37 | Crypto.__init__(me, c, h, m, | |
b2687a0a MW |
38 | h().hash('cipher:' + tag).done(), |
39 | h().hash('mac:' + tag).done()) | |
43c09851 | 40 | me.salt = salt |
41 | ||
42 | class Buffer (object): | |
43 | def __init__(me, s): | |
44 | me.str = s | |
45 | me.i = 0 | |
46 | def get(me, n): | |
47 | i = me.i | |
48 | if n + i > len(me.str): | |
49 | raise IndexError, 'buffer underflow' | |
50 | me.i += n | |
51 | return me.str[i:i + n] | |
52 | def getbyte(me): | |
53 | return ord(me.get(1)) | |
54 | def unpack(me, fmt): | |
55 | return _S.unpack(fmt, me.get(_S.calcsize(fmt))) | |
56 | def getstring(me): | |
57 | return me.get(me.unpack('>H')[0]) | |
58 | def checkend(me): | |
59 | if me.i != len(me.str): | |
60 | raise ValueError, 'junk at end of buffer' | |
61 | ||
62 | def _wrapstr(s): | |
63 | return _S.pack('>H', len(s)) + s | |
64 | ||
65 | class PWIter (object): | |
66 | def __init__(me, pw): | |
67 | me.pw = pw | |
68 | me.k = me.pw.db.firstkey() | |
69 | def next(me): | |
70 | k = me.k | |
71 | while True: | |
72 | if k is None: | |
b2687a0a | 73 | raise StopIteration |
43c09851 | 74 | if k[0] == '$': |
b2687a0a | 75 | break |
43c09851 | 76 | k = me.pw.db.nextkey(k) |
77 | me.k = me.pw.db.nextkey(k) | |
78 | return me.pw.unpack(me.pw.db[k])[0] | |
79 | class PW (object): | |
80 | def __init__(me, file, mode = 'r'): | |
81 | me.db = _G.open(file, mode) | |
82 | c = _C.gcciphers[me.db['cipher']] | |
83 | h = _C.gchashes[me.db['hash']] | |
84 | m = _C.gcmacs[me.db['mac']] | |
85 | tag = me.db['tag'] | |
86 | ppk = PPK(_C.ppread(tag), c, h, m, me.db['salt']) | |
87 | try: | |
88 | buf = Buffer(ppk.decrypt(me.db['key'])) | |
89 | except DecryptError: | |
90 | _C.ppcancel(tag) | |
91 | raise | |
92 | me.ck = buf.getstring() | |
93 | me.mk = buf.getstring() | |
94 | buf.checkend() | |
95 | me.k = Crypto(c, h, m, me.ck, me.mk) | |
96 | me.magic = me.k.decrypt(me.db['magic']) | |
97 | def keyxform(me, key): | |
98 | return '$' + me.k.h().hash(me.magic).hash(key).done() | |
99 | def changepp(me): | |
100 | tag = me.db['tag'] | |
101 | _C.ppcancel(tag) | |
102 | ppk = PPK(_C.ppread(tag, _C.PMODE_VERIFY), | |
b2687a0a | 103 | me.k.c.__class__, me.k.h, me.k.m.__class__) |
43c09851 | 104 | me.db['key'] = ppk.encrypt(_wrapstr(me.ck) + _wrapstr(me.mk)) |
105 | me.db['salt'] = ppk.salt | |
106 | def pack(me, key, value): | |
107 | w = _wrapstr(key) + _wrapstr(value) | |
108 | pl = (len(w) + 255) & ~255 | |
109 | w += '\0' * (pl - len(w)) | |
110 | return me.k.encrypt(w) | |
111 | def unpack(me, p): | |
112 | buf = Buffer(me.k.decrypt(p)) | |
113 | key = buf.getstring() | |
114 | value = buf.getstring() | |
115 | return key, value | |
116 | def __getitem__(me, key): | |
2e6a3fda | 117 | try: |
118 | return me.unpack(me.db[me.keyxform(key)])[1] | |
119 | except KeyError: | |
120 | raise KeyError, key | |
43c09851 | 121 | def __setitem__(me, key, value): |
122 | me.db[me.keyxform(key)] = me.pack(key, value) | |
123 | def __delitem__(me, key): | |
2e6a3fda | 124 | try: |
125 | del me.db[me.keyxform(key)] | |
126 | except KeyError: | |
127 | raise KeyError, key | |
43c09851 | 128 | def __iter__(me): |
129 | return PWIter(me) | |
130 |