Skip to content

Commit

Permalink
Add AES128-GCM96 support to transit (#7555)
Browse files Browse the repository at this point in the history
  • Loading branch information
jefferai authored Oct 3, 2019
1 parent 406cc1b commit 6737e46
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 31 deletions.
2 changes: 2 additions & 0 deletions builtin/logical/transit/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -968,8 +968,10 @@ func testDerivedKeyUpgrade(t *testing.T, keyType keysutil.KeyType) {

func TestConvergentEncryption(t *testing.T) {
testConvergentEncryptionCommon(t, 0, keysutil.KeyType_AES256_GCM96)
testConvergentEncryptionCommon(t, 2, keysutil.KeyType_AES128_GCM96)
testConvergentEncryptionCommon(t, 2, keysutil.KeyType_AES256_GCM96)
testConvergentEncryptionCommon(t, 2, keysutil.KeyType_ChaCha20_Poly1305)
testConvergentEncryptionCommon(t, 3, keysutil.KeyType_AES128_GCM96)
testConvergentEncryptionCommon(t, 3, keysutil.KeyType_AES256_GCM96)
testConvergentEncryptionCommon(t, 3, keysutil.KeyType_ChaCha20_Poly1305)
}
Expand Down
2 changes: 2 additions & 0 deletions builtin/logical/transit/path_backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

func TestTransit_BackupRestore(t *testing.T) {
// Test encryption/decryption after a restore for supported keys
testBackupRestore(t, "aes128-gcm96", "encrypt-decrypt")
testBackupRestore(t, "aes256-gcm96", "encrypt-decrypt")
testBackupRestore(t, "chacha20-poly1305", "encrypt-decrypt")
testBackupRestore(t, "rsa-2048", "encrypt-decrypt")
Expand All @@ -23,6 +24,7 @@ func TestTransit_BackupRestore(t *testing.T) {
testBackupRestore(t, "rsa-4096", "sign-verify")

// Test HMAC/verification after a restore for all key types
testBackupRestore(t, "aes128-gcm96", "hmac-verify")
testBackupRestore(t, "aes256-gcm96", "hmac-verify")
testBackupRestore(t, "chacha20-poly1305", "hmac-verify")
testBackupRestore(t, "ecdsa-p256", "hmac-verify")
Expand Down
30 changes: 26 additions & 4 deletions builtin/logical/transit/path_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ func TestTransit_ConfigSettings(t *testing.T) {
req := &logical.Request{
Storage: storage,
Operation: logical.UpdateOperation,
Path: "keys/aes",
Path: "keys/aes256",
Data: map[string]interface{}{
"derived": true,
},
}
doReq(req)

req.Path = "keys/aes128"
req.Data["type"] = "aes128-gcm96"
doReq(req)

req.Path = "keys/ed"
req.Data["type"] = "ed25519"
doReq(req)
Expand All @@ -59,7 +63,13 @@ func TestTransit_ConfigSettings(t *testing.T) {

delete(req.Data, "type")

req.Path = "keys/aes/rotate"
req.Path = "keys/aes128/rotate"
doReq(req)
doReq(req)
doReq(req)
doReq(req)

req.Path = "keys/aes256/rotate"
doReq(req)
doReq(req)
doReq(req)
Expand Down Expand Up @@ -89,7 +99,7 @@ func TestTransit_ConfigSettings(t *testing.T) {
doReq(req)
doReq(req)

req.Path = "keys/aes/config"
req.Path = "keys/aes256/config"
// Too high
req.Data["min_decryption_version"] = 7
doErrReq(req)
Expand All @@ -114,6 +124,8 @@ func TestTransit_ConfigSettings(t *testing.T) {
req.Data["min_decryption_version"] = 2
req.Data["min_encryption_version"] = 3
doReq(req)
req.Path = "keys/aes128/config"
doReq(req)
req.Path = "keys/ed/config"
doReq(req)
req.Path = "keys/p256/config"
Expand All @@ -131,7 +143,7 @@ func TestTransit_ConfigSettings(t *testing.T) {
}

maxKeyVersion := 5
key := "aes"
key := "aes256"

testHMAC := func(ver int, valid bool) {
req.Path = "hmac/" + key
Expand Down Expand Up @@ -193,6 +205,16 @@ func TestTransit_ConfigSettings(t *testing.T) {
testHMAC(3, true)
testHMAC(2, false)

key = "aes128"
testEncryptDecrypt(5, true)
testEncryptDecrypt(4, true)
testEncryptDecrypt(3, true)
testEncryptDecrypt(2, false)
testHMAC(5, true)
testHMAC(4, true)
testHMAC(3, true)
testHMAC(2, false)

delete(req.Data, "plaintext")
req.Data["input"] = "abcd"
key = "ed"
Expand Down
5 changes: 3 additions & 2 deletions builtin/logical/transit/path_encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ encryption key) this nonce value is **never reused**.
Description: `
This parameter is required when encryption key is expected to be created.
When performing an upsert operation, the type of key to create. Currently,
"aes256-gcm96" (symmetric) is the only type supported. Defaults to
"aes256-gcm96".`,
"aes128-gcm96" (symmetric) and "aes256-gcm96" (symmetric) are the only types supported. Defaults to "aes256-gcm96".`,
},

"convergent_encryption": &framework.FieldSchema{
Expand Down Expand Up @@ -228,6 +227,8 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d

keyType := d.Get("type").(string)
switch keyType {
case "aes128-gcm96":
polReq.KeyType = keysutil.KeyType_AES128_GCM96
case "aes256-gcm96":
polReq.KeyType = keysutil.KeyType_AES256_GCM96
case "chacha20-poly1305":
Expand Down
2 changes: 1 addition & 1 deletion builtin/logical/transit/path_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func getExportKey(policy *keysutil.Policy, key *keysutil.KeyEntry, exportType st

case exportTypeEncryptionKey:
switch policy.Type {
case keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
case keysutil.KeyType_AES128_GCM96, keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
return strings.TrimSpace(base64.StdEncoding.EncodeToString(key.Key)), nil

case keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096:
Expand Down
2 changes: 2 additions & 0 deletions builtin/logical/transit/path_export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import (
)

func TestTransit_Export_KeyVersion_ExportsCorrectVersion(t *testing.T) {
verifyExportsCorrectVersion(t, "encryption-key", "aes128-gcm96")
verifyExportsCorrectVersion(t, "encryption-key", "aes256-gcm96")
verifyExportsCorrectVersion(t, "encryption-key", "chacha20-poly1305")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p256")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p384")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p521")
verifyExportsCorrectVersion(t, "signing-key", "ed25519")
verifyExportsCorrectVersion(t, "hmac-key", "aes128-gcm96")
verifyExportsCorrectVersion(t, "hmac-key", "aes256-gcm96")
verifyExportsCorrectVersion(t, "hmac-key", "chacha20-poly1305")
verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p256")
Expand Down
6 changes: 4 additions & 2 deletions builtin/logical/transit/path_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (b *backend) pathKeys() *framework.Path {
Type: framework.TypeString,
Default: "aes256-gcm96",
Description: `
The type of key to create. Currently, "aes256-gcm96" (symmetric), "ecdsa-p256"
The type of key to create. Currently, "aes128-gcm96" (symmetric), "aes256-gcm96" (symmetric), "ecdsa-p256"
(asymmetric), "ecdsa-p384" (asymmetric), "ecdsa-p521" (asymmetric), "ed25519" (asymmetric), "rsa-2048" (asymmetric), "rsa-4096"
(asymmetric) are supported. Defaults to "aes256-gcm96".
`,
Expand Down Expand Up @@ -139,6 +139,8 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
AllowPlaintextBackup: allowPlaintextBackup,
}
switch keyType {
case "aes128-gcm96":
polReq.KeyType = keysutil.KeyType_AES128_GCM96
case "aes256-gcm96":
polReq.KeyType = keysutil.KeyType_AES256_GCM96
case "chacha20-poly1305":
Expand Down Expand Up @@ -260,7 +262,7 @@ func (b *backend) pathPolicyRead(ctx context.Context, req *logical.Request, d *f
}

switch p.Type {
case keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
case keysutil.KeyType_AES128_GCM96, keysutil.KeyType_AES256_GCM96, keysutil.KeyType_ChaCha20_Poly1305:
retKeys := map[string]int64{}
for k, v := range p.Keys {
retKeys[k] = v.DeprecatedCreationTime
Expand Down
2 changes: 1 addition & 1 deletion sdk/helper/keysutil/lock_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest) (retP *
// because we don't know if the parameters match.

switch req.KeyType {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
if req.Convergent && !req.Derived {
cleanup()
return nil, false, fmt.Errorf("convergent encryption requires derivation to be enabled")
Expand Down
59 changes: 38 additions & 21 deletions sdk/helper/keysutil/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const (
KeyType_ChaCha20_Poly1305
KeyType_ECDSA_P384
KeyType_ECDSA_P521
KeyType_AES128_GCM96
)

const (
Expand Down Expand Up @@ -91,15 +92,15 @@ type KeyType int

func (kt KeyType) EncryptionSupported() bool {
switch kt {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096:
return true
}
return false
}

func (kt KeyType) DecryptionSupported() bool {
switch kt {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA4096:
return true
}
return false
Expand All @@ -123,14 +124,16 @@ func (kt KeyType) HashSignatureInput() bool {

func (kt KeyType) DerivationSupported() bool {
switch kt {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_ED25519:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_ED25519:
return true
}
return false
}

func (kt KeyType) String() string {
switch kt {
case KeyType_AES128_GCM96:
return "aes128-gcm96"
case KeyType_AES256_GCM96:
return "aes256-gcm96"
case KeyType_ChaCha20_Poly1305:
Expand Down Expand Up @@ -729,7 +732,7 @@ func (p *Policy) DeriveKey(context []byte, ver, numBytes int) ([]byte, error) {
}

switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
n, err := derBytes.ReadFrom(limReader)
if err != nil {
return nil, errutil.InternalError{Err: fmt.Sprintf("error reading returned derived bytes: %v", err)}
Expand Down Expand Up @@ -800,40 +803,45 @@ func (p *Policy) Encrypt(ver int, context, nonce []byte, value string) (string,
var ciphertext []byte

switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
hmacKey := context

var aead cipher.AEAD
var encKey []byte
var deriveHMAC bool

numBytes := 32
encBytes := 32
hmacBytes := 0
if p.convergentVersion(ver) > 2 {
deriveHMAC = true
numBytes = 64
hmacBytes = 32
}
if p.Type == KeyType_AES128_GCM96 {
encBytes = 16
}
key, err := p.DeriveKey(context, ver, numBytes)

key, err := p.DeriveKey(context, ver, encBytes+hmacBytes)
if err != nil {
return "", err
}

if len(key) < numBytes {
if len(key) < encBytes+hmacBytes {
return "", errutil.InternalError{Err: "could not derive key, length too small"}
}

encKey = key[:32]
if len(encKey) != 32 {
encKey = key[:encBytes]
if len(encKey) != encBytes {
return "", errutil.InternalError{Err: "could not derive enc key, length not correct"}
}
if deriveHMAC {
hmacKey = key[32:]
if len(hmacKey) != 32 {
hmacKey = key[encBytes:]
if len(hmacKey) != hmacBytes {
return "", errutil.InternalError{Err: "could not derive hmac key, length not correct"}
}
}

switch p.Type {
case KeyType_AES256_GCM96:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96:
// Setup the cipher
aesCipher, err := aes.NewCipher(encKey)
if err != nil {
Expand Down Expand Up @@ -964,20 +972,25 @@ func (p *Policy) Decrypt(context, nonce []byte, value string) (string, error) {
var plain []byte

switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
var aead cipher.AEAD

encKey, err := p.DeriveKey(context, ver, 32)
numBytes := 32
if p.Type == KeyType_AES128_GCM96 {
numBytes = 16
}

encKey, err := p.DeriveKey(context, ver, numBytes)
if err != nil {
return "", err
}

if len(encKey) != 32 {
if len(encKey) != numBytes {
return "", errutil.InternalError{Err: "could not derive enc key, length not correct"}
}

switch p.Type {
case KeyType_AES256_GCM96:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96:
// Setup the cipher
aesCipher, err := aes.NewCipher(encKey)
if err != nil {
Expand Down Expand Up @@ -1399,9 +1412,13 @@ func (p *Policy) Rotate(ctx context.Context, storage logical.Storage) (retErr er
entry.HMACKey = hmacKey

switch p.Type {
case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
// Generate a 256bit key
newKey, err := uuid.GenerateRandomBytes(32)
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
// Default to 256 bit key
numBytes := 32
if p.Type == KeyType_AES128_GCM96 {
numBytes = 16
}
newKey, err := uuid.GenerateRandomBytes(numBytes)
if err != nil {
return err
}
Expand Down

0 comments on commit 6737e46

Please sign in to comment.