xref: /aosp_15_r20/external/conscrypt/common/src/test/resources/hpke/parse-hpke-encryption.py (revision cd0cc2e34ba52cdf454361820a14d744e4bd531d)
1# !/usr/bin/env python3
2
3import json
4
5from pathlib import Path
6
7# Can only process base mode 0
8# https://www.rfc-editor.org/rfc/rfc9180.html#name-hybrid-public-key-encryptio
9MODE_BASE = 0x00
10
11# Can only process KEM DHKEM(X25519, HKDF-SHA256) = 0x0020
12# https://www.rfc-editor.org/rfc/rfc9180.html#name-key-encapsulation-mechanism
13KEM_DHKEM_X25519_SHA256 = 0x0020
14
15# Can only process KDF HKDF-SHA256
16# https://www.rfc-editor.org/rfc/rfc9180.html#name-key-derivation-functions-kd
17KDF_HKDF_SHA256 = 0x0001
18
19# Can process all AEADs except EXPORT-only as this will be generating
20# a file to test encryption/decryption only, not secret exports
21# https://www.rfc-editor.org/rfc/rfc9180.html#name-authenticated-encryption-wi
22AEAD_EXPORT_ONLY = 0xffff
23
24
25def parse_and_format(file_in_path: str, file_out_path: str) -> None:
26    """
27    Parse and formats test-vectors.txt into Conscrypt's format.
28    A copy of the JSON file mentioned in RFC 9180 must be placed right next to
29    this script. A file will be created named "hpke-encryption.csv"
30
31        Parameters:
32            file_in_path: Absolute path to test-vectors.txt.
33            file_out_path: Absolute path to output file.
34    """
35
36    with open(file_in_path) as input:
37        payload = json.load(input)
38
39    records = ["# Several lines conform cryptographic operations ordered in sequence.",
40               "#   If records belong to a sequence, the following values won't change: ",
41               "#   kem_id, kdf_id, aead_id, info, skRm, skEm, pkRm, and pkEm.",
42               "#   The first record in the sequence contains all the data, while the ",
43               "#   next records in the sequence has the data omitted to make the file readable.",
44               "#   Please use the data from the first record of the sequence when performing ",
45               "#   the cryptographic operations. ",
46               "# ",
47               "# Data is in the format:",
48               "# kem_id,kdf_id,aead_id,info,skRm,skEm,pkRm,pkEm,aad,ct,pt"]
49
50    for key in payload:
51        # Skip these to test only capabilities exposed by BoringSSL
52        if (key["mode"] != MODE_BASE or
53                key["kem_id"] != KEM_DHKEM_X25519_SHA256 or
54                key["kdf_id"] != KDF_HKDF_SHA256 or
55                key["aead_id"] == AEAD_EXPORT_ONLY):
56            continue
57
58        firstEncryptionKeyIteration = True
59        for encryptionKey in key["encryptions"]:
60            if (firstEncryptionKeyIteration):
61                firstEncryptionKeyIteration = False
62                records.append("{},{},{},{},{},{},{},{},{},{},{}"
63                                   .format(str(key["kem_id"]),
64                                           str(key["kdf_id"]),
65                                           str(key["aead_id"]),
66                                           str(key["info"]),
67                                           str(key["skRm"]),
68                                           str(key["skEm"]),
69                                           str(key["pkRm"]),
70                                           str(key["pkEm"]),
71                                           str(encryptionKey["aad"]),
72                                           str(encryptionKey["ct"]),
73                                           str(encryptionKey["pt"])))
74            else:
75                records.append(",,,,,,,,{},{},{}"
76                                   .format(str(encryptionKey["aad"]),
77                                           str(encryptionKey["ct"]),
78                                           str(encryptionKey["pt"])))
79
80        with open(file_out_path, "w") as output:
81            output.write("\n".join(records))
82
83
84def main():
85    path = Path(__file__).parent.absolute()
86    parse_and_format(path / "test-vectors.txt", path / "hpke-encryption.csv")
87
88
89if __name__ == "__main__":
90    main()
91