예제 #1
0
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)
예제 #2
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'
        )
예제 #3
0
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
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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')