github.com/emmansun/gmsm@v0.29.1/cfca/pkcs12_sm2.go (about) 1 // Package cfca handles cfca issued key and certificate 2 package cfca 3 4 import ( 5 "crypto/cipher" 6 "encoding/asn1" 7 "errors" 8 "fmt" 9 "math/big" 10 11 "github.com/emmansun/gmsm/padding" 12 "github.com/emmansun/gmsm/pkcs" 13 "github.com/emmansun/gmsm/sm2" 14 "github.com/emmansun/gmsm/sm3" 15 "github.com/emmansun/gmsm/sm4" 16 "github.com/emmansun/gmsm/smx509" 17 ) 18 19 // CFCA私有格式,在SADK中把它定义为PKCS12_SM2 20 21 type cfcaKeyPairData struct { 22 Version int `asn1:"default:1"` 23 EncryptedKey keyData 24 Certificate certData 25 } 26 27 // 被加密的私钥数据 28 type keyData struct { 29 ContentType asn1.ObjectIdentifier 30 Algorithm asn1.ObjectIdentifier 31 EncryptedContent asn1.RawValue 32 } 33 34 // 对应的证书 35 type certData struct { 36 ContentType asn1.ObjectIdentifier 37 Content asn1.RawContent 38 } 39 40 var ( 41 oidSM2Data = asn1.ObjectIdentifier{1, 2, 156, 10197, 6, 1, 4, 2, 1} 42 oidSM4 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 104} // SADK中认为这就是SM4_CBC,不知道是不是历史原因 43 oidSM4CBC = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 104, 2} 44 ) 45 46 // ParseSM2 parses the der data, returns private key and related certificate, it's CFCA private structure. 47 func ParseSM2(password, data []byte) (*sm2.PrivateKey, *smx509.Certificate, error) { 48 var keys cfcaKeyPairData 49 if _, err := asn1.Unmarshal(data, &keys); err != nil { 50 return nil, nil, err 51 } 52 if !keys.Certificate.ContentType.Equal(oidSM2Data) { 53 return nil, nil, fmt.Errorf("cfca: unsupported content type oid <%v>", keys.Certificate.ContentType) 54 } 55 if !keys.EncryptedKey.ContentType.Equal(oidSM2Data) { 56 return nil, nil, fmt.Errorf("cfca: unsupported content type oid <%v>", keys.EncryptedKey.ContentType) 57 } 58 if !keys.EncryptedKey.Algorithm.Equal(oidSM4) && !keys.EncryptedKey.Algorithm.Equal(oidSM4CBC) { 59 return nil, nil, fmt.Errorf("cfca: unsupported algorithm <%v>", keys.EncryptedKey.Algorithm) 60 } 61 ivkey := sm3.Kdf(password, 32) 62 marshalledIV, err := asn1.Marshal(ivkey[:16]) 63 if err != nil { 64 return nil, nil, err 65 } 66 pk, err := pkcs.SM4CBC.Decrypt(ivkey[16:], &asn1.RawValue{FullBytes: marshalledIV}, keys.EncryptedKey.EncryptedContent.Bytes) 67 if err != nil { 68 return nil, nil, err 69 } 70 d := new(big.Int).SetBytes(pk) // here we do NOT check if the d is in (0, N) or not 71 // Create private key from *big.Int 72 prvKey := new(sm2.PrivateKey) 73 prvKey.Curve = sm2.P256() 74 prvKey.D = d 75 prvKey.PublicKey.X, prvKey.PublicKey.Y = prvKey.ScalarBaseMult(prvKey.D.Bytes()) 76 77 cert, err := smx509.ParseCertificate(keys.Certificate.Content) 78 if err != nil { 79 return nil, nil, err 80 } 81 82 if !prvKey.PublicKey.Equal(cert.PublicKey) { 83 return nil, nil, errors.New("cfca: public key and private key do not match") 84 } 85 return prvKey, cert, nil 86 } 87 88 // MarshalSM2 encodes sm2 private key and related certificate to cfca defined format 89 func MarshalSM2(password []byte, key *sm2.PrivateKey, cert *smx509.Certificate) ([]byte, error) { 90 if len(password) == 0 { 91 return nil, errors.New("cfca: invalid password") 92 } 93 ivkey := sm3.Kdf(password, 32) 94 block, err := sm4.NewCipher(ivkey[16:]) 95 if err != nil { 96 return nil, err 97 } 98 mode := cipher.NewCBCEncrypter(block, ivkey[:16]) 99 pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize())) 100 plainText := pkcs7.Pad(key.D.Bytes()) 101 ciphertext := make([]byte, len(plainText)) 102 mode.CryptBlocks(ciphertext, plainText) 103 104 ciphertext, err = asn1.Marshal(ciphertext) 105 if err != nil { 106 return nil, err 107 } 108 109 keys := cfcaKeyPairData{ 110 Version: 1, 111 EncryptedKey: keyData{ 112 ContentType: oidSM2Data, 113 Algorithm: oidSM4, 114 EncryptedContent: asn1.RawValue{FullBytes: ciphertext}, 115 }, 116 Certificate: certData{ 117 ContentType: oidSM2Data, 118 Content: cert.Raw, 119 }, 120 } 121 122 return asn1.Marshal(keys) 123 }