C 203: PBKDF2 and AES (90 pts)

What you need:

Purpose

To perform practical encryption of data using a password, AES-CBC. and PBKDF2 (Password-Based Key Derivation Function 2).

Installing pip and pycryptodome

If you are using a Debian Linux system, execute these commands from a Bash prompt:
sudo apt update
sudo apt install python3-pip -y
python3 -m pip install pycryptodome

Opening Python

Open a Terminal or Command Prompt window and execute this command:
python3
Python 3 opens in Immediate Mode, as shown below.

Understanding PBKDF2

PBKDF2 is a way to use a password and generate a cryptographic key from it. The explanation below is from Wiki[edia:

Using PBKDF2

Execute these commands:
import hashlib
help(hashlib)
Press the PageDown key several times to get to the end of the help page. In the "FUNCTIONS" section, you see the pbkdf2_hmac function description, as shown below.

Press q to close the help page.

Execute this command to derive a 16-byte key from the password "apple" with one round of HMAC-MD5 and no salt:

hashlib.pbkdf2_hmac('md5', b"apple", b"", 1, 16).hex()
You see the key shown below.

C 203.1: Hexadecimal Values (5 pts)

Compute a 4-byte hash of this password:
today7
With these parameters:
  • Hash name: sha1
  • Salt: aaaabbbb
  • Iterations: 1000
The flag is the hash value in hexadecimal.

Type Conversions

Notice that the key and salt in the pbkdf2_hmac function are bytes. Bytes, strings, and integers are different data types in Python 3. To convert among them, see:

Python3 Conversions

C 203.2: Crack a PIN (10 pts)

The password is a three-digit number, between 000 and 999.

The hash value, using the same parameters as the previous flag, is:

f68923f5
Find the password. That's the flag.

Hint: for loops in Python, see project VP 100.

Using PBKDF2 and AES Together

This is the most common use case. The user enters a password, which is used to derive a key, which is then used to encrypt data with AES.

Execute this code to find a 128-bit key from the password "apple" and use that key to encrypt a sentence with AES:

import hashlib
from Crypto.Cipher import AES

cleartext = b'Any nation that does not honor its heroes will not long endure. '
key = hashlib.pbkdf2_hmac('md5', b"apple", b"", 1, 16)
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = cipher.encrypt(cleartext)
print(ciphertext.hex())
The ciphertext is a long string of hex, as shown below.

To decrypt the ciphertext, enter this code:

import hashlib
from Crypto.Cipher import AES

ciphertext = bytes.fromhex("68aa9afdbd3f2f0a40dfd961ad631bf2a9f56bc1a5808a90609e36e112e429402046b639085aa24c22b60ef2c7fba971c0862ff2587203236d7e3d6afbb5851d")
key = hashlib.pbkdf2_hmac('md5', b"apple", b"", 1, 16)
cipher = AES.new(key, AES.MODE_ECB)
cleartext = cipher.decrypt(ciphertext)
print(cleartext)
The cleartext is recovered, as shown below.

C 203.3: Encrypt a Sentence (5 pts)

Calculate ciphertext from these parameters:
  • Password: WSYIWYG
  • Hash name: sha256
  • Salt: 3xrtras4lt
  • Iterations: 50
  • Plaintext: Abandon all hope
  • Encryption algorithm: AES-ECB
  • Key size: 128 bits
The flag is the ciphertext in hexadecimal.

C 203.4: Decrypt (20 pts)

The password contains three lowercase letters, between aaa and zzz.

Using the same parameters as the previous challenge, decrypt this ciphertext:

7afa663510b006989976f542d0da66a5
The decrypted text contains only valid ASCII bytes, so no value is larger than 127.

Encrypted Virtual Machines

VMware uses this system to encrypt virtual machines: Here's part of the VMX file of a virtual machine I encrypted with a password of 123123.

This is a "keysafe": a data structure which contains an encrypted key, which can only be extracted by entering the correct password.

Making these substitutions:

and adding line breaks for readability produces this, with the important parts bolded:
encryption.keySafe = "vmware:key/list/(pair/(phrase/+IOeb4UyCwg=/
pass2key=PBKDF2-HMAC-SHA-1:
cipher=AES-256:
rounds=10000:
salt=tKU/oavut45txJFpUmcDng==,
HMAC-SHA-1,
L7te7YmmbxRzEhmaHIx/RlsenaF3h+qF4rPBlAeGpAarBASv7XVUfU/5Y/AAKRqArknfLGRB7RO+zw6NcjjNIWzQJY23hHUNLpa84xlVzH3+j0xstLpbJYkiYEIOV2XoZKu5XATB59CyBefiBvinGTonjrw=
))"
There are three base64-encoded values there. The first one is an unimportant ID number, the second one is the salt, and the third one is encrypted data. The first 16 bytes of the encrypted data is the iv, required for AES-CBC.
Execute this code to decrypt the data:
import hashlib
from Crypto.Cipher import AES
import base64

data = bytes.fromhex(base64.b64decode("L7te7YmmbxRzEhmaHIx/RlsenaF3h+qF4rPBlAeGpAarBASv7XVUfU/5Y/AAKRqArknfLGRB7RO+zw6NcjjNIWzQJY23hHUNLpa84xlVzH3+j0xstLpbJYkiYEIOV2XoZKu5XATB59CyBefiBvinGTonjrw=").hex())

iv = data[0:16]
ciphertext = data[16:64]
salt = bytes.fromhex(base64.b64decode("tKU/oavut45txJFpUmcDng==").hex())
key = hashlib.pbkdf2_hmac('sha1', b"123123", salt, 10000, 32)
cipher = AES.new(key, AES.MODE_CBC, iv)
cleartext = cipher.decrypt(ciphertext)
print(cleartext)
As shown below, the decrypted data begins with some readable text and contains another key.

C 203.5: Crack the Safe (20 pts)

The password for the keysafe shown below contains six digits. Each digit is repeated twice, like this: 112233, so there are 1000 possible keys from 000000 through 999999.

Find the key to crack the safe. That six-digit key is the flag.

encryption.keySafe = "vmware:key/list/(pair/(phrase/76IjGGQzjAA=/
pass2key=PBKDF2-HMAC-SHA-1:
cipher=AES-256:
rounds=10000:
salt=DkjJMNgtJIY/3StMtBQ0LA==,
HMAC-SHA-1,
0n1UgXgEpQ8Xun9PbStxYjmV54rkENd0+Ew4xXbhqN9yRXTeX4WEGWt5Nblz8LXtlgWV8uK8yjuIiLWsiBagTiVPJO6l2+XGIQn2fLCXs00HquSK9ap2oSx41s30nCH4f4Foozgt8EExi55moOY2dL3Y4ls=
))"
The decrypted text contains only valid ASCII bytes, so no value is larger than 127.

C 203.6: Crack a Harder Safe (30 pts)

The password for the keysafe shown below contains eight characters. The first two characters are We and the last two characters are ss

The other four characters are lowercase letters.

Find the key to crack the safe. That eight-character key is the flag.

encryption.keySafe = "vmware:key/list/(pair/(phrase/zROLP2SQhFQ=/
pass2key=PBKDF2-HMAC-SHA-1:
cipher=AES-256:
rounds=10000:
salt=sa+HuVbMVcXjFSqkA6wGkg==,
HMAC-SHA-1,
gYELJ/hydfSzSi8VM8nBA5RPOMFQBE9qdJmzYD286iHUur/JuBiIgAqKB9iQHaL2KCJiWtf4r0bzrSqocRhDES3YcM1dyzVOTFhNlMdFlVtLraeZ+cJdfzi31WDjaQsn0zWX5d5vr4k4GNf2BbOPHcwLxBU=
))"
The decrypted text contains only valid ASCII bytes, so no value is larger than 127.

References

Breaking Encrypted Virtual Machines: Recovering VMWare, Parallels, and VirtualBox Passwords
axcheron/pyvmx-cracker
axcheron/pyvboxdie-cracker

Acknowledgement

Thanks to ipv6sage for suggesting this project.
Posted 11-6-20 by Sam Bowne
Hint for challenge 6 improved 11-9-2021
Duplicate 203.4 removed 11-9-21
Minor text corrections 9-21-22