Codebase list aeskeyfind / a282f8e
Add autopkgtests Add autopkgtests for aeskeyfind. Those include a smoke test and the extraction of 128-bit and 256-bit AES keys from process memory dumps, wich are generated during the tests runtime. Jan Gru authored 2 years ago Samuel Henrique committed 2 years ago
7 changed file(s) with 217 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Tests: smoke, recover-aes-128, recover-aes-256
1 Depends: aeskeyfind, gdb, procps, python3-pycryptodome
2 Restrictions: allow-stderr
0 #!/bin/sh
1
2 # $1 = key specification as multiline string
3 # $2 = dump file to store process memory
4
5 GEN_SCRIPT="debian/tests/helpers/gen_aes_key.py"
6
7 # Spawns subshell running the key generation script
8 (echo "$1" | python3 "${GEN_SCRIPT}") &
9
10 # Sleep to retrieve the PID of the child process reliably
11 sleep .3
12
13 PID=$(pgrep -f "python3 ${GEN_SCRIPT}")
14
15 #gcore -o"$3" ${PID} > /dev/null 2>&1
16 # Dumps memory
17 grep rw-p /proc/${PID}/maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1\t\2/p' \
18 | while read start stop;
19 do gdb --batch --pid ${PID} -ex "append memory $2 0x$start 0x$stop" > /dev/null 2>&1;
20 done
21
22 # Terminates key generation script
23 kill -9 ${PID}
0 import argparse
1 import time
2 import sys
3
4 # Use pycryptodome's AES library
5 # See https://pycryptodome.readthedocs.io/en/latest/src/cipher/aes.html
6 from Cryptodome.Cipher import AES
7
8
9 KEY_ELEMENTS = ["KEY", "IV"]
10
11
12 def main(infile=None):
13 lines = []
14
15 # Checks, if interactive session or reading from a file
16 if sys.stdin.isatty():
17 if infile.name != "<stdin>":
18 # Reads specification file
19 with open(infile.name, "r") as f:
20 lines = f.readlines()
21 else:
22 exit("Supply data via STDIN or file!")
23 else:
24 lines = sys.stdin.readlines()
25
26 construct_key(lines)
27
28
29 def construct_key(lines):
30 keymaterial = {}
31
32 # Populates keymaterial
33 for line in lines:
34 # Strips of \n
35 line = line.strip()
36
37 # Tokenizes line
38 parts = line.split("=", 1)
39 name = parts[0]
40 val = parts[-1]
41
42 # Stores line in dict
43 if name in KEY_ELEMENTS:
44 keymaterial[name] = bytes(val, "utf-8")
45
46 # Performs checks regarding well-formed key material
47 if "KEY" not in keymaterial:
48 exit("Key specification is incomplete.")
49 elif (
50 len(keymaterial["KEY"]) != 16
51 and len(keymaterial["KEY"]) != 24
52 and len(keymaterial["KEY"]) != 32
53 ):
54 exit("Unsupported key length: " + str(len(keymaterial["KEY"])))
55
56 # Constructs AES key by given parameters
57 # Assign it to a variable to keep it in memory
58 if "IV" in keymaterial.keys():
59 aes_key = AES.new(
60 keymaterial["KEY"], AES.MODE_CBC, iv=keymaterial["IV"]
61 ) # noqa: F841
62 else:
63 aes_key = AES.new(keymaterial["KEY"], AES.MODE_CBC) # noqa: F841
64
65 while True:
66 time.sleep(1)
67
68
69 def parse_args():
70 parser = argparse.ArgumentParser(
71 description="Construct an AES key according to specified key material and sleep forever." # noqa: E501
72 )
73 parser.add_argument(
74 "keyspec", nargs="?", type=argparse.FileType("r"), default=sys.stdin
75 )
76 args = parser.parse_args()
77 return args
78
79
80 if __name__ == "__main__":
81 args = parse_args()
82 construct_key(args.keyspec)
0 #!/bin/sh
1
2 ################################################################
3 # Usage: #
4 # test_aes_extraction <KEY> <IV> #
5 # #
6 # Example: #
7 # test_aes_extraction "DebianDebianDebi" "aaaabbbbccccdddd"#
8 # #
9 # #
10 # Note: Use either 16, 24 or 32 byte long keys and IVs. #
11 ################################################################
12
13 # Exit on first failure
14 set -e
15
16 # Converts a ASCII string to its hex representation
17 str2hex() {
18 echo "$1" | sed 's/\(.\)/\1\n/g' | \
19 xargs -I {} printf "%x" "'{}"
20 }
21
22 # Path of the script, which is used to create AES keys
23 # and dump the memory of the process performing AES construction
24 GEN_DUMP="debian/tests/helpers/gen_aes_dump.sh"
25
26
27 # Defines the AES key-material, used to generate the dump
28 # and to serve as target value for the extraction
29 if [ -z "$1" ]
30 then
31 echo "No key provided!"
32 exit 1
33 fi
34
35 KEY="$1"
36
37 # Combination of the parameters to feed into the script
38 if [ -z "$2" ]
39 then
40 KEYSPEC="KEY=$1"
41 else
42 KEYSPEC="KEY=$1\nIV=$2"
43 fi
44
45 # Memory dump to process
46 DMP="${AUTOPKGTEST_TMP}/aes.dmp"
47
48 # Dump memory of process, which generates key material
49 sh ${GEN_DUMP} "$KEYSPEC" "$DMP"
50
51 # Performs key extraction
52 # This fails on kernel 5.10.0.6 and glibc 2.31-11
53 # Change threshold to 50 via `-t 50`, then it succeeds
54 # https://bugs.debian.org/989179
55 ACTUAL=$(aeskeyfind -t 50 "${DMP}") # FAILS!
56
57 # Checks, compare actual result with target values
58 echo "${ACTUAL}" | grep -q $(str2hex "${KEY}")
59
60 # Clean up
61 rm ${DMP}
62
63 exit 0
0 #!/bin/sh
1
2 set -e
3
4 # Helper script to use for dumping and key extraction
5 TEST_SCRIPT="debian/tests/helpers/test_aes_extraction.sh"
6
7 # Defines the AES key-material
8 KEY="DebianDebianDebi"
9
10 # Dump memory of process, which generates key material
11 sh ${TEST_SCRIPT} "$KEY"
12
0 #!/bin/sh
1
2 set -e
3
4 # Helper script to use for dumping and key extraction
5 TEST_SCRIPT="debian/tests/helpers/test_aes_extraction.sh"
6
7 # Defines the AES key-material
8 KEY="DebianDebianDebianDebianDebianDe"
9
10 # Dump memory of process, which generates key material
11 sh ${TEST_SCRIPT} "$KEY"
12
0 #!/bin/sh
1
2 # Exit on failure immediately
3 set -e
4
5 # Specifies testfile containing 1K of zeros
6 DMP="${AUTOPKGTEST_TMP}/zeros.dmp"
7 truncate -s 1K ${DMP}
8
9 # Run aeskeyfind with zero-filled dump
10 # This is needed, since aeskeyfind returns 1 upon calling without parameters
11 aeskeyfind ${DMP}
12
13 # Clean up
14 rm ${DMP}
15
16 exit 0