github.com/emmansun/gmsm@v0.29.1/pkcs7/envelope.go (about) 1 package pkcs7 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/x509/pkix" 8 "encoding/asn1" 9 "errors" 10 11 "github.com/emmansun/gmsm/pkcs" 12 "github.com/emmansun/gmsm/sm2" 13 "github.com/emmansun/gmsm/smx509" 14 ) 15 16 type EnvelopedData struct { 17 ed envelopedData 18 key []byte 19 contentType asn1.ObjectIdentifier 20 encryptedContentType asn1.ObjectIdentifier 21 } 22 23 type envelopedData struct { 24 Version int 25 RecipientInfos []recipientInfo `asn1:"set"` 26 EncryptedContentInfo encryptedContentInfo 27 } 28 29 type recipientInfo struct { 30 Version int 31 IssuerAndSerialNumber issuerAndSerial 32 KeyEncryptionAlgorithm pkix.AlgorithmIdentifier 33 EncryptedKey []byte 34 } 35 36 type encryptedContentInfo struct { 37 ContentType asn1.ObjectIdentifier 38 ContentEncryptionAlgorithm pkix.AlgorithmIdentifier 39 EncryptedContent asn1.RawValue `asn1:"tag:0,optional"` 40 } 41 42 func (data envelopedData) GetRecipient(cert *smx509.Certificate) *recipientInfo { 43 for _, recp := range data.RecipientInfos { 44 if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) { 45 return &recp 46 } 47 } 48 return nil 49 } 50 51 // GetRecipients returns the list of recipients (READONLY) for the enveloped data 52 func (data envelopedData) GetRecipients() ([]IssuerAndSerial, error) { 53 var recipients []IssuerAndSerial 54 for _, recp := range data.RecipientInfos { 55 recipients = append(recipients, newIssuerAndSerial(recp.IssuerAndSerialNumber)) 56 } 57 return recipients, nil 58 } 59 60 func (data envelopedData) GetEncryptedContentInfo() *encryptedContentInfo { 61 return &data.EncryptedContentInfo 62 } 63 64 // ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt 65 // content with an unsupported algorithm. 66 var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, AES-GCM, SM4-CBC and SM4-GCM supported") 67 68 // Encrypt creates and returns an envelope data PKCS7 structure with encrypted 69 // recipient keys for each recipient public key. 70 // 71 // # The algorithm used to perform encryption is determined by the argument cipher 72 // 73 // TODO(fullsailor): Add support for encrypting content with other algorithms 74 func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) { 75 ed, err := NewEnvelopedData(cipher, content) 76 if err != nil { 77 return nil, err 78 } 79 for _, recipient := range recipients { 80 if err := ed.AddRecipient(recipient, 0, func(cert *smx509.Certificate, key []byte) ([]byte, error) { 81 return encryptKey(key, cert, false) 82 }); err != nil { 83 return nil, err 84 } 85 } 86 return ed.Finish() 87 } 88 89 // EncryptSM creates and returns an envelope data PKCS7 structure with encrypted 90 // recipient keys for each recipient public key. 91 // The OIDs use GM/T 0010 - 2012 set and the encrypted key use ASN.1 format. 92 // 93 // The algorithm used to perform encryption is determined by the argument cipher 94 func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) { 95 return encryptSM(cipher, content, recipients, false) 96 } 97 98 // EncryptCFCA creates and returns an envelope data PKCS7 structure with encrypted 99 // recipient keys for each recipient public key. 100 // The OIDs use GM/T 0010 - 2012 set and the encrypted key use C1C2C3 format and without 0x4 prefix. 101 // 102 // The algorithm used to perform encryption is determined by the argument cipher 103 func EncryptCFCA(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) { 104 return encryptSM(cipher, content, recipients, true) 105 } 106 107 func encryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate, isLegacyCFCA bool) ([]byte, error) { 108 ed, err := NewSM2EnvelopedData(cipher, content) 109 if err != nil { 110 return nil, err 111 } 112 for _, recipient := range recipients { 113 if err := ed.AddRecipient(recipient, 1, func(cert *smx509.Certificate, key []byte) ([]byte, error) { 114 return encryptKey(key, cert, isLegacyCFCA) 115 }); err != nil { 116 return nil, err 117 } 118 } 119 return ed.Finish() 120 } 121 122 // NewEnvelopedData creates a new EnvelopedData structure with the provided cipher and content. 123 func NewEnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) { 124 var key []byte 125 var err error 126 127 // Create key 128 key = make([]byte, cipher.KeySize()) 129 if _, err = rand.Read(key); err != nil { 130 return nil, err 131 } 132 133 id, ciphertext, err := cipher.Encrypt(rand.Reader, key, content) 134 if err != nil { 135 return nil, err 136 } 137 ed := &EnvelopedData{} 138 ed.contentType = OIDEnvelopedData 139 ed.encryptedContentType = OIDData 140 ed.key = key 141 ed.ed = envelopedData{ 142 Version: 0, 143 EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)), 144 } 145 return ed, nil 146 } 147 148 // NewSM2EnvelopedData creates a new EnvelopedData structure with the provided cipher and content. 149 // The OIDs use GM/T 0010 - 2012 set. 150 func NewSM2EnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) { 151 var key []byte 152 var err error 153 154 // Create key 155 key = make([]byte, cipher.KeySize()) 156 if _, err = rand.Read(key); err != nil { 157 return nil, err 158 } 159 160 id, ciphertext, err := cipher.Encrypt(rand.Reader, key, content) 161 if err != nil { 162 return nil, err 163 } 164 ed := &EnvelopedData{} 165 ed.contentType = SM2OIDEnvelopedData 166 ed.encryptedContentType = SM2OIDData 167 ed.key = key 168 ed.ed = envelopedData{ 169 Version: 1, 170 EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)), 171 } 172 return ed, nil 173 } 174 175 // AddRecipient adds a recipient to the EnvelopedData structure. 176 func (ed *EnvelopedData) AddRecipient(cert *smx509.Certificate, version int, encryptKeyFunc func(cert *smx509.Certificate, key []byte) ([]byte, error)) error { 177 encrypted, err := encryptKeyFunc(cert, ed.key) 178 if err != nil { 179 return err 180 } 181 ias, err := cert2issuerAndSerial(cert) 182 if err != nil { 183 return err 184 } 185 var keyEncryptionAlgorithm asn1.ObjectIdentifier = OIDEncryptionAlgorithmRSA 186 if cert.SignatureAlgorithm == smx509.SM2WithSM3 { 187 keyEncryptionAlgorithm = OIDKeyEncryptionAlgorithmSM2 188 } 189 190 info := recipientInfo{ 191 Version: version, 192 IssuerAndSerialNumber: ias, 193 KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{ 194 Algorithm: keyEncryptionAlgorithm, 195 }, 196 EncryptedKey: encrypted, 197 } 198 ed.ed.RecipientInfos = append(ed.ed.RecipientInfos, info) 199 return nil 200 } 201 202 // Finish creates the final PKCS7 structure. 203 func (ed *EnvelopedData) Finish() ([]byte, error) { 204 innerContent, err := asn1.Marshal(ed.ed) 205 if err != nil { 206 return nil, err 207 } 208 209 // Prepare outer payload structure 210 wrapper := contentInfo{ 211 ContentType: ed.contentType, 212 Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, IsCompound: true, Bytes: innerContent}, 213 } 214 return asn1.Marshal(wrapper) 215 } 216 217 func newEncryptedContent(contentType asn1.ObjectIdentifier, alg *pkix.AlgorithmIdentifier, ciphertext asn1.RawValue) encryptedContentInfo { 218 return encryptedContentInfo{ 219 ContentType: contentType, 220 ContentEncryptionAlgorithm: *alg, 221 EncryptedContent: ciphertext, 222 } 223 } 224 225 func marshalEncryptedContent(content []byte) asn1.RawValue { 226 asn1Content, _ := asn1.Marshal(content) 227 return asn1.RawValue{Tag: 0, Class: asn1.ClassContextSpecific, Bytes: asn1Content, IsCompound: true} 228 } 229 230 func encryptKey(key []byte, recipient *smx509.Certificate, isCFCA bool) ([]byte, error) { 231 if pub, ok := recipient.PublicKey.(*rsa.PublicKey); ok { 232 return rsa.EncryptPKCS1v15(rand.Reader, pub, key) 233 } 234 if pub, ok := recipient.PublicKey.(*ecdsa.PublicKey); ok && pub.Curve == sm2.P256() { 235 if isCFCA { 236 encryptedKey, err := sm2.Encrypt(rand.Reader, pub, key, sm2.NewPlainEncrypterOpts(sm2.MarshalUncompressed, sm2.C1C2C3)) 237 if err != nil { 238 return nil, err 239 } 240 return encryptedKey[1:], nil 241 } else { 242 return sm2.EncryptASN1(rand.Reader, pub, key) 243 } 244 } 245 return nil, errors.New("pkcs7: only supports RSA/SM2 key") 246 }