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 or RSAKey

  • 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, or AcquiredSession

  • 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