imgtool: add creation of ECIES-P256 encrypted images

Signed-off-by: Fabio Utzig <utzig@apache.org>
This commit is contained in:
Fabio Utzig 2019-10-22 09:56:44 -03:00 committed by Fabio Utzig
parent b3f058c0ef
commit 7a3b2605ac
2 changed files with 43 additions and 13 deletions

View File

@ -24,10 +24,13 @@ from intelhex import IntelHex
import hashlib
import struct
import os.path
from cryptography.hazmat.primitives.asymmetric import padding
from .keys import rsa, ecdsa
from cryptography.hazmat.primitives.asymmetric import ec, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.exceptions import InvalidSignature
IMAGE_MAGIC = 0x96f3b83d
@ -56,6 +59,7 @@ TLV_VALUES = {
'ED25519': 0x24,
'ENCRSA2048': 0x30,
'ENCKW128': 0x31,
'ENCEC256': 0x32,
'DEPENDENCY': 0x40
}
@ -209,6 +213,25 @@ class Image():
len(self.payload), tsize, self.slot_size)
raise Exception(msg)
def ecies_p256_hkdf(self, enckey, plainkey):
newpk = ec.generate_private_key(ec.SECP256R1(), default_backend())
shared = newpk.exchange(ec.ECDH(), enckey._get_public())
derived_key = HKDF(
algorithm=hashes.SHA256(), length=48, salt=None,
info=b'MCUBoot_ECIES_v1', backend=default_backend()).derive(shared)
encryptor = Cipher(algorithms.AES(derived_key[:16]),
modes.CTR(bytes([0] * 16)),
backend=default_backend()).encryptor()
cipherkey = encryptor.update(plainkey) + encryptor.finalize()
mac = hmac.HMAC(derived_key[16:], hashes.SHA256(),
backend=default_backend())
mac.update(cipherkey)
ciphermac = mac.finalize()
pubk = newpk.public_key().public_bytes(
encoding=Encoding.X962,
format=PublicFormat.UncompressedPoint)
return cipherkey, ciphermac, pubk
def create(self, key, enckey, dependencies=None):
self.enckey = enckey
@ -279,12 +302,17 @@ class Image():
if enckey is not None:
plainkey = os.urandom(16)
cipherkey = enckey._get_public().encrypt(
plainkey, padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
tlv.add('ENCRSA2048', cipherkey)
if isinstance(enckey, rsa.RSAPublic):
cipherkey = enckey._get_public().encrypt(
plainkey, padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None))
tlv.add('ENCRSA2048', cipherkey)
elif isinstance(enckey, ecdsa.ECDSA256P1Public):
cipherkey, mac, pubk = self.ecies_p256_hkdf(enckey, plainkey)
tlv.add('ENCEC256', pubk + mac + cipherkey)
nonce = bytes([0] * 16)
cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce),

View File

@ -226,11 +226,13 @@ def sign(key, align, version, header_size, pad_header, slot_size, pad,
img.load(infile)
key = load_key(key) if key else None
enckey = load_key(encrypt) if encrypt else None
if enckey:
if not isinstance(enckey, (keys.RSA, keys.RSAPublic)):
raise Exception("Encryption only available with RSA key")
if key and not isinstance(key, keys.RSA):
raise Exception("Signing only available with private RSA key")
if enckey and key:
if ((isinstance(key, keys.ECDSA256P1) and
not isinstance(enckey, keys.ECDSA256P1Public))
or (isinstance(key, keys.RSA) and
not isinstance(enckey, keys.RSAPublic))):
# FIXME
raise Exception("Signing and encryption must use the same type of key")
img.create(key, enckey, dependencies)
img.save(outfile, hex_addr)