Raef Coles | 59cf5d8 | 2024-12-09 15:41:13 +0000 | [diff] [blame^] | 1 | #!/usr/bin/env python3 |
| 2 | #------------------------------------------------------------------------------- |
| 3 | # SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors |
| 4 | # |
| 5 | # SPDX-License-Identifier: BSD-3-Clause |
| 6 | # |
| 7 | #------------------------------------------------------------------------------- |
| 8 | |
| 9 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes |
| 10 | |
| 11 | import key_derivation |
| 12 | |
| 13 | import argparse |
| 14 | import logging |
| 15 | logger = logging.getLogger("TF-M") |
| 16 | from arg_utils import * |
| 17 | import secrets |
| 18 | |
| 19 | def _encrypt_aes_ctr(data : bytes, |
| 20 | iv : bytes, |
| 21 | key : bytes |
| 22 | ) -> bytes: |
| 23 | assert len(iv) >= 8 |
| 24 | |
| 25 | if len(iv) < 16: |
| 26 | iv += bytes(16 - len(iv)) |
| 27 | |
| 28 | c = Cipher(algorithms.AES(key), modes.CTR(iv)) |
| 29 | return c.encryptor().update(data) |
| 30 | |
| 31 | encrypt_algs = { |
| 32 | "AES_CTR": _encrypt_aes_ctr, |
| 33 | } |
| 34 | |
| 35 | def add_arguments(parser : argparse.ArgumentParser, |
| 36 | prefix : str = "", |
| 37 | required : bool = True, |
| 38 | ) -> None: |
| 39 | add_prefixed_argument(parser, "encrypt_key", prefix, help="encryption key input file", |
| 40 | required=required, type=arg_type_bytes) |
| 41 | add_prefixed_argument(parser, "encrypt_alg", prefix, help="encryption algorithm", |
| 42 | choices=encrypt_algs.keys(), required=required) |
| 43 | add_prefixed_argument(parser, "iv", prefix, help="encryption intial value", |
| 44 | type=arg_type_bytes, required=False) |
| 45 | |
| 46 | key_derivation.add_arguments(parser, prefix, required=False) |
| 47 | |
| 48 | def parse_args(args : argparse.Namespace, |
| 49 | prefix : str = "", |
| 50 | ) -> dict: |
| 51 | out = parse_args_automatically(args, ["encrypt_alg", "encrypt_key", "iv"], prefix) |
| 52 | out["kdf_args"] = key_derivation.parse_args(args) |
| 53 | |
| 54 | return out |
| 55 | |
| 56 | def encrypt_data(data : bytes, |
| 57 | encrypt_key : bytes, |
| 58 | encrypt_alg : str, |
| 59 | kdf_args : dict, |
| 60 | iv : bytes = None, |
| 61 | **kwargs, |
| 62 | ) -> (bytes, bytes): |
| 63 | if not data: |
| 64 | return iv, data |
| 65 | |
| 66 | assert(encrypt_key) |
| 67 | assert(encrypt_alg) |
| 68 | |
| 69 | if kdf_args: |
| 70 | # FixMe: If RSE_SYMMETRIC_PROVISIONING is OFF, should we use directly |
| 71 | # the encrypt_key without deriving another one? |
| 72 | encrypt_key = key_derivation.derive_symmetric_key(**kdf_args, |
| 73 | input_key = encrypt_key, |
| 74 | length = 32 |
| 75 | ) |
| 76 | |
| 77 | if not iv: |
| 78 | iv = secrets.token_bytes(12) + int(0).to_bytes(4, 'little') |
| 79 | |
| 80 | encrypted_data = encrypt_algs[encrypt_alg]( |
| 81 | data = data, |
| 82 | key = encrypt_key, |
| 83 | iv = iv) |
| 84 | return iv, encrypted_data |
| 85 | |
| 86 | script_description = """ |
| 87 | Encrypt some data |
| 88 | """ |
| 89 | if __name__ == "__main__": |
| 90 | import argparse |
| 91 | |
| 92 | parser = argparse.ArgumentParser(allow_abbrev=False, |
| 93 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, |
| 94 | description=script_description) |
| 95 | parser.add_argument("--log_level", help="log level", required=False, default="ERROR", choices=logging._levelToName.values()) |
| 96 | parser.add_argument("--data", help="data to sign", type=arg_type_bytes, required=True) |
| 97 | |
| 98 | add_arguments(parser, required=True) |
| 99 | |
| 100 | args = parser.parse_args() |
| 101 | logger.setLevel(args.log_level) |
| 102 | config = parse_args(args) |
| 103 | config |= parse_args_automatically(args, ["data"]) |
| 104 | |
| 105 | print(encrypt_data(**config)[1].hex()) |