#!/usr/bin/env python3 # SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import datetime import hashlib import hmac import os import random import struct from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric.rsa import _modinv as modinv # type: ignore from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.utils import int_to_bytes def number_as_bignum_words(number): # type: (int) -> str """ Given a number, format result as a C array of words (little-endian, same as ESP32 RSA peripheral or mbedTLS) """ result = [] while number != 0: result.append('0x%08x' % (number & 0xFFFFFFFF)) number >>= 32 return '{ ' + ', '.join(result) + ' }' def number_as_bytes(number, pad_bits=None): # type: (int, int) -> bytes """ Given a number, format as a little endian array of bytes """ result = int_to_bytes(number)[::-1] # type: bytes while pad_bits is not None and len(result) < (pad_bits // 8): result += b'\x00' return result def bytes_as_char_array(b): # type: (bytes) -> str """ Given a sequence of bytes, format as a char array """ return '{ ' + ', '.join('0x%02x' % x for x in b) + ' }' NUM_HMAC_KEYS = 3 NUM_MESSAGES = 10 NUM_CASES = 6 hmac_keys = [os.urandom(32) for x in range(NUM_HMAC_KEYS)] messages = [random.randrange(0, 1 << 4096) for x in range(NUM_MESSAGES)] with open('digital_signature_test_cases.h', 'w') as f: f.write('/*\n') year = datetime.datetime.now().year f.write(' * SPDX-FileCopyrightText: {year} Espressif Systems (Shanghai) CO LTD\n'.format(year=year)) f.write(' *\n') f.write(' * SPDX-License-Identifier: Apache-2.0\n') f.write(' *\n') f.write(' * File generated by gen_digital_signature_tests.py\n') f.write(' */\n') # Write out HMAC keys f.write('#define NUM_HMAC_KEYS %d\n\n' % NUM_HMAC_KEYS) f.write('static const uint8_t test_hmac_keys[NUM_HMAC_KEYS][32] = {\n') for h in hmac_keys: f.write(' %s,\n' % bytes_as_char_array(h)) f.write('};\n\n') # Write out messages f.write('#define NUM_MESSAGES %d\n\n' % NUM_MESSAGES) f.write('static const uint32_t test_messages[NUM_MESSAGES][4096/32] = {\n') for m in messages: f.write(' // Message %d\n' % messages.index(m)) f.write(' %s,\n' % number_as_bignum_words(m)) f.write(' };\n') f.write('\n\n\n') f.write('#define NUM_CASES %d\n\n' % NUM_CASES) f.write('static const encrypt_testcase_t test_cases[NUM_CASES] = {\n') for case in range(NUM_CASES): f.write(' { /* Case %d */\n' % case) iv = os.urandom(16) f.write(' .iv = %s,\n' % (bytes_as_char_array(iv))) hmac_key_idx = random.randrange(0, NUM_HMAC_KEYS) aes_key = hmac.HMAC(hmac_keys[hmac_key_idx], b'\xFF' * 32, hashlib.sha256).digest() sizes = [4096, 3072, 2048, 1024, 512] key_size = sizes[case % len(sizes)] private_key = rsa.generate_private_key( public_exponent=65537, key_size=key_size, backend=default_backend()) priv_numbers = private_key.private_numbers() pub_numbers = private_key.public_key().public_numbers() Y = priv_numbers.d M = pub_numbers.n rr = 1 << (key_size * 2) rinv = rr % pub_numbers.n mprime = - modinv(M, 1 << 32) mprime &= 0xFFFFFFFF length = key_size // 32 - 1 f.write(' .p_data = {\n') f.write(' .Y = %s,\n' % number_as_bignum_words(Y)) f.write(' .M = %s,\n' % number_as_bignum_words(M)) f.write(' .Rb = %s,\n' % number_as_bignum_words(rinv)) f.write(' .M_prime = 0x%08x,\n' % mprime) f.write(' .length = %d, // %d bit\n' % (length, key_size)) f.write(' },\n') # calculate MD from preceding values and IV # Y4096 || M4096 || Rb4096 || M_prime32 || LENGTH32 || IV128 md_in = number_as_bytes(Y, 4096) + \ number_as_bytes(M, 4096) + \ number_as_bytes(rinv, 4096) + \ struct.pack('