You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ut...@apache.org on 2018/10/12 16:07:59 UTC

[mynewt-newt] 03/04: Allow encrypted images using aes-128 keywrap

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-newt.git

commit 06bd71e7776b7e3d8e58ccaf21e0ab47eb8fa203
Author: Fabio Utzig <ut...@apache.org>
AuthorDate: Tue Sep 11 20:27:27 2018 -0300

    Allow encrypted images using aes-128 keywrap
    
    This adds an extra method of encrypted image creation, using
    AES-128-KEK. This requires a recent version of mbedtls with nist_kw
    support and decreases the flash usage by 8KB from RSA-OAEP. The key file
    must be provided in base64 format and it's decoded content should be a
    16 byte random key.
    
    To generate a key:
    
    > dd if=/dev/urandom of=/dev/stdout bs=1 count=16 | base64 > aes-128-kek.b64
---
 newt/image/image.go | 78 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 54 insertions(+), 24 deletions(-)

diff --git a/newt/image/image.go b/newt/image/image.go
index 80546e5..bbc6b5a 100644
--- a/newt/image/image.go
+++ b/newt/image/image.go
@@ -30,6 +30,7 @@ import (
 	"crypto/sha256"
 	"crypto/x509"
 	"encoding/asn1"
+	"encoding/base64"
 	"encoding/binary"
 	"encoding/hex"
 	"encoding/pem"
@@ -42,6 +43,7 @@ import (
 	"strconv"
 	"strings"
 
+	keywrap "github.com/NickBall/go-aes-key-wrap"
 	log "github.com/Sirupsen/logrus"
 
 	"mynewt.apache.org/newt/newt/pkg"
@@ -155,7 +157,8 @@ const (
 	IMAGE_TLV_RSA2048  = 0x20
 	IMAGE_TLV_ECDSA224 = 0x21
 	IMAGE_TLV_ECDSA256 = 0x22
-	IMAGE_TLV_ENCKEY   = 0x30
+	IMAGE_TLV_ENC_RSA  = 0x30
+	IMAGE_TLV_ENC_KEK  = 0x31
 )
 
 /*
@@ -869,39 +872,59 @@ func (image *Image) generateV2(loader *Image) error {
 
 	plainSecret := make([]byte, 16)
 	var cipherSecret []byte
+	var _type uint8
 	if PubKeyFile != "" {
+		_, err = rand.Read(plainSecret)
+		if err != nil {
+			return util.NewNewtError(fmt.Sprintf("Random generation error: %s\n", err))
+		}
+
 		keyBytes, err := ioutil.ReadFile(PubKeyFile)
 		if err != nil {
 			return util.NewNewtError(fmt.Sprintf("Error reading pubkey file: %s", err))
 		}
 
+		// Try reading as PEM (asymetric key), if it fails, assume this is a
+		// base64 encoded symetric key
 		b, _ := pem.Decode(keyBytes)
-		if b == nil || (b.Type != "PUBLIC KEY" && b.Type != "RSA PUBLIC KEY") {
-			return util.NewNewtError(fmt.Sprintf("Error decoding pubkey file: %s", err))
-		}
+		if b == nil {
+			kek, err := base64.StdEncoding.DecodeString(string(keyBytes))
+			if err != nil {
+				return util.NewNewtError(fmt.Sprintf("Error decoding kek: %s", err))
+			} else if len(kek) != 16 {
+				return util.NewNewtError(fmt.Sprintf("Unexpected key size: %d != 16", len(kek)))
+			}
 
-		pub, err := x509.ParsePKIXPublicKey(b.Bytes)
-		if err != nil {
-			return util.NewNewtError(fmt.Sprintf("Error parsing pubkey file: %s", err))
-		}
+			cipher, err := aes.NewCipher(kek)
+			if err != nil {
+				return util.NewNewtError(fmt.Sprintf("Error creating keywrap cipher: %s", err))
+			}
 
-		var pubk *rsa.PublicKey
-		switch pub.(type) {
-		case *rsa.PublicKey:
-			pubk = pub.(*rsa.PublicKey)
-		default:
-			return util.NewNewtError(fmt.Sprintf("Error parsing pubkey file: %s", err))
-		}
+			cipherSecret, err = keywrap.Wrap(cipher, plainSecret)
+			if err != nil {
+				return util.NewNewtError(fmt.Sprintf("Error key-wrapping: %s", err))
+			}
+		} else if b.Type != "PUBLIC KEY" && b.Type != "RSA PUBLIC KEY" {
+			return util.NewNewtError("Invalid PEM file")
+		} else {
+			pub, err := x509.ParsePKIXPublicKey(b.Bytes)
+			if err != nil {
+				return util.NewNewtError(fmt.Sprintf("Error parsing pubkey file: %s", err))
+			}
 
-		_, err = rand.Read(plainSecret)
-		if err != nil {
-			return util.NewNewtError(fmt.Sprintf("Random generation error: %s\n", err))
-		}
+			var pubk *rsa.PublicKey
+			switch pub.(type) {
+			case *rsa.PublicKey:
+				pubk = pub.(*rsa.PublicKey)
+			default:
+				return util.NewNewtError(fmt.Sprintf("Error parsing pubkey file: %s", err))
+			}
 
-		rng := rand.Reader
-		cipherSecret, err = rsa.EncryptOAEP(sha256.New(), rng, pubk, plainSecret, nil)
-		if err != nil {
-			return util.NewNewtError(fmt.Sprintf("Error from encryption: %s\n", err))
+			rng := rand.Reader
+			cipherSecret, err = rsa.EncryptOAEP(sha256.New(), rng, pubk, plainSecret, nil)
+			if err != nil {
+				return util.NewNewtError(fmt.Sprintf("Error from encryption: %s\n", err))
+			}
 		}
 	}
 
@@ -1187,8 +1210,15 @@ func (image *Image) generateV2(loader *Image) error {
 	}
 
 	if cipherSecret != nil {
+		if len(cipherSecret) == 256 {
+			_type = IMAGE_TLV_ENC_RSA
+		} else if len(cipherSecret) == 24 {
+			_type = IMAGE_TLV_ENC_KEK
+		} else {
+			return util.NewNewtError(fmt.Sprintf("Invalid enc TLV size "))
+		}
 		tlv := &ImageTrailerTlv{
-			Type: IMAGE_TLV_ENCKEY,
+			Type: _type,
 			Pad:  0,
 			Len:  uint16(len(cipherSecret)),
 		}