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 \xbe cy\xd1 \xe4 8\xf3 \xf0 T\xf5 \x89 \xa2 (\xee S\xd8 \xd9 BZ\t \xb7 n\xc9 j"\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 ('-------------------------------' )
0 commit comments