podman
177 строк · 5.1 Кб
1package pkcs7
2
3import (
4"bytes"
5"crypto"
6"crypto/aes"
7"crypto/cipher"
8"crypto/des"
9"crypto/rand"
10"crypto/rsa"
11"crypto/x509"
12"encoding/asn1"
13"errors"
14"fmt"
15)
16
17// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
18var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported")
19
20// ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data
21var ErrNotEncryptedContent = errors.New("pkcs7: content data is a decryptable data type")
22
23// Decrypt decrypts encrypted content info for recipient cert and private key
24func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
25data, ok := p7.raw.(envelopedData)
26if !ok {
27return nil, ErrNotEncryptedContent
28}
29recipient := selectRecipientForCertificate(data.RecipientInfos, cert)
30if recipient.EncryptedKey == nil {
31return nil, errors.New("pkcs7: no enveloped recipient for provided certificate")
32}
33switch pkey := pkey.(type) {
34case *rsa.PrivateKey:
35var contentKey []byte
36contentKey, err := rsa.DecryptPKCS1v15(rand.Reader, pkey, recipient.EncryptedKey)
37if err != nil {
38return nil, err
39}
40return data.EncryptedContentInfo.decrypt(contentKey)
41}
42return nil, ErrUnsupportedAlgorithm
43}
44
45// DecryptUsingPSK decrypts encrypted data using caller provided
46// pre-shared secret
47func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error) {
48data, ok := p7.raw.(encryptedData)
49if !ok {
50return nil, ErrNotEncryptedContent
51}
52return data.EncryptedContentInfo.decrypt(key)
53}
54
55func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
56alg := eci.ContentEncryptionAlgorithm.Algorithm
57if !alg.Equal(OIDEncryptionAlgorithmDESCBC) &&
58!alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC) &&
59!alg.Equal(OIDEncryptionAlgorithmAES256CBC) &&
60!alg.Equal(OIDEncryptionAlgorithmAES128CBC) &&
61!alg.Equal(OIDEncryptionAlgorithmAES128GCM) &&
62!alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
63fmt.Printf("Unsupported Content Encryption Algorithm: %s\n", alg)
64return nil, ErrUnsupportedAlgorithm
65}
66
67// EncryptedContent can either be constructed of multple OCTET STRINGs
68// or _be_ a tagged OCTET STRING
69var cyphertext []byte
70if eci.EncryptedContent.IsCompound {
71// Complex case to concat all of the children OCTET STRINGs
72var buf bytes.Buffer
73cypherbytes := eci.EncryptedContent.Bytes
74for {
75var part []byte
76cypherbytes, _ = asn1.Unmarshal(cypherbytes, &part)
77buf.Write(part)
78if cypherbytes == nil {
79break
80}
81}
82cyphertext = buf.Bytes()
83} else {
84// Simple case, the bytes _are_ the cyphertext
85cyphertext = eci.EncryptedContent.Bytes
86}
87
88var block cipher.Block
89var err error
90
91switch {
92case alg.Equal(OIDEncryptionAlgorithmDESCBC):
93block, err = des.NewCipher(key)
94case alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC):
95block, err = des.NewTripleDESCipher(key)
96case alg.Equal(OIDEncryptionAlgorithmAES256CBC), alg.Equal(OIDEncryptionAlgorithmAES256GCM):
97fallthrough
98case alg.Equal(OIDEncryptionAlgorithmAES128GCM), alg.Equal(OIDEncryptionAlgorithmAES128CBC):
99block, err = aes.NewCipher(key)
100}
101
102if err != nil {
103return nil, err
104}
105
106if alg.Equal(OIDEncryptionAlgorithmAES128GCM) || alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
107params := aesGCMParameters{}
108paramBytes := eci.ContentEncryptionAlgorithm.Parameters.Bytes
109
110_, err := asn1.Unmarshal(paramBytes, ¶ms)
111if err != nil {
112return nil, err
113}
114
115gcm, err := cipher.NewGCM(block)
116if err != nil {
117return nil, err
118}
119
120if len(params.Nonce) != gcm.NonceSize() {
121return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
122}
123if params.ICVLen != gcm.Overhead() {
124return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
125}
126
127plaintext, err := gcm.Open(nil, params.Nonce, cyphertext, nil)
128if err != nil {
129return nil, err
130}
131
132return plaintext, nil
133}
134
135iv := eci.ContentEncryptionAlgorithm.Parameters.Bytes
136if len(iv) != block.BlockSize() {
137return nil, errors.New("pkcs7: encryption algorithm parameters are malformed")
138}
139mode := cipher.NewCBCDecrypter(block, iv)
140plaintext := make([]byte, len(cyphertext))
141mode.CryptBlocks(plaintext, cyphertext)
142if plaintext, err = unpad(plaintext, mode.BlockSize()); err != nil {
143return nil, err
144}
145return plaintext, nil
146}
147
148func unpad(data []byte, blocklen int) ([]byte, error) {
149if blocklen < 1 {
150return nil, fmt.Errorf("invalid blocklen %d", blocklen)
151}
152if len(data)%blocklen != 0 || len(data) == 0 {
153return nil, fmt.Errorf("invalid data len %d", len(data))
154}
155
156// the last byte is the length of padding
157padlen := int(data[len(data)-1])
158
159// check padding integrity, all bytes should be the same
160pad := data[len(data)-padlen:]
161for _, padbyte := range pad {
162if padbyte != byte(padlen) {
163return nil, errors.New("invalid padding")
164}
165}
166
167return data[:len(data)-padlen], nil
168}
169
170func selectRecipientForCertificate(recipients []recipientInfo, cert *x509.Certificate) recipientInfo {
171for _, recp := range recipients {
172if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
173return recp
174}
175}
176return recipientInfo{}
177}
178