Skip to content

Commit

Permalink
fake script still not showing issue
Browse files Browse the repository at this point in the history
- possibly DynamicDict is the culprit
  • Loading branch information
Evidlo committed Oct 7, 2024
1 parent b0f2a97 commit 7ef9043
Showing 1 changed file with 35 additions and 38 deletions.
73 changes: 35 additions & 38 deletions dev/pykeepass_issue219.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,62 @@
stream_tell, stream_seek, stream_read, stream_write,
)
from Cryptodome.Random import get_random_bytes
from types import SimpleNamespace as sn

# simple placeholder checksum function
def check_func(header_data, master_seed):
return header_data + master_seed

def compute_header_hmac_hash(context):
"""Compute HMAC-SHA256 hash of header.
Used to prevent header tampering."""
print('----------------------')
print('master_seed:', sum(context.header.master_seed))
print("header_sha:", sum(context.header._data))
print('master_seed:', sum(context.header.value.master_seed))
print("header_sha:", sum(context.header.data))
print('----------------------')

return context.header._data + context.header.master_seed
return context.header.data + context.header.value.master_seed


class RandomGreedyBytes(type(GreedyBytes)):
"""Same as GreedyBytes, but generate random bytes when building"""
class RandomBytes(Bytes):
"""Same as Bytes, but generate random bytes when building"""

def _build(self, obj, stream, context, path):
data = bytes(obj) if type(obj) is bytearray else obj
data = get_random_bytes(len(data))
stream_write(stream, data, len(data), path)
print('generating random bytes...')
length = self.length(context) if callable(self.length) else self.length
data = get_random_bytes(length)
print('old:', sum(context.master_seed))
print('new:', sum(data))
stream_write(stream, data, length, path)
return data

class Copy(Subconstruct):
"""Same as RawCopy, but don't create parent container when parsing.
Instead store data in ._data attribute of subconstruct, and never rebuild from data
"""
# class Copy(Subconstruct):
# """Same as RawCopy, but don't create parent container when parsing.
# Instead store data in ._data attribute of subconstruct, and never rebuild from data
# """

def _parse(self, stream, context, path):
offset1 = stream_tell(stream, path)
obj = self.subcon._parsereport(stream, context, path)
offset2 = stream_tell(stream, path)
stream_seek(stream, offset1, 0, path)
obj._data = stream_read(stream, offset2-offset1, path)
return obj
# def _parse(self, stream, context, path):
# offset1 = stream_tell(stream, path)
# obj = self.subcon._parsereport(stream, context, path)
# offset2 = stream_tell(stream, path)
# stream_seek(stream, offset1, 0, path)
# obj._data = stream_read(stream, offset2-offset1, path)
# return obj

def _build(self, obj, stream, context, path):
offset1 = stream_tell(stream, path)
obj = self.subcon._build(obj, stream, context, path)
offset2 = stream_tell(stream, path)
stream_seek(stream, offset1, 0, path)
obj._data = stream_read(stream, offset2-offset1, path)
return obj
# def _build(self, obj, stream, context, path):
# offset1 = stream_tell(stream, path)
# obj = self.subcon._build(obj, stream, context, path)
# offset2 = stream_tell(stream, path)
# stream_seek(stream, offset1, 0, path)
# obj._data = stream_read(stream, offset2-offset1, path)
# return obj

# simple database format with header and checksum
s = Struct(
"header" / Copy(Struct(
"header" / RawCopy(Struct(
"master_seed" / Prefixed(
Int8ul,
RandomGreedyBytes(),
RandomBytes(8),
),
"more_data" / Bytes(8)
)),
# "hash" / Checksum(
# Bytes(25),
# lambda ctx: check_func(ctx.header._data, ctx.header.master_seed),
# this
# )
"hash" / Checksum(
Bytes(25),
compute_header_hmac_hash,
Expand All @@ -77,15 +73,16 @@ def _build(self, obj, stream, context, path):
length = int.to_bytes(len(master_seed), length=1, byteorder='big')
more_data = b'12345678'
header = length + master_seed + more_data
data1 = header + check_func(header, master_seed)
data1 = header + compute_header_hmac_hash(sn(header=sn(data=header, value=sn(master_seed=master_seed))))

# parse the database
print('PARSING')
parsed1 = s.parse(data1)

# rebuild and try to reparse final result
print('SAVING')
del parsed1.header.data
data2 = s.build(parsed1)
parsed2 = s.parse(data2)
if parsed1.header.master_seed == parsed2.header.master_seed:
if parsed1.header.value.master_seed == parsed2.header.value.master_seed:
Exception("Database unchanged")

0 comments on commit 7ef9043

Please sign in to comment.