Skip to content

Commit 3fd81a6

Browse files
committed
working randombytes test?
1 parent 7ef9043 commit 3fd81a6

File tree

2 files changed

+184
-17
lines changed

2 files changed

+184
-17
lines changed

dev/issue219_adaptertest.py

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python3
2+
3+
from construct import (
4+
Byte, Bytes, Checksum, Computed, Flag, GreedyBytes, GreedyString, If,
5+
IfThenElse, Int32sl, Int32ul, Int64sl, Int64ul, Mapping, Padding, Peek,
6+
Pointer, Prefixed, RepeatUntil, Struct, Switch, Tell, this,
7+
)
8+
from construct import Check, Int16ul, RawCopy, Switch, stream_write, ChecksumError, Adapter, Container, ListContainer
9+
from collections import OrderedDict
10+
from Cryptodome.Random import get_random_bytes
11+
12+
class RandomBytes(Bytes):
13+
"""Same as Bytes, but generate random bytes when building"""
14+
15+
def _build(self, obj, stream, context, path):
16+
print('generating random bytes...')
17+
length = self.length(context) if callable(self.length) else self.length
18+
data = get_random_bytes(length)
19+
print('old:', sum(context.data))
20+
print('new:', sum(data))
21+
stream_write(stream, data, length, path)
22+
return data
23+
24+
# DynamicHeaderItem = Struct(
25+
# "id" / Mapping(
26+
# Byte,
27+
# {
28+
# 'end': 0,
29+
# 'master_seed': 4,
30+
# }
31+
# ),
32+
# "data" / Prefixed(
33+
# Int32ul,
34+
# Switch(
35+
# this.id,
36+
# {
37+
# 'master_seed': RandomBytes(32),
38+
# },
39+
# default=GreedyBytes
40+
# )
41+
# )
42+
# )
43+
from pykeepass_issue219_deleteme import DynamicHeaderItem
44+
45+
class DynamicDict(Adapter):
46+
"""ListContainer <---> Container
47+
Convenience mapping so we dont have to iterate ListContainer to find
48+
the right item
49+
50+
FIXME: lump kwarg was added to get around the fact that InnerHeader is
51+
not truly a dict. We lump all 'binary' InnerHeaderItems into a single list
52+
"""
53+
54+
def __init__(self, key, subcon, lump=[]):
55+
super().__init__(subcon)
56+
self.key = key
57+
self.lump = lump
58+
59+
# map ListContainer to Container
60+
def _decode(self, obj, context, path):
61+
d = OrderedDict()
62+
for l in self.lump:
63+
d[l] = ListContainer([])
64+
for item in obj:
65+
if item[self.key] in self.lump:
66+
d[item[self.key]].append(item)
67+
else:
68+
d[item[self.key]] = item
69+
70+
return Container(d)
71+
72+
# map Container to ListContainer
73+
def _encode(self, obj, context, path):
74+
l = []
75+
for key in obj:
76+
if key == 'master_seed':
77+
print('key:', key, sum(obj[key].data))
78+
if key in self.lump:
79+
l += obj[key]
80+
else:
81+
l.append(obj[key])
82+
83+
return ListContainer(l)
84+
85+
DynamicHeader4 = DynamicDict(
86+
'id',
87+
RepeatUntil(
88+
lambda item, a, b: item.id == 'end',
89+
DynamicHeaderItem
90+
)
91+
)
92+
93+
# master_seed header item
94+
master_dyn_item_data = (
95+
# id, length
96+
b'\x04' + b'\x20\x00\x00\x00' +
97+
# seed
98+
b'\xfe\xb9\xbecy\xd1\xe48\xf3\xf0T\xf5\x89\xa2(\xeeS\xd8\xd9BZ\t\xb7n\xc9j"\x12\xc3\x82\xd6\x83'
99+
)
100+
end_dyn_item_data = (
101+
# id, length
102+
b'\x00' + b'\x02\x00\x00\x00' +
103+
# value
104+
b'\r\n'
105+
)
106+
107+
dynamic_dict = master_dyn_item_data + end_dyn_item_data
108+
109+
if __name__ == '__main__':
110+
111+
print('PARSE')
112+
header = DynamicHeader4.parse(dynamic_dict)
113+
print('-------------------------------')
114+
print('master_seed:', sum(header.master_seed.data))
115+
print('-------------------------------')
116+
117+
print('BUILD')
118+
header_data = DynamicHeader4.build(header)
119+
120+
print('PARSE')
121+
header = DynamicHeader4.parse(header_data)
122+
print('-------------------------------')
123+
print('master_seed:', sum(header.master_seed.data))
124+
print('-------------------------------')

dev/pykeepass_issue219_deleteme.py

+60-17
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
IfThenElse, Int32sl, Int32ul, Int64sl, Int64ul, Mapping, Padding, Peek,
66
Pointer, Prefixed, RepeatUntil, Struct, Switch, Tell, this,
77
)
8-
from construct import Check, Int16ul, RawCopy, Switch, stream_write, ChecksumError
8+
from construct import Check, Int16ul, RawCopy, Switch, stream_write, ChecksumError, Adapter, Container, ListContainer
9+
from collections import OrderedDict
910
from Cryptodome.Random import get_random_bytes
1011

11-
from pykeepass.kdbx_parsing.kdbx4 import compute_transformed, CompressionFlags, VariantDictionary, CipherId, DynamicDict
12+
from pykeepass.kdbx_parsing.kdbx4 import compute_transformed, CompressionFlags, VariantDictionary, CipherId
1213
from pykeepass.kdbx_parsing.common import compute_master
1314
import hmac
1415
import hashlib
@@ -81,14 +82,55 @@ def _build(self, obj, stream, context, path):
8182
)
8283
)
8384

85+
86+
class DynamicDict(Adapter):
87+
"""ListContainer <---> Container
88+
Convenience mapping so we dont have to iterate ListContainer to find
89+
the right item
90+
91+
FIXME: lump kwarg was added to get around the fact that InnerHeader is
92+
not truly a dict. We lump all 'binary' InnerHeaderItems into a single list
93+
"""
94+
95+
def __init__(self, key, subcon, lump=[]):
96+
super().__init__(subcon)
97+
self.key = key
98+
self.lump = lump
99+
100+
# map ListContainer to Container
101+
def _decode(self, obj, context, path):
102+
d = OrderedDict()
103+
for l in self.lump:
104+
d[l] = ListContainer([])
105+
for item in obj:
106+
if item[self.key] in self.lump:
107+
d[item[self.key]].append(item)
108+
else:
109+
d[item[self.key]] = item
110+
111+
return Container(d)
112+
113+
# map Container to ListContainer
114+
def _encode(self, obj, context, path):
115+
l = []
116+
for key in obj:
117+
if key == 'master_seed':
118+
print('key:', key, sum(obj[key].data))
119+
if key in self.lump:
120+
l += obj[key]
121+
else:
122+
l.append(obj[key])
123+
124+
return ListContainer(l)
125+
84126
DynamicHeader4 = DynamicDict(
85127
'id',
86128
RepeatUntil(
87129
lambda item, a, b: item.id == 'end',
88130
DynamicHeaderItem
89131
)
90132
)
91-
133+
# from issue219_adaptertest_deleteme import DynamicHeader4
92134

93135
Body4 = Struct(
94136
"transformed_key" / Computed(compute_transformed),
@@ -134,17 +176,18 @@ def _build(self, obj, stream, context, path):
134176
)
135177
)
136178

137-
# parse the database
138-
opts = dict(password='password', keyfile='test4.key', decrypt=True, transformed_key=None)
139-
print('PARSING')
140-
parsed1 = KDBX.parse_file('test4.kdbx', **opts)
141-
# rebuild and try to reparse final result
142-
print('SAVING')
143-
del parsed1.header.data
144-
KDBX.build_file(parsed1, '/tmp/test4.kdbx', **opts)
145-
# parse the database
146-
print('PARSING')
147-
try:
148-
parsed2 = KDBX.parse_file('/tmp/test4.kdbx', **opts)
149-
except ChecksumError:
150-
pass
179+
if __name__ == '__main__':
180+
# parse the database
181+
opts = dict(password='password', keyfile='test4.key', decrypt=True, transformed_key=None)
182+
print('PARSING')
183+
parsed1 = KDBX.parse_file('test4.kdbx', **opts)
184+
# rebuild and try to reparse final result
185+
print('SAVING')
186+
del parsed1.header.data
187+
KDBX.build_file(parsed1, '/tmp/test4.kdbx', **opts)
188+
# parse the database
189+
print('PARSING')
190+
try:
191+
parsed2 = KDBX.parse_file('/tmp/test4.kdbx', **opts)
192+
except ChecksumError:
193+
pass

0 commit comments

Comments
 (0)