forked from edgexfoundry/app-functions-sdk-go
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(transforms): new AES 256 Encryption Transform (edgexfoundry#984)
Add new transform using AES 256 Encryption with a SHA512 authentication mechanism. Fixes edgexfoundry#968 Signed-off-by: Alex Ullrich <[email protected]>
- Loading branch information
Showing
9 changed files
with
734 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2014 Coda Hale | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# etm | ||
|
||
This package contains code retrieved from https://github.com/codahale/etm on 2021-10-28. It implements the crypto.AEAD interface using AES-CBC encryption and sha hashing algorithms. It was stripped of all aead constructions other than `AEAD_AES_256_CBC_HMAC_SHA_512` to fit our usage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
// Package etm provides a set of Encrypt-Then-MAC AEAD implementations, which | ||
// combine block ciphers like AES with HMACs. | ||
// | ||
// AEADs | ||
// | ||
// An AEAD (Authenticated Encryption with Associated Data) construction provides | ||
// a unified API for sealing messages in a way which provides both | ||
// confidentiality *and* integrity. | ||
// | ||
// This not only prevents malicious tampering but also eliminates online attacks | ||
// like padding oracle attacks which can allow an attacker to recover plaintexts | ||
// without knowledge of the secret key (e.g., Lucky 13 attack, BEAST attack, | ||
// etc.). | ||
// | ||
// By rejecting ciphertexts which have been modified, these types of attacks are | ||
// eliminated. | ||
// | ||
// Constructions | ||
// | ||
// This package implements one of five proposed standards: | ||
// | ||
// AEAD_AES_256_CBC_HMAC_SHA_512 | ||
// | ||
// Four proposed standards were removed because they aren't used here: | ||
// | ||
// AEAD_AES_128_CBC_HMAC_SHA_256 | ||
// AEAD_AES_192_CBC_HMAC_SHA_384 | ||
// AEAD_AES_256_CBC_HMAC_SHA_384 | ||
// AEAD_AES_128_CBC_HMAC_SHA1 | ||
// | ||
// All constructions combine AES in CBC mode with an HMAC, but vary in the | ||
// degree of security offered and the amount of overhead required. See | ||
// http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-02 for full | ||
// technical details. | ||
// | ||
// AES-128-CBC-HMAC-SHA-256 | ||
// | ||
// AEAD_AES_128_CBC_HMAC_SHA_256 requires a 32-byte key, provides 128 bits of | ||
// security for both confidentiality and integrity, and adds up to 56 bytes of | ||
// overhead per message. | ||
// | ||
// AES-192-CBC-HMAC-SHA-384 | ||
// | ||
// AEAD_AES_192_CBC_HMAC_SHA_384 requires a 48-byte key, provides 192 bits of | ||
// security for both confidentiality and integrity, and adds up to 64 bytes of | ||
// overhead per message. | ||
// | ||
// AES-256-CBC-HMAC-SHA-384 | ||
// | ||
// AEAD_AES_256_CBC_HMAC_SHA_384 requires a 56-byte key, provides 256 bits of | ||
// security for confidentiality, provides 192 bits of security for integrity, and | ||
// adds up to 64 bytes of overhead per message. | ||
// | ||
// AES-256-CBC-HMAC-SHA-512 | ||
// | ||
// AEAD_AES_256_CBC_HMAC_SHA_512 requires a 64-byte key, provides 256 bits of | ||
// security for both confidentiality and integrity, and adds up to 72 bytes of | ||
// overhead per message. | ||
// | ||
package etm | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"crypto/hmac" | ||
"crypto/sha512" | ||
"encoding/binary" | ||
"errors" | ||
"fmt" | ||
"hash" | ||
) | ||
|
||
// NewAES256SHA512 returns an AEAD_AES_256_CBC_HMAC_SHA_512 instance given a | ||
// 64-byte key or an error if the key is the wrong size. | ||
// AEAD_AES_256_CBC_HMAC_SHA_512 combines AES-256 in CBC mode with | ||
// HMAC-SHA-512-256. | ||
func NewAES256SHA512(key []byte) (cipher.AEAD, error) { | ||
return create(etmParams{ | ||
cipherParams: aesCBC, | ||
macAlg: sha512.New, | ||
encKeySize: 32, | ||
macKeySize: 32, | ||
tagSize: 32, | ||
key: key, | ||
}) | ||
} | ||
|
||
type etmParams struct { | ||
cipherParams | ||
encKeySize, macKeySize, tagSize int | ||
|
||
key []byte | ||
macAlg func() hash.Hash | ||
} | ||
|
||
func create(p etmParams) (cipher.AEAD, error) { | ||
l := p.encKeySize + p.macKeySize | ||
if len(p.key) != l { | ||
return nil, fmt.Errorf("etm: key must be %d bytes long", l) | ||
} | ||
encKey, macKey := split(p.key, p.encKeySize, p.macKeySize) | ||
return &etmAEAD{ | ||
etmParams: p, | ||
encKey: encKey, | ||
macKey: macKey, | ||
}, nil | ||
} | ||
|
||
const ( | ||
dataLenSize = 8 | ||
) | ||
|
||
type etmAEAD struct { | ||
etmParams | ||
encKey, macKey []byte | ||
} | ||
|
||
func (aead *etmAEAD) Overhead() int { | ||
return aead.padSize + aead.tagSize + dataLenSize + aead.NonceSize() | ||
} | ||
|
||
func (aead *etmAEAD) NonceSize() int { | ||
return aead.nonceSize | ||
} | ||
|
||
func (aead *etmAEAD) Seal(dst, nonce, plaintext, data []byte) []byte { | ||
b, _ := aead.encAlg(aead.encKey) // guaranteed to work | ||
|
||
c := aead.encrypter(b, nonce) | ||
i := aead.pad(plaintext, aead.blockSize) | ||
s := make([]byte, len(i)) | ||
c.CryptBlocks(s, i) | ||
s = append(nonce, s...) | ||
|
||
t := tag(hmac.New(aead.macAlg, aead.macKey), data, s, aead.tagSize) | ||
|
||
return append(dst, append(s, t...)...) | ||
} | ||
|
||
func (aead *etmAEAD) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { | ||
s := ciphertext[:len(ciphertext)-aead.tagSize] | ||
t := ciphertext[len(ciphertext)-aead.tagSize:] | ||
t2 := tag(hmac.New(aead.macAlg, aead.macKey), data, s, aead.tagSize) | ||
if nonce == nil { | ||
nonce = s[:aead.NonceSize()] | ||
} | ||
|
||
if !hmac.Equal(t, t2) { | ||
return nil, errors.New("message authentication failed") | ||
} | ||
|
||
b, _ := aead.encAlg(aead.encKey) // guaranteed to work | ||
|
||
c := aead.decrypter(b, nonce) | ||
o := make([]byte, len(s)-len(nonce)) | ||
c.CryptBlocks(o, s[len(nonce):]) | ||
|
||
return append(dst, aead.unpad(o, aead.blockSize)...), nil | ||
} | ||
|
||
type cipherParams struct { | ||
nonceSize, blockSize, padSize int | ||
|
||
encAlg func(key []byte) (cipher.Block, error) | ||
encrypter func(cipher.Block, []byte) cipher.BlockMode | ||
decrypter func(cipher.Block, []byte) cipher.BlockMode | ||
pad func([]byte, int) []byte | ||
unpad func([]byte, int) []byte | ||
} | ||
|
||
// AES-CBC-PKCS7 | ||
var aesCBC = cipherParams{ | ||
encAlg: aes.NewCipher, | ||
blockSize: aes.BlockSize, | ||
nonceSize: aes.BlockSize, | ||
encrypter: cipher.NewCBCEncrypter, | ||
decrypter: cipher.NewCBCDecrypter, | ||
padSize: aes.BlockSize, | ||
pad: pkcs7pad, | ||
unpad: pkcs7unpad, | ||
} | ||
|
||
func tag(h hash.Hash, data, s []byte, l int) []byte { | ||
al := make([]byte, dataLenSize) | ||
binary.BigEndian.PutUint64(al, uint64(len(data)*8)) // in bits | ||
h.Write(data) | ||
h.Write(s) | ||
h.Write(al) | ||
return h.Sum(nil)[:l] | ||
} | ||
|
||
func split(key []byte, encKeyLen, macKeyLen int) ([]byte, []byte) { | ||
return key[0:encKeyLen], key[len(key)-macKeyLen:] | ||
} | ||
|
||
func pkcs7pad(b []byte, blockSize int) []byte { | ||
ps := make([]byte, blockSize-(len(b)%blockSize)) | ||
for i := range ps { | ||
ps[i] = byte(len(ps)) | ||
} | ||
return append(b, ps...) | ||
} | ||
|
||
func pkcs7unpad(b []byte, _ int) []byte { | ||
return b[:len(b)-int(b[len(b)-1])] | ||
} |
Oops, something went wrong.