imgtool: add creation of ECIES-P256 encrypted images
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py
index cfc9b7c..e2461c2 100644
--- a/scripts/imgtool/image.py
+++ b/scripts/imgtool/image.py
@@ -24,10 +24,13 @@
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 @@
'ED25519': 0x24,
'ENCRSA2048': 0x30,
'ENCKW128': 0x31,
+ 'ENCEC256': 0x32,
'DEPENDENCY': 0x40
}
@@ -209,6 +213,25 @@
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 @@
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),