Length Extension Attacks
eecs-388
Merkle-Damgård Construction
- method for building hash functions from fixed-input-length compression functions
- used by many hash functions (e.g. MD5, SHA-1, SHA-256),which allows them to convert messages of arbitrary length into fixed-length hashes
- procedure:
- pad input message so length is a multiple of compression function’s block size
- split padded message into equal-sized blocks
- feed (or initialization vector if ) and into the compression function to get the new hash 4. hash of the last block = hash digest
---
config:
look: handDrawn
---
graph LR
B1["$$B_1$$"]
B2["$$B_2$$"]
B3["$$B_{n-1}$$"]
B4["$$B_n$$"]
IV["IV"]
F1{"$$f$$"}
F2{"$$f$$"}
F3{"$$f$$"}
F4{"$$f$$"}
H["$$h(M)$$"]
B1 ~~~ B2 ~~~ B3 ~~~ B4
B1 --> F1
B2 --> F2
B3 --> F3
B4 --> F4
IV --> F1 --> F2 --> F3 --> F4 --> H
Exploit
Input
- length of message
m sha256(m)
Output
m + padding(m) + xsha256(m + padding(len(m)) + x)
Setup
say we intercept message m, but cannot read it
without knowing m, we can compute the hash of longer messages of the form m + padding(len(m)) + suffix by initializing our SHA-256 function to sha256(m) and setting the function’s message length counter to the size of m plus the padding: padded_message_len = len(m) + len(padding(len(m)))
# m is an arbitrary message; we don't need to know it's contents
padded_message_len = len(m) + len(padding(len(m)))
h2 = sha256(
state=bytes.fromhex(sha256(m))
count=padded_message_len
)
then we can use length extension to get the hash of a longer string that we append more text to:
x = 'suffix'.encode() # .encode() converts str to bytes
h2.update(x)
print(h2.hexdigest())
note that h2.hexdigest() is equal to sha256(m + padding(len(m)) + x), but not sha256(m + x