Added support for ECDH in enveloped data with ECDSA certificates.
- fixed parsing of choice(was compatible with Apple mail.app which tagged kari explicitly) - minor fixes
This commit is contained in:
163
oid/key_wrap.go
Normal file
163
oid/key_wrap.go
Normal file
@ -0,0 +1,163 @@
|
||||
package oid
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/subtle"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// KeyWrap wraps and unwraps key with the key encrytion key (KEK) for a given (KeyWrapAlgorithm)
|
||||
type KeyWrap struct {
|
||||
KEK []byte
|
||||
KeyWrapAlgorithm asn1.ObjectIdentifier
|
||||
}
|
||||
|
||||
// Wrap wraps the content encryption key (cek)
|
||||
func (kw *KeyWrap) Wrap(cek []byte) (ciphertext []byte, err error) {
|
||||
|
||||
var block cipher.Block
|
||||
switch kw.KeyWrapAlgorithm.String() {
|
||||
case AES128Wrap.String(), AES192Wrap.String(), AES256Wrap.String():
|
||||
block, err = aes.NewCipher(kw.KEK)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return Wrap(block, cek)
|
||||
|
||||
}
|
||||
|
||||
// UnWrap unwraps the encrypted key (encKey)
|
||||
func (kw *KeyWrap) UnWrap(encKey []byte) (cek []byte, err error) {
|
||||
|
||||
var block cipher.Block
|
||||
switch kw.KeyWrapAlgorithm.String() {
|
||||
case AES128Wrap.String(), AES192Wrap.String(), AES256Wrap.String():
|
||||
block, err = aes.NewCipher(kw.KEK)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return Unwrap(block, encKey)
|
||||
|
||||
}
|
||||
|
||||
// KeyLen returns the key lenght of the key wrap algorithm
|
||||
func (kw *KeyWrap) KeyLen() (len int) {
|
||||
|
||||
switch kw.KeyWrapAlgorithm.String() {
|
||||
case AES128Wrap.String():
|
||||
len = 16
|
||||
case AES192Wrap.String():
|
||||
len = 24
|
||||
case AES256Wrap.String():
|
||||
len = 32
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AlgorithmIdentifier returns the OID of the key wrap algorithm
|
||||
func (kw *KeyWrap) AlgorithmIdentifier() (algID pkix.AlgorithmIdentifier) {
|
||||
|
||||
switch kw.KeyWrapAlgorithm.String() {
|
||||
case AES128Wrap.String(), AES192Wrap.String(), AES256Wrap.String():
|
||||
algID = pkix.AlgorithmIdentifier{Algorithm: kw.KeyWrapAlgorithm}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// defaultIV from RFC-3394
|
||||
var defaultIV = []byte{0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}
|
||||
|
||||
// Wrap encrypts the content encryption key (cek) with the given AES cipher (block), using the AES Key Wrap algorithm (RFC-3394)
|
||||
func Wrap(block cipher.Block, cek []byte) (encKey []byte, err error) {
|
||||
if len(cek)%8 != 0 {
|
||||
return nil, errors.New("Lenght of cek must be in 8-byte blocks")
|
||||
}
|
||||
|
||||
// 1. Initialize variables
|
||||
|
||||
// Set A = IV, an initial value (see 2.2.3)
|
||||
B := make([]byte, 16)
|
||||
copy(B, defaultIV)
|
||||
|
||||
// For i = 1 to n
|
||||
// R[i] = P[i]
|
||||
encKey = make([]byte, len(cek)+8)
|
||||
copy(encKey[8:], cek)
|
||||
|
||||
n := len(cek) / 8
|
||||
|
||||
// 2. Calculate intermediate values.
|
||||
for j := 0; j <= 5; j++ {
|
||||
for i := 1; i <= n; i++ {
|
||||
|
||||
// B = AES(K, A | R[i])
|
||||
copy(B[8:], encKey[i*8:(i+1)*8])
|
||||
block.Encrypt(B, B)
|
||||
|
||||
// A = MSB(64, B) ^ t where t = (n*j)+i
|
||||
t := uint64(n*j + i)
|
||||
b := binary.BigEndian.Uint64(B[:8]) ^ t
|
||||
binary.BigEndian.PutUint64(B[:8], b)
|
||||
|
||||
// R[i] = LSB(64, B)
|
||||
copy(encKey[i*8:(i+1)*8], B[8:])
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Output the results.
|
||||
copy(encKey[:8], B[:8])
|
||||
return
|
||||
}
|
||||
|
||||
// Unwrap decrypts the provided encrypted key (encKey) with the given AES cipher (block), using the AES Key Wrap algorithm (RFC-3394).
|
||||
// Returns an error if validation fails.
|
||||
func Unwrap(block cipher.Block, encKey []byte) (cek []byte, err error) {
|
||||
if len(cek)%8 != 0 {
|
||||
return nil, errors.New("Length of encKey must multiple 8-bytes")
|
||||
}
|
||||
|
||||
//Initialize variables
|
||||
B := make([]byte, 16)
|
||||
copy(B, encKey[:8])
|
||||
|
||||
cek = make([]byte, len(encKey)-8)
|
||||
copy(cek, encKey[8:])
|
||||
|
||||
n := (len(encKey) / 8) - 1
|
||||
|
||||
//Compute intermediate values
|
||||
for j := 5; j >= 0; j-- {
|
||||
for i := n; i >= 1; i-- {
|
||||
|
||||
// B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
|
||||
copy(B[8:], cek[(i-1)*8:i*8])
|
||||
t := uint64(n*j + i)
|
||||
b := binary.BigEndian.Uint64(B[:8]) ^ t
|
||||
binary.BigEndian.PutUint64(B[:8], b)
|
||||
|
||||
block.Decrypt(B, B)
|
||||
|
||||
// A = MSB(64, B)
|
||||
// R[i] = LSB(64, B)
|
||||
copy(cek[(i-1)*8:i*8], B[8:])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if subtle.ConstantTimeCompare(B[:8], defaultIV) != 1 {
|
||||
return nil, errors.New("Integrity check failed - unexpected IV")
|
||||
}
|
||||
|
||||
//Output
|
||||
return
|
||||
}
|
51
oid/oid.go
51
oid/oid.go
@ -28,8 +28,13 @@ var (
|
||||
|
||||
// Signature Algorithm OIDs
|
||||
var (
|
||||
SignatureAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||
SignatureAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
SignatureAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||
SignatureAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
SignatureAlgorithmECDSAwithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||
SignatureAlgorithmECDSAwithSHA224 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 1}
|
||||
SignatureAlgorithmECDSAwithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||
SignatureAlgorithmECDSAwithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||
SignatureAlgorithmECDSAwithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
||||
)
|
||||
|
||||
// Public Key Encryption OIDs
|
||||
@ -51,6 +56,27 @@ var (
|
||||
SubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14}
|
||||
)
|
||||
|
||||
// Elliptic curve public key OID
|
||||
var (
|
||||
ECPublicKey = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
)
|
||||
|
||||
// DH Key Derivation Schemes OIDs
|
||||
var (
|
||||
DHSinglePassstdDHsha1kdfscheme = asn1.ObjectIdentifier{1, 3, 133, 16, 840, 63, 0, 2}
|
||||
DHSinglePassstdDHsha224kdfscheme = asn1.ObjectIdentifier{1, 3, 132, 1, 11, 0}
|
||||
DHSinglePassstdDHsha256kdfscheme = asn1.ObjectIdentifier{1, 3, 132, 1, 11, 1}
|
||||
DHSinglePassstdDHsha384kdfscheme = asn1.ObjectIdentifier{1, 3, 132, 1, 11, 2}
|
||||
DHSinglePassstdDHsha512kdfscheme = asn1.ObjectIdentifier{1, 3, 132, 1, 11, 3}
|
||||
)
|
||||
|
||||
// Key wrap algorithm OIDs
|
||||
var (
|
||||
AES128Wrap = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 5}
|
||||
AES192Wrap = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 25}
|
||||
AES256Wrap = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 45}
|
||||
)
|
||||
|
||||
// DigestAlgorithmToHash maps digest OIDs to crypto.Hash values.
|
||||
var DigestAlgorithmToHash = map[string]crypto.Hash{
|
||||
DigestAlgorithmSHA1.String(): crypto.SHA1,
|
||||
@ -113,6 +139,18 @@ var SignatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA384.String(): x509.ECDSAWithSHA384,
|
||||
DigestAlgorithmSHA512.String(): x509.ECDSAWithSHA512,
|
||||
},
|
||||
SignatureAlgorithmECDSAwithSHA1.String(): map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA1.String(): x509.ECDSAWithSHA1,
|
||||
},
|
||||
SignatureAlgorithmECDSAwithSHA256.String(): map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA256.String(): x509.ECDSAWithSHA256,
|
||||
},
|
||||
SignatureAlgorithmECDSAwithSHA384.String(): map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA384.String(): x509.ECDSAWithSHA384,
|
||||
},
|
||||
SignatureAlgorithmECDSAwithSHA512.String(): map[string]x509.SignatureAlgorithm{
|
||||
DigestAlgorithmSHA512.String(): x509.ECDSAWithSHA512,
|
||||
},
|
||||
}
|
||||
|
||||
// PublicKeyAlgorithmToSignatureAlgorithm maps certificate public key
|
||||
@ -127,3 +165,12 @@ var PublicKeyAlgorithmToSignatureAlgorithm = map[x509.PublicKeyAlgorithm]pkix.Al
|
||||
var PublicKeyAlgorithmToEncrytionAlgorithm = map[x509.PublicKeyAlgorithm]pkix.AlgorithmIdentifier{
|
||||
x509.RSA: pkix.AlgorithmIdentifier{Algorithm: EncryptionAlgorithmRSA},
|
||||
}
|
||||
|
||||
// KDFHashAlgorithm key derivation schemes to its hash algorithms
|
||||
var KDFHashAlgorithm = map[string]crypto.Hash{
|
||||
DHSinglePassstdDHsha1kdfscheme.String(): crypto.SHA1,
|
||||
DHSinglePassstdDHsha224kdfscheme.String(): crypto.SHA224,
|
||||
DHSinglePassstdDHsha256kdfscheme.String(): crypto.SHA256,
|
||||
DHSinglePassstdDHsha384kdfscheme.String(): crypto.SHA384,
|
||||
DHSinglePassstdDHsha512kdfscheme.String(): crypto.SHA512,
|
||||
}
|
||||
|
@ -32,9 +32,10 @@ var (
|
||||
AEADChaCha20Poly1305 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 3, 18}
|
||||
)
|
||||
|
||||
var symmetricKeyLen = map[string]int{
|
||||
EncryptionAlgorithmDESCBC.String(): 7,
|
||||
EncryptionAlgorithmDESEDE3CBC.String(): 21,
|
||||
// SymmetricKeyLen maps the encryption algorithm to its key length
|
||||
var SymmetricKeyLen = map[string]int{
|
||||
EncryptionAlgorithmDESCBC.String(): 8,
|
||||
EncryptionAlgorithmDESEDE3CBC.String(): 24,
|
||||
EncryptionAlgorithmAES128CBC.String(): 16,
|
||||
EncryptionAlgorithmAES256CBC.String(): 32,
|
||||
//AEAD
|
||||
@ -46,7 +47,7 @@ var symmetricKeyLen = map[string]int{
|
||||
func (e *EncryptionAlgorithm) Encrypt(plaintext []byte) (ciphertext []byte, err error) {
|
||||
|
||||
if e.Key == nil {
|
||||
e.Key = make([]byte, symmetricKeyLen[e.EncryptionAlgorithmIdentifier.String()])
|
||||
e.Key = make([]byte, SymmetricKeyLen[e.EncryptionAlgorithmIdentifier.String()])
|
||||
rand.Read(e.Key)
|
||||
}
|
||||
|
||||
@ -71,7 +72,7 @@ func (e *EncryptionAlgorithm) Encrypt(plaintext []byte) (ciphertext []byte, err
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String():
|
||||
if e.IV == nil {
|
||||
e.IV = make([]byte, len(e.Key))
|
||||
e.IV = make([]byte, blockCipher.BlockSize())
|
||||
rand.Read(e.IV)
|
||||
}
|
||||
|
||||
@ -180,7 +181,6 @@ func (e *EncryptionAlgorithm) Decrypt(ciphertext []byte) (plaintext []byte, err
|
||||
switch e.EncryptionAlgorithmIdentifier.String() {
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String(), EncryptionAlgorithmDESCBC.String(), EncryptionAlgorithmDESEDE3CBC.String():
|
||||
e.IV = e.ContentEncryptionAlgorithmIdentifier.Parameters.Bytes
|
||||
|
||||
blockMode = cipher.NewCBCDecrypter(blockCipher, e.IV)
|
||||
case EncryptionAlgorithmAES128GCM.String():
|
||||
aead, err = cipher.NewGCM(blockCipher)
|
||||
@ -198,7 +198,6 @@ func (e *EncryptionAlgorithm) Decrypt(ciphertext []byte) (plaintext []byte, err
|
||||
case EncryptionAlgorithmAES128CBC.String(), EncryptionAlgorithmAES256CBC.String(), EncryptionAlgorithmDESCBC.String(), EncryptionAlgorithmDESEDE3CBC.String():
|
||||
plaintext = make([]byte, len(ciphertext))
|
||||
blockMode.CryptBlocks(plaintext, ciphertext)
|
||||
|
||||
return unpad(plaintext, blockMode.BlockSize())
|
||||
case EncryptionAlgorithmAES128GCM.String(), AEADChaCha20Poly1305.String():
|
||||
var cipher []byte
|
||||
@ -247,6 +246,9 @@ func unpad(data []byte, blocklen int) ([]byte, error) {
|
||||
|
||||
// the last byte is the length of padding
|
||||
padlen := int(data[len(data)-1])
|
||||
if padlen > blocklen {
|
||||
return nil, fmt.Errorf("pad len %d is bigger than block len len %d", padlen, blocklen)
|
||||
}
|
||||
|
||||
// check padding integrity, all bytes should be the same
|
||||
pad := data[len(data)-padlen:]
|
||||
|
Reference in New Issue
Block a user