Update github.com/containerd/imgcrypt to v2.0.0
Signed-off-by: Kirtana Ashok <kiashok@microsoft.com>
This commit is contained in:
475
vendor/github.com/smallstep/pkcs7/encrypt.go
generated
vendored
Normal file
475
vendor/github.com/smallstep/pkcs7/encrypt.go
generated
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type envelopedData struct {
|
||||
Version int
|
||||
RecipientInfos []recipientInfo `asn1:"set"`
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type encryptedData struct {
|
||||
Version int
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type recipientInfo struct {
|
||||
Version int
|
||||
IssuerAndSerialNumber issuerAndSerial
|
||||
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedKey []byte
|
||||
}
|
||||
|
||||
type encryptedContentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent asn1.RawValue `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
const (
|
||||
// EncryptionAlgorithmDESCBC is the DES CBC encryption algorithm
|
||||
EncryptionAlgorithmDESCBC = iota
|
||||
|
||||
// EncryptionAlgorithmAES128CBC is the AES 128 bits with CBC encryption algorithm
|
||||
// Avoid this algorithm unless required for interoperability; use AES GCM instead.
|
||||
EncryptionAlgorithmAES128CBC
|
||||
|
||||
// EncryptionAlgorithmAES256CBC is the AES 256 bits with CBC encryption algorithm
|
||||
// Avoid this algorithm unless required for interoperability; use AES GCM instead.
|
||||
EncryptionAlgorithmAES256CBC
|
||||
|
||||
// EncryptionAlgorithmAES128GCM is the AES 128 bits with GCM encryption algorithm
|
||||
EncryptionAlgorithmAES128GCM
|
||||
|
||||
// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
|
||||
EncryptionAlgorithmAES256GCM
|
||||
)
|
||||
|
||||
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
|
||||
// plaintext message. Change the value of this variable to change which
|
||||
// algorithm is used in the Encrypt() function.
|
||||
var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC
|
||||
|
||||
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
|
||||
// content with an unsupported algorithm.
|
||||
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, and AES-GCM supported")
|
||||
|
||||
// KeyEncryptionAlgorithm determines the algorithm used to encrypt a
|
||||
// content key. Change the value of this variable to change which
|
||||
// algorithm is used in the Encrypt() function.
|
||||
var KeyEncryptionAlgorithm = OIDEncryptionAlgorithmRSA
|
||||
|
||||
// ErrUnsupportedKeyEncryptionAlgorithm is returned when an
|
||||
// unsupported key encryption algorithm OID is provided.
|
||||
var ErrUnsupportedKeyEncryptionAlgorithm = errors.New("pkcs7: unsupported key encryption algorithm provided")
|
||||
|
||||
// KeyEncryptionHash determines the crypto.Hash algorithm to use
|
||||
// when encrypting a content key. Change the value of this variable
|
||||
// to change which algorithm is used in the Encrypt() function.
|
||||
var KeyEncryptionHash = crypto.SHA256
|
||||
|
||||
// ErrUnsupportedKeyEncryptionHash is returned when an
|
||||
// unsupported key encryption hash is provided.
|
||||
var ErrUnsupportedKeyEncryptionHash = errors.New("pkcs7: unsupported key encryption hash provided")
|
||||
|
||||
// ErrPSKNotProvided is returned when attempting to encrypt
|
||||
// using a PSK without actually providing the PSK.
|
||||
var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided")
|
||||
|
||||
const nonceSize = 12
|
||||
|
||||
type aesGCMParameters struct {
|
||||
Nonce []byte `asn1:"tag:4"`
|
||||
ICVLen int
|
||||
}
|
||||
|
||||
func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||
var keyLen int
|
||||
var algID asn1.ObjectIdentifier
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmAES128GCM:
|
||||
keyLen = 16
|
||||
algID = OIDEncryptionAlgorithmAES128GCM
|
||||
case EncryptionAlgorithmAES256GCM:
|
||||
keyLen = 32
|
||||
algID = OIDEncryptionAlgorithmAES256GCM
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESGCM: %d", ContentEncryptionAlgorithm)
|
||||
}
|
||||
if key == nil {
|
||||
// Create AES key
|
||||
key = make([]byte, keyLen)
|
||||
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create nonce
|
||||
nonce := make([]byte, nonceSize)
|
||||
|
||||
_, err := rand.Read(nonce)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Encrypt content
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ciphertext := gcm.Seal(nil, nonce, content, nil)
|
||||
|
||||
// Prepare ASN.1 Encrypted Content Info
|
||||
paramSeq := aesGCMParameters{
|
||||
Nonce: nonce,
|
||||
ICVLen: gcm.Overhead(),
|
||||
}
|
||||
|
||||
paramBytes, err := asn1.Marshal(paramSeq)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
eci := encryptedContentInfo{
|
||||
ContentType: OIDData,
|
||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: algID,
|
||||
Parameters: asn1.RawValue{
|
||||
Tag: asn1.TagSequence,
|
||||
Bytes: paramBytes,
|
||||
},
|
||||
},
|
||||
EncryptedContent: marshalEncryptedContent(ciphertext),
|
||||
}
|
||||
|
||||
return key, &eci, nil
|
||||
}
|
||||
|
||||
func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||
if key == nil {
|
||||
// Create DES key
|
||||
key = make([]byte, 8)
|
||||
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create CBC IV
|
||||
iv := make([]byte, des.BlockSize)
|
||||
_, err := rand.Read(iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Encrypt padded content
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
plaintext, err := pad(content, mode.BlockSize())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cyphertext := make([]byte, len(plaintext))
|
||||
mode.CryptBlocks(cyphertext, plaintext)
|
||||
|
||||
// Prepare ASN.1 Encrypted Content Info
|
||||
eci := encryptedContentInfo{
|
||||
ContentType: OIDData,
|
||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: OIDEncryptionAlgorithmDESCBC,
|
||||
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||
},
|
||||
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||
}
|
||||
|
||||
return key, &eci, nil
|
||||
}
|
||||
|
||||
func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||
var keyLen int
|
||||
var algID asn1.ObjectIdentifier
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmAES128CBC:
|
||||
keyLen = 16
|
||||
algID = OIDEncryptionAlgorithmAES128CBC
|
||||
case EncryptionAlgorithmAES256CBC:
|
||||
keyLen = 32
|
||||
algID = OIDEncryptionAlgorithmAES256CBC
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESCBC: %d", ContentEncryptionAlgorithm)
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
// Create AES key
|
||||
key = make([]byte, keyLen)
|
||||
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create CBC IV
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, err := rand.Read(iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Encrypt padded content
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
plaintext, err := pad(content, mode.BlockSize())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cyphertext := make([]byte, len(plaintext))
|
||||
mode.CryptBlocks(cyphertext, plaintext)
|
||||
|
||||
// Prepare ASN.1 Encrypted Content Info
|
||||
eci := encryptedContentInfo{
|
||||
ContentType: OIDData,
|
||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: algID,
|
||||
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||
},
|
||||
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||
}
|
||||
|
||||
return key, &eci, nil
|
||||
}
|
||||
|
||||
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
||||
// recipient keys for each recipient public key.
|
||||
//
|
||||
// The algorithm used to perform encryption is determined by the current value
|
||||
// of the global ContentEncryptionAlgorithm package variable. By default, the
|
||||
// value is EncryptionAlgorithmDESCBC. To use a different algorithm, change the
|
||||
// value before calling Encrypt(). For example:
|
||||
//
|
||||
// ContentEncryptionAlgorithm = EncryptionAlgorithmAES256GCM
|
||||
//
|
||||
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
||||
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
|
||||
var eci *encryptedContentInfo
|
||||
var key []byte
|
||||
var err error
|
||||
|
||||
// Apply chosen symmetric encryption method
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmDESCBC:
|
||||
key, eci, err = encryptDESCBC(content, nil)
|
||||
case EncryptionAlgorithmAES128CBC:
|
||||
fallthrough
|
||||
case EncryptionAlgorithmAES256CBC:
|
||||
key, eci, err = encryptAESCBC(content, nil)
|
||||
case EncryptionAlgorithmAES128GCM:
|
||||
fallthrough
|
||||
case EncryptionAlgorithmAES256GCM:
|
||||
key, eci, err = encryptAESGCM(content, nil)
|
||||
|
||||
default:
|
||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare each recipient's encrypted cipher key
|
||||
recipientInfos := make([]recipientInfo, len(recipients))
|
||||
for i, recipient := range recipients {
|
||||
algorithm := KeyEncryptionAlgorithm
|
||||
hash := KeyEncryptionHash
|
||||
var kea pkix.AlgorithmIdentifier
|
||||
switch {
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP):
|
||||
parameters, err := getParametersForKeyEncryptionAlgorithm(algorithm, hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parameters for key encryption: %v", err)
|
||||
}
|
||||
kea = pkix.AlgorithmIdentifier{
|
||||
Algorithm: algorithm,
|
||||
Parameters: parameters,
|
||||
}
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSA):
|
||||
kea = pkix.AlgorithmIdentifier{
|
||||
Algorithm: algorithm,
|
||||
}
|
||||
default:
|
||||
return nil, ErrUnsupportedKeyEncryptionAlgorithm
|
||||
}
|
||||
encrypted, err := encryptKey(key, recipient, algorithm, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ias, err := cert2issuerAndSerial(recipient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info := recipientInfo{
|
||||
Version: 0,
|
||||
IssuerAndSerialNumber: ias,
|
||||
KeyEncryptionAlgorithm: kea,
|
||||
EncryptedKey: encrypted,
|
||||
}
|
||||
recipientInfos[i] = info
|
||||
}
|
||||
|
||||
// Prepare envelope content
|
||||
envelope := envelopedData{
|
||||
EncryptedContentInfo: *eci,
|
||||
Version: 0,
|
||||
RecipientInfos: recipientInfos,
|
||||
}
|
||||
innerContent, err := asn1.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare outer payload structure
|
||||
wrapper := contentInfo{
|
||||
ContentType: OIDEnvelopedData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||
}
|
||||
|
||||
return asn1.Marshal(wrapper)
|
||||
}
|
||||
|
||||
func getParametersForKeyEncryptionAlgorithm(algorithm asn1.ObjectIdentifier, hash crypto.Hash) (asn1.RawValue, error) {
|
||||
if !algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP) {
|
||||
return asn1.RawValue{}, nil // return empty; not used
|
||||
}
|
||||
|
||||
params := rsaOAEPAlgorithmParameters{}
|
||||
switch hash {
|
||||
case crypto.SHA1:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA1}
|
||||
case crypto.SHA224:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA224}
|
||||
case crypto.SHA256:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA256}
|
||||
case crypto.SHA384:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA384}
|
||||
case crypto.SHA512:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA512}
|
||||
default:
|
||||
return asn1.RawValue{}, ErrUnsupportedAlgorithm
|
||||
}
|
||||
|
||||
b, err := asn1.Marshal(params)
|
||||
if err != nil {
|
||||
return asn1.RawValue{}, fmt.Errorf("failed marshaling key encryption parameters: %v", err)
|
||||
}
|
||||
|
||||
return asn1.RawValue{
|
||||
FullBytes: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
|
||||
// encrypted using caller provided pre-shared secret.
|
||||
func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
|
||||
var eci *encryptedContentInfo
|
||||
var err error
|
||||
|
||||
if key == nil {
|
||||
return nil, ErrPSKNotProvided
|
||||
}
|
||||
|
||||
// Apply chosen symmetric encryption method
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmDESCBC:
|
||||
_, eci, err = encryptDESCBC(content, key)
|
||||
|
||||
case EncryptionAlgorithmAES128GCM:
|
||||
fallthrough
|
||||
case EncryptionAlgorithmAES256GCM:
|
||||
_, eci, err = encryptAESGCM(content, key)
|
||||
|
||||
default:
|
||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare encrypted-data content
|
||||
ed := encryptedData{
|
||||
Version: 0,
|
||||
EncryptedContentInfo: *eci,
|
||||
}
|
||||
innerContent, err := asn1.Marshal(ed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare outer payload structure
|
||||
wrapper := contentInfo{
|
||||
ContentType: OIDEncryptedData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||
}
|
||||
|
||||
return asn1.Marshal(wrapper)
|
||||
}
|
||||
|
||||
func marshalEncryptedContent(content []byte) asn1.RawValue {
|
||||
return asn1.RawValue{Bytes: content, Class: 2, IsCompound: false}
|
||||
}
|
||||
|
||||
func encryptKey(key []byte, recipient *x509.Certificate, algorithm asn1.ObjectIdentifier, hash crypto.Hash) ([]byte, error) {
|
||||
pub, ok := recipient.PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, ErrUnsupportedKeyType
|
||||
}
|
||||
|
||||
switch {
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSA):
|
||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP):
|
||||
return rsa.EncryptOAEP(hash.New(), rand.Reader, pub, key, nil)
|
||||
default:
|
||||
return nil, ErrUnsupportedKeyEncryptionAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
func pad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen < 1 {
|
||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||
}
|
||||
padlen := blocklen - (len(data) % blocklen)
|
||||
if padlen == 0 {
|
||||
padlen = blocklen
|
||||
}
|
||||
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
|
||||
return append(data, pad...), nil
|
||||
}
|
||||
Reference in New Issue
Block a user