This is an automated email from the ASF dual-hosted git repository.

utzig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-artifact.git


The following commit(s) were added to refs/heads/master by this push:
     new 9320939  Add support for image encryption using ECIES-P256
9320939 is described below

commit 9320939f0dace14f8810e31a17320fb534c193f3
Author: Fabio Utzig <[email protected]>
AuthorDate: Wed Nov 6 18:27:10 2019 -0300

    Add support for image encryption using ECIES-P256
    
    This adds support for encrypting images using ECIES-P256. The MCUBoot
    implementation was described here:
    
    
https://github.com/JuulLabs-OSS/mcuboot/blob/master/docs/encrypted_images.md#ecies-p256-encryption
    
    Signed-off-by: Fabio Utzig <[email protected]>
---
 image/create.go |  2 ++
 image/image.go  |  5 ++++-
 sec/encrypt.go  | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/image/create.go b/image/create.go
index 0ee3bb9..6fc0f27 100644
--- a/image/create.go
+++ b/image/create.go
@@ -129,6 +129,8 @@ func GenerateEncTlv(cipherSecret []byte) (ImageTlv, error) {
 
        if len(cipherSecret) == 256 {
                encType = IMAGE_TLV_ENC_RSA
+       } else if len(cipherSecret) == 113 {
+               encType = IMAGE_TLV_ENC_EC256
        } else if len(cipherSecret) == 24 {
                encType = IMAGE_TLV_ENC_KEK
        } else {
diff --git a/image/image.go b/image/image.go
index 7cd1e1a..f0a033e 100644
--- a/image/image.go
+++ b/image/image.go
@@ -64,6 +64,7 @@ const (
        IMAGE_TLV_ED25519   = 0x24
        IMAGE_TLV_ENC_RSA   = 0x30
        IMAGE_TLV_ENC_KEK   = 0x31
+       IMAGE_TLV_ENC_EC256 = 0x32
        IMAGE_TLV_AES_NONCE = 0x50
        IMAGE_TLV_SECRET_ID = 0x60
 )
@@ -78,6 +79,7 @@ var imageTlvTypeNameMap = map[uint8]string{
        IMAGE_TLV_ED25519:   "ED25519",
        IMAGE_TLV_ENC_RSA:   "ENC_RSA",
        IMAGE_TLV_ENC_KEK:   "ENC_KEK",
+       IMAGE_TLV_ENC_EC256: "ENC_EC256",
        IMAGE_TLV_AES_NONCE: "AES_NONCE",
        IMAGE_TLV_SECRET_ID: "SEC_KEY_ID",
 }
@@ -171,7 +173,8 @@ func ImageTlvTypeIsSig(tlvType uint8) bool {
 
 func ImageTlvTypeIsSecret(tlvType uint8) bool {
        return tlvType == IMAGE_TLV_ENC_RSA ||
-               tlvType == IMAGE_TLV_ENC_KEK
+               tlvType == IMAGE_TLV_ENC_KEK ||
+               tlvType == IMAGE_TLV_ENC_EC256
 }
 
 func (ver ImageVersion) String() string {
diff --git a/sec/encrypt.go b/sec/encrypt.go
index b9a579e..85d4571 100644
--- a/sec/encrypt.go
+++ b/sec/encrypt.go
@@ -23,11 +23,15 @@ import (
        "bytes"
        "crypto/aes"
        "crypto/cipher"
+       "crypto/ecdsa"
+       "crypto/elliptic"
+       "crypto/hmac"
        "crypto/rand"
        "crypto/rsa"
        "crypto/sha256"
        "crypto/x509"
        "encoding/base64"
+       "golang.org/x/crypto/hkdf"
        "io"
 
        keywrap "github.com/NickBall/go-aes-key-wrap"
@@ -49,6 +53,7 @@ type PrivEncKey struct {
 
 type PubEncKey struct {
        Rsa *rsa.PublicKey
+       Ec  *ecdsa.PublicKey
        Aes cipher.Block
 }
 
@@ -88,6 +93,8 @@ func parsePubKePem(b []byte) (PubEncKey, error) {
        switch pub := itf.(type) {
        case *rsa.PublicKey:
                key.Rsa = pub
+       case *ecdsa.PublicKey:
+               key.Ec = pub
        default:
                return key, errors.Errorf(
                        "unknown public encryption key type: %T", pub)
@@ -130,8 +137,8 @@ func (key *PrivEncKey) PubEncKey() PubEncKey {
 }
 
 func (key *PubEncKey) AssertValid() {
-       if key.Rsa == nil && key.Aes == nil {
-               panic("invalid public encryption key; neither RSA nor AES")
+       if key.Rsa == nil && key.Aes == nil && key.Ec == nil {
+               panic("invalid public encryption key; neither RSA nor AES nor 
EC-P256")
        }
 }
 
@@ -163,6 +170,40 @@ func encryptRsa(pubk *rsa.PublicKey, plainSecret []byte) 
([]byte, error) {
        return cipherSecret, nil
 }
 
+func encryptEc256(peerPubK *ecdsa.PublicKey, plainSecret []byte) ([]byte, 
error) {
+       pk, x, y, err := elliptic.GenerateKey(elliptic.P256(), rand.Reader)
+       if err != nil {
+               return nil, errors.Wrapf(err, "Could not generate ephemeral EC 
keypair")
+       }
+
+       pubk := elliptic.Marshal(elliptic.P256(), x, y)
+
+       shared, _ := elliptic.P256().ScalarMult(peerPubK.X, peerPubK.Y, pk)
+
+       kdf := hkdf.New(sha256.New, shared.Bytes(), nil, 
[]byte("MCUBoot_ECIES_v1"))
+       derived := make([]byte, 48)
+       _, err = kdf.Read(derived)
+       if err != nil {
+               return nil, errors.Wrapf(err, "Error during key derivation")
+       }
+
+       cipherSecret, err := EncryptAES(plainSecret, derived[:16], nil)
+       if err != nil {
+               return nil, errors.Wrapf(err, "Error encrypting key")
+       }
+
+       h := hmac.New(sha256.New, derived[16:])
+       h.Write(cipherSecret)
+       mac := h.Sum(nil)
+
+       var tlv []byte
+       tlv = append(tlv, pubk...)
+       tlv = append(tlv, mac...)
+       tlv = append(tlv, cipherSecret...)
+
+       return tlv, nil
+}
+
 func encryptAes(c cipher.Block, plain []byte) ([]byte, error) {
        ciph, err := keywrap.Wrap(c, plain)
        if err != nil {
@@ -177,6 +218,8 @@ func (k *PubEncKey) Encrypt(plain []byte) ([]byte, error) {
 
        if k.Rsa != nil {
                return encryptRsa(k.Rsa, plain)
+       } else if k.Ec != nil {
+               return encryptEc256(k.Ec, plain)
        } else {
                return encryptAes(k.Aes, plain)
        }

Reply via email to