def get_random_bytes(n, trng=True): """ This function generates a random number :param n: how much randomness to generate. Valid values are from 8 to 256 :param trng: If True the a True Random Generator will be used, otherwise Deterministic Random Number Generator :raises: TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: Bytes object with randomness """ api = chip.init() api.exp_optiga_crypt_random.argtypes = c_byte, POINTER(c_ubyte), c_ushort api.exp_optiga_crypt_random.restype = c_int p = (c_ubyte * n)() if trng is True: ret = api.exp_optiga_crypt_random(Rng.TRNG.value, p, len(p)) else: ret = api.exp_optiga_crypt_random(Rng.DRNG.value, p, len(p)) if ret == 0: return bytes(p) else: return bytes(0)
def write(data, object_id, offset=0): """ This function helps to write the data stored on the chip :param data: Data to write, should be either bytes of bytearray :param object_id: An ID of the Object. Should be ObjectId :param offset: An optional parameter defining whether you want to read the data with offset :raises ValueError - when any of the parameters contain an invalid value TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: """ api = chip.init() if not isinstance(data, bytes) and not isinstance(data, bytearray): raise TypeError("data should be bytes type") if not isinstance(object_id, ObjectId): raise TypeError('keyid should be KeyId type,' 'you gave {0}'.format(type(object_id))) if len(data) > 1700: raise ValueError("length of data exceeds the limit of 1700") if offset > 1700: raise ValueError("offset should be less than the limit of 1700 bytes") api.exp_optiga_util_write_data.argtypes = c_ushort, c_ubyte, c_ushort, POINTER( c_ubyte), c_ushort api.exp_optiga_util_write_data.restype = c_int _data = (c_ubyte * len(data))(*data) ret = api.exp_optiga_util_write_data(c_ushort(object_id.value), 0x40, offset, _data, len(data)) if ret != 0: raise ValueError( 'Some problems during communication. You have possible selected one of locked objects' )
def generate_keypair(curve='secp256r1', keyid=KeyId.USER_PRIVKEY_1): """ This function generates an ECC keypair, the private part is stored on the chip based on the provided slot :param curve: Curve name, should be either secp256r1 or secp384r1 :param keyid: A Private Key Slot object ID. The value should be within the KeyId Enumeration :raises TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: EccKey object or None """ _bytes = None api = chip.init() c = str2curve(curve, return_value=True) if keyid not in KeyId: raise TypeError('Key ID should be selected of class KeyId') api.optiga_crypt_ecc_generate_keypair.argtypes = c_int, c_ubyte, c_bool, c_void_p, POINTER( c_ubyte), POINTER(c_ushort) api.optiga_crypt_ecc_generate_keypair.restype = c_int c_keyusage = c_ubyte(KeyUsage.KEY_AGREEMENT.value | KeyUsage.AUTHENTICATION.value) c_keyid = c_ushort(keyid.value) p = (c_ubyte * 100)() c_plen = c_ushort(len(p)) ret = api.optiga_crypt_ecc_generate_keypair(c, c_keyusage, 0, byref(c_keyid), p, byref(c_plen)) pubkey = (c_ubyte * c_plen.value)() memmove(pubkey, p, c_plen.value) if ret == 0: return EccKey(pkey=bytes(pubkey), keyid=keyid, curve=curve) else: warnings.warn("Failed to generate an ECC keypair, return a NoneType") return None
def read(object_id, offset=0): """ This function helps to read the data stored on the chip :param object_id: An ID of the Object. Should be ObjectId :param offset: An optional parameter defining whether you want to read the data with offset :raises: ValueError - when any of the parameters contain an invalid value TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: bytearray with the data """ api = chip.init() if offset > 1700: raise ValueError("offset should be less than the limit of 1700 bytes") if not isinstance(object_id, ObjectId): raise TypeError( "You need to provide an ObjectId you provided {0}".format( object_id)) api.exp_optiga_util_read_data.argtypes = c_ushort, c_ushort, POINTER( c_ubyte), POINTER(c_ushort) api.exp_optiga_util_read_data.restype = c_int d = (c_ubyte * 1700)() c_dlen = c_ushort(1700) ret = api.exp_optiga_util_read_data(c_ushort(object_id.value), offset, d, byref(c_dlen)) if ret == 0 and not all(_d == 0 for _d in list(bytes(d))): data = (c_ubyte * c_dlen.value)() memmove(data, d, c_dlen.value) _bytes = bytearray(data) else: _bytes = bytearray(0) return _bytes
def sign(ecckey, data): """ This function signs given data based on the provided EccKey object :param ecckey: a valid EccKey object. Use ecc.generate_keypair() for this :param data: Data to sign, the data will be hashed based on the used curve. If secp256r1 then sha256, otherwise sha384 :raises: TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: EcdsaSignature object or None """ api = chip.init() if not isinstance(data, bytes) and not isinstance(data, bytearray): if isinstance(data, str): _d = bytes(data.encode()) warnings.warn( "data will be converted to bytes type before signing") else: raise TypeError( 'Data to sign should be either bytes or str type, you gave {0}' .format(type(data))) else: _d = data if not isinstance(ecckey, EccKey): raise TypeError('Key ID should be selected of class KeyId') api.exp_optiga_crypt_ecdsa_sign.argtypes = POINTER( c_ubyte), c_ubyte, c_ushort, POINTER(c_ubyte), POINTER(c_ubyte) api.exp_optiga_crypt_ecdsa_sign.restype = c_int if ecckey.curve == 'secp256r1': digest = (c_ubyte * 32)(*hashlib.sha256(_d).digest()) s = (c_ubyte * (64 + 6))() hash_algorithm = 'sha256' elif ecckey.curve == 'secp384r1': digest = (c_ubyte * 48)(*hashlib.sha384(_d).digest()) s = (c_ubyte * (96 + 6))() hash_algorithm = 'sha384' c_slen = c_ubyte(len(s)) ret = api.exp_optiga_crypt_ecdsa_sign(digest, len(digest), ecckey.keyid.value, s, byref(c_slen)) if ret == 0: signature = (c_ubyte * (c_slen.value + 2))() signature[0] = 0x30 signature[1] = c_slen.value memmove(addressof(signature) + 2, s, c_slen.value) return EcdsaSignature(hash_algorithm, ecckey.keyid, bytes(signature)) else: warnings.warn("Failed to sign a data, return a NoneType") return None
def sign(rsakey, data, hash_algorithm='sha256'): """ This function signs given data based on the provided RsaKey object :param rsakey: a valid RsaKey object. Use rsa.generate_keypair() for this :param data: Data to sign :param hash_algorithm: Hash algorithm which should be used to sign data. SHA256 by default :raises: TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: RsassaSignature object or None """ api = chip.init() if not chip.is_trustm(): raise TypeError( 'You are trying to use Trust M API with the Trust X hardware') if not isinstance(data, bytes) and not isinstance(data, bytearray): if isinstance(data, str): _d = bytes(data.encode()) warnings.warn( "data will be converted to bytes type before signing") else: raise TypeError( 'Data to sign should be either bytes or str type, you gave {0}' .format(type(data))) else: _d = data if not isinstance(rsakey, RsaKey): raise TypeError('Key ID should be selected of class KeyId') api.optiga_crypt_rsa_sign.argtypes = POINTER( c_ubyte), c_ubyte, c_ushort, POINTER(c_ubyte), POINTER(c_ubyte) api.optiga_crypt_rsa_sign.restype = c_int if hash_algorithm == 'sha256': digest = (c_ubyte * 32)(*hashlib.sha256(_d).digest()) s = (c_ubyte * 320)() # Signature schemes RSA SSA PKCS1-v1.5 with SHA256 digest sign_scheme = 0x01 elif hash_algorithm == 'sha384': digest = (c_ubyte * 48)(*hashlib.sha384(_d).digest()) s = (c_ubyte * 320)() # Signature schemes RSA SSA PKCS1-v1.5 with SHA384 digest sign_scheme = 0x02 else: raise ValueError( 'This key isze is not supported, you typed {0} supported are [\'sha256\', \'sha384\']' .format(hash_algorithm)) c_slen = c_uint(len(s)) ret = api.exp_optiga_crypt_rsa_sign(sign_scheme, digest, len(digest), rsakey.keyid.value, s, byref(c_slen), 0) if ret == 0: signature = (c_ubyte * c_slen.value)() memmove(addressof(signature), s, c_slen.value) print(bytes(signature)) return RsassaSignature(hash_algorithm, rsakey.keyid, bytes(signature)) else: warnings.warn("Failed to sign a data, return a NoneType") return None
def generate_keypair(key_size='1024', keyid=KeyId.RSA_KEY_E0FC): """ This function generates an RSA keypair, the private part is stored on the chip based on the provided slot :param key_size: Size of the key, can be 1024 or 2048 :param keyid: A Private Key Slot object ID. The value should be within the KeyId Enumeration :raises: TypeError - when any of the parameters are of the wrong type OSError - when an error is returned by the chip initialisation library :return: RsaKey object or None """ _bytes = None api = chip.init() if not chip.is_trustm(): raise TypeError( 'You are trying to use Trust M API with the Trust X hardware') allowed_key_sizes = {'1024', '2048'} if key_size not in allowed_key_sizes: raise ValueError( 'This key size is not supported, you typed {0} (type {1}) supported are [1024, 2048]' .format(key_size, type(key_size))) if keyid not in KeyId: raise TypeError('Key ID should be selected of class KeyId') api.exp_optiga_crypt_rsa_generate_keypair.argtypes = c_int, c_ubyte, c_bool, c_void_p, POINTER( c_ubyte), POINTER(c_ushort) api.exp_optiga_crypt_rsa_generate_keypair.restype = c_int if key_size is '1024': c_keytype = 0x41 rsa_header = b'\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00' else: c_keytype = 0x42 rsa_header = b'\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00' c_keyusage = c_ubyte(KeyUsage.KEY_AGREEMENT.value | KeyUsage.AUTHENTICATION.value | KeyUsage.ENCRYPTION.value) c_keyid = c_ushort(keyid.value) p = (c_ubyte * 320)() c_plen = c_ushort(len(p)) ret = api.exp_optiga_crypt_ecc_generate_keypair(c_keytype, c_keyusage, 0, byref(c_keyid), p, byref(c_plen)) pubkey = (c_ubyte * c_plen.value)() memmove(pubkey, p, c_plen.value) if ret == 0: return RsaKey(pkey=rsa_header + bytes(pubkey), keyid=keyid, key_size=int(key_size)) else: raise ValueError( 'Failed to generate an RSA keypair, return a NoneType')