Cryptography
Here are some examples for what you can do with this submodule
True random number generation
Generate a true random number, accepted values from 8 to 255 bytes
from optigatrust import crypto
crypto.random(8)
Keypair generation (ECC, RSA)
from optigatrust import crypto
from optigatrust import objects
key_object = objects.ECCKey(0xe0f1)
pkey, _ = crypto.generate_pair(key_object, curve='secp256r1')
pkey, _ = crypto.generate_pair(key_object, curve='secp384r1')
pkey, _ = crypto.generate_pair(key_object, curve='secp521r1')
pkey, _ = crypto.generate_pair(key_object, curve='brainpoolp256r1')
pkey, _ = crypto.generate_pair(key_object, curve='brainpoolp384r1')
pkey, _ = crypto.generate_pair(key_object, curve='brainpoolp512r1')
pkey, _ = crypto.generate_pair(key_object, curve='secp384r1', key_usage=['authentication', 'signature'])
pkey, _ = crypto.generate_pair(key_object, curve='secp384r1', key_usage=['authentication', 'key_agreement', 'signature'])
pkey, key = crypto.generate_pair(key_object=key_object, curve='secp256r1', export=True)
Elliptic Curve Digital Signature Algorithm (ECDSA)
from optigatrust import crypto
from optigatrust import objects
key_object = objects.ECCKey(0xe0f1)
_, _ = crypto.generate_pair(key_object, curve='secp256r1')
s = crypto.ecdsa_sign(key_object, 'Hello World')
PKCS1 v1.5 Signature generation (RSA SSA)
from optigatrust import crypto
from optigatrust import objects
key_object = objects.RSAKey(0xe0fc)
_, _ = crypto.generate_pair(key_object, key_size=1024)
s = crypto.pkcs1v15_sign(key_object, 'Hello World')
Elliptic Curve Diffie-Hellman (ECDH)
Store the shared secret internally on the chip
# methods to handle objects
import optigatrust.objects as objects
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
# imports from the cryptography package to create a third party private, public key pairs
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
# Generate a new keypair
# ignore the public part, as we need only the private key generated in the slot
key_object = objects.ECCKey(0xe0f1)
_, _ = optiga_ec.generate_pair(key_object, 'secp256r1')
# Generate a new keypair in soft, export the peer part
private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
peer_public_key = private_key.public_key().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
# Derive a shared secret using our internally store private key, and external public
# Don't export the shared secret, but store internally
session_object = optiga_ec.ecdh(key_object, peer_public_key)
Use a different curve - ‘brainpool256r1’
# methods to handle objects
import optigatrust.objects as objects
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
# imports from the cryptography package to create a third party private, public key pairs
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
# Generate a new keypair
# ignore the public part, as we need only the private key generated in the slot
key_object = objects.ECCKey(0xe0f1)
_, _ = optiga_ec.generate_pair(key_object, 'brainpoolp256r1')
# Generate a new keypair in soft, export the peer part
private_key = ec.generate_private_key(ec.BrainpoolP256R1(), default_backend())
peer_public_key = private_key.public_key().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
# Derive a shared secret using our internally store private key, and external public
# Don't export the shared secret, but store internally
session_object = optiga_ec.ecdh(key_object, peer_public_key)
Hash-based Message Authentication Code (HMAC)
Using an ECDH to generate the shared secret, and use this secret for HMAC
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
# ... repeat steps to generate a proper shared secret on the chip from the above example
session_object = ecdh('with_secp256r1_curve')
# Generate hash-based MAC
data = 'Hello world!'
mac = optiga_ec.hmac(session_object, str.encode(data), hash_algorithm='sha256')
or with a different curve
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
# ... repeat steps to generate a proper shared secret on the chip from the above example
session_object = ecdh('with_brainpoolp512r1_curve')
# Generate hash-based MAC
data = 'Hello world!'
mac = optiga_ec.hmac(session_object, str.encode(data), hash_algorithm='sha512')
Use an externally provided secret
# methods to handle objects
import optigatrust.objects as objects
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
secret = 'BFB770EEBF8F61C704E00D828B7A3641D5CD7A3846DEF90F214240250AAF9C2E'
# Initialise the object and write secret data to it.
app_data = objects.AppData(0xf1d0)
app_data.write(bytes().fromhex(secret))
# AppData Object should have a shared secret type to be used for hmac
app_data.meta = {'type': 'pre_sh_secret', 'execute': 'always'}
mac = optiga_ec.hmac(app_data, str.encode(data), hash_algorithm='sha256')
Key Derivation (HKDF, TLS PRF)
TLS PRF
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
# random seed for the kdf function
seed = '61C7DEF90FD5CD7A8B7A364104E00D823846BFB770EEBF8F40252E0A2142AF9C'
# ... repeat steps to generate a proper shared secret on the chip from the above example
session_object = ecdh('with_secp256r1_curve')
# derive a key and export it
derived_key = optiga_ec.tls_prf(session_object, 32, seed=bytes().fromhex(seed), hash_algorithm='sha256', export=True)
Use an externally provided secret
# methods to handle objects
import optigatrust.objects as objects
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
secret = 'BFB770EEBF8F61C704E00D828B7A3641D5CD7A3846DEF90F214240250AAF9C2E'
# Initialise the object and write secret data to it.
app_data = objects.AppData(0xf1d0)
app_data.write(bytes().fromhex(secret))
# AppData Object should have a shared secret type to be used for an kdf
app_data.meta = {'type': 'pre_sh_secret', 'execute': 'always'}
derived_key = optiga_ec.tls_prf(app_data, 32, label='Firmware update', seed=bytes().fromhex(seed), hash_algorithm=hash_alg, export=True)
HKDF
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
# random seed for the kdf function
seed = '61C7DEF90FD5CD7A8B7A364104E00D823846BFB770EEBF8F40252E0A2142AF9C'
# ... repeat steps to generate a proper shared secret on the chip from the above example
session_object = ecdh('with_secp512r1_curve')
# derive a key and export it
derived_key = optiga_ec.hkdf(session_object, 32, hash_algorithm='sha512', export=True)
Use an externally provided secret
# methods to handle objects
import optigatrust.objects as objects
# methods to handle crypto functions on the optiga
import optigatrust.crypto as optiga_ec
secret = 'BFB770EEBF8F61C704E00D828B7A3641D5CD7A3846DEF90F214240250AAF9C2E'
# Initialise the object and write secret data to it.
app_data = objects.AppData(0xf1d0)
app_data.write(bytes().fromhex(secret))
# AppData Object should have a shared secret type to be used for an kdf
app_data.meta = {'type': 'pre_sh_secret', 'execute': 'always'}
derived_key = optiga_ec.hkdf(app_data, 32, hash_algorithm='sha256', export=True)
API
This module implements all crypo related APIs of the optigatrust package
- optigatrust.crypto.ecdh(key_object, external_pkey, export=False)
This function derives a shared secret using Diffie-Hellman Key-Exchange. This function assumes the instance of the key from which this method will be called represents the private key on the system used for ECDH
- Parameters:
key_object – Key Object on the OPTIGA Chip, which should be used as a source of the private key storage
ECCKey
external_pkey –
a bytearray with a public key You can submit public keys with parameters as per openssl output in DER format
from asn1crypto import pem # Option 1 pem_string = '-----BEGIN PUBLIC KEY-----\n' + \ 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhqPByq/2I5Xv1jqSZbBzS8fptkdP\n' + \ 'fArs2+l6SZ8IfOIukkf/wHiww0FV+jxehrVyzW+cy9+KftBobalw3iXN2A==\n' + \ '-----END PUBLIC KEY-----' if pem.detect(pem_string): type_name, headers, der_bytes = pem.unarmor(pem_string) # Option 2 hex_string ='3059301306072a8648ce3d020106082a' + \ '8648ce3d0301070342000486a3c1caaf' + \ 'f62395efd63a9265b0734bc7e9b6474f' + \ '7c0aecdbe97a499f087ce22e9247ffc0' + \ '78b0c34155fa3c5e86b572cd6f9ccbdf' + \ '8a7ed0686da970de25cdd8' der_bytes = bytes().from_hex(hex_string)
export – defines whether the resulting secret should be exported or not
- Raises:
TypeError - when any of the parameters are of the wrong type
OSError - when an error is returned by the core initialisation library
- Returns:
in case export set to True returns a shared secret, otherwise returns
AcquiredSession()
- optigatrust.crypto.ecdsa_verify_data_oid(signature, data, hash_algorithm, oid)
This function verifies an ECDSA signature for given data and OID of a certificate.
- Parameters:
signature – ECDSA siganture to be verified
hash – Hash to be verified for verification
oid – OID of certificate to be used for verification
- Raises:
TypeError - when any of the parameters are of the wrong type
OSError - when an error is returned by the core initialisation library
IOError - when an error is returned by verification
- Returns:
True if signature validation is successful
- optigatrust.crypto.ecdsa_verify_data_pk_host(signature, data, hash_algorithm, public_key, curve)
This function verifies an ECDSA signature for given data and public key.
- Parameters:
signature – ECDSA siganture to be verified
data – Data to be verified for verification
hash_algorithm – Hash algorithm to be used for verification
public_key – Public key to be used for verification
curve – Curve of public key to be used for verification
- Raises:
TypeError - when any of the parameters are of the wrong type
OSError - when an error is returned by the core initialisation library
IOError - when an error is returned by verification
- Returns:
True if signature validation is successful
- optigatrust.crypto.generate_pair(key_object, curve=None, key_usage=None, key_size=1024, export=False)
This function generates a ECC/RSA keypair
- Parameters:
key_object – Key Object on the OPTIGA Chip, which should be used as a source of the private key storage. Can be
ECCKey
orRSAKey
curve – Curve name in string, only EC relevant, should be one of supported by the chip curves. For instance m3 has the widest range of supported algorithms: secp256r1, secp384r1, secp521r1, brainpoolp256r1, brainpoolp384r1, brainpoolp512r1
key_usage – Key usage defined per string. Can be selected as following: [‘key_agreement’, ‘authentication’, ‘encryption’, ‘signature’]
key_size – Key size is only RSA relevant, possible values are 1024 and 2048
export – Bool type indicates whether the private key should be exported
- Raises:
TypeError - when any of the parameters are of the wrong type
OSError - when an error is returned by the core initialisation library
- Returns:
A tuple of keys (public_key, private_key) if export isnt requested, the private part is None Example (EC)
public_key= '3059301306072a8648ce3d020106082a8648ce...67477a4deb6ab7d1159ddc0bfe7341e40e9' private_key= '308187020100301306072a8648ce3d020106082a86....1159ddc0bfe7341e40e9'
- optigatrust.crypto.hkdf(key_object, key_length, salt=None, info=None, hash_algorithm='sha256', export=False)
This function derives a key (HKDF) using the secret stored on OPTIGA
Note
Only OPTIGA™ Trust M3 relevant
- Parameters:
key_object – Key Object on the OPTIGA Chip, which should be used as a source of the private key storage. Can be one of the following classes
AppData
,AcquiredSession
key_length – Size of the requested key. Minimum Length = 16 byte; maximum length = 66 bytes (in case of OPTIGA™ Trust M V1, = 48 bytes) in case of session reference; maximum length = 256 byte in case of returned secret
salt – Optional salt, should be bytestring
info – Optional info, should be bytestring
hash_algorithm – Hash algorithm which should be used to sign data. ‘sha256’ by default
export – set it to True, if you would like to export the resulting. In other case the key will e stored in the
AcquiredSession
- Raises:
TypeError - when any of the parameters are of the wrong type
ValueError - when any of the parameters not expected
OSError - when an error is returned by the core initialisation library
- Returns:
byte string with the key if requested, otherwise
AcquiredSession
- optigatrust.crypto.hmac(key_object, data, hash_algorithm='sha256')
This function calculates a HMAC over a given data using the secret stored on OPTIGA
Note
Only OPTIGA™ Trust M3 relevant
- Parameters:
key_object – Key Object on the OPTIGA Chip, which should be used as a source of the private key storage. Can be one of the following classes
AppData
,Session
, orAcquiredSession
data – A byte string data
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
ValueError - when any of the parameters not expected
OSError - when an error is returned by the core initialisation library
- Returns:
byte string with the resulating MAC
- optigatrust.crypto.pkcs1v15_sign(key_object, data, hash_algorithm='sha256')
This function signs given data based on the provided RsaKey object
- Parameters:
key_object – Key Object on the OPTIGA Chip, which should be used as a source of the private key storage. Should be of type
RSAKey
data – Data to sign
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 core initialisation library
- Returns:
PKCS1v15Signature
object or None
- optigatrust.crypto.random(number, trng=True)
This function generates a random number
- Parameters:
number – how much randomness to generate. Valid values are integers from 8 to 256
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
- Returns:
Bytes object with randomness
- optigatrust.crypto.tls_prf(obj, key_length, seed, label=None, hash_algorithm='sha256', export=False)
This function derives a key (TLS PRF) using the secret stored on OPTIGA
Note
SHA384 and SH512 are only OPTIGA™ Trust M3 relevant
- Parameters:
obj – Key Object on the OPTIGA Chip, which should be used as a source of the private key storage. Can be one of the following classes
AppData
,AcquiredSession
key_length – Size of the requested key. Minimum Length = 16 byte; maximum length = 66 bytes (in case of OPTIGA™ Trust M V1, = 48 bytes) in case of session reference; maximum length = 256 byte in case of returned secret
seed – Optional seed, should be bytestring
label – Optional label, should be bytestring
hash_algorithm – Hash algorithm which should be used to sign data. ‘sha256’ by default
export – set it to True, if you would like to export the resulting. In other case the key will e stored in the
AcquiredSession
- Raises:
TypeError - when any of the parameters are of the wrong type
ValueError - when any of the parameters not expected
OSError - when an error is returned by the core initialisation library
- Returns:
byte string with the key if requested, otherwise
AcquiredSession