Skip to content

Instantly share code, notes, and snippets.

@singe
Created October 18, 2017 18:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save singe/e680fef88b61b2ae4aac3ff051306695 to your computer and use it in GitHub Desktop.
Save singe/e680fef88b61b2ae4aac3ff051306695 to your computer and use it in GitHub Desktop.
Simple demonstration of how you can recover plaintext from a stream cipher when the nonce is reused.
#!/usr/bin/env python3
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
pairwiseTransientKey = b'pairwiseTransKey'
EAPOLheader = b'Unencrypted Frame Stuff'
plaintext1 = b'Attack at dawn'
nonce1 = get_random_bytes(11)
cipher1 = AES.new(pairwiseTransientKey, AES.MODE_CCM, nonce1)
cipher1.update(EAPOLheader)
msg1 = nonce1, EAPOLheader, cipher1.encrypt(plaintext1), cipher1.digest()
plaintext2 = b'Run for the hills'
#nonce2 = get_random_bytes(11)
nonce2 = nonce1 #The nonce aka IV aka (packet number || MAC) is repeated
cipher2 = AES.new(pairwiseTransientKey, AES.MODE_CCM, nonce2)
cipher2.update(EAPOLheader)
msg2 = nonce2, EAPOLheader, cipher2.encrypt(plaintext2), cipher2.digest()
pairwiseTransientKeystream = bytes(a ^ b for a, b in zip(msg1[2], plaintext1))
decrypted = bytes(a ^ b for a, b in zip(msg2[2], pairwiseTransientKeystream))
if decrypted == plaintext2[0:len(decrypted)]:
print (f'Plaintext 1: {plaintext1}')
print (f'Plaintext 2: {plaintext2}')
print (f'Recovered plaintext 2: {decrypted}')
@singe
Copy link
Author

singe commented Oct 18, 2017

Output:
▶ ./aes-ccm-test.py
Plaintext 1: b'Attack at dawn'
Plaintext 2: b'Run for the hills'
Recovered plaintext 2: b'Run for the hi'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment