123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- /*
- Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package sm2
- import (
- "crypto/aes"
- "crypto/cipher"
- "crypto/elliptic"
- "crypto/hmac"
- "crypto/md5"
- "crypto/rand"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/sha512"
- "crypto/x509/pkix"
- "encoding/asn1"
- "encoding/pem"
- "errors"
- "hash"
- "io/ioutil"
- "math/big"
- "os"
- "reflect"
- )
- /*
- * reference to RFC5959 and RFC2898
- */
- var (
- oidPBES1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 3} // pbeWithMD5AndDES-CBC(PBES1)
- oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} // id-PBES2(PBES2)
- oidPBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} // id-PBKDF2
- oidKEYMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 5}
- oidKEYSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7}
- oidKEYSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9}
- oidKEYSHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 11}
- oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
- oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
- oidSM2 = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
- )
- // reference to https://www.rfc-editor.org/rfc/rfc5958.txt
- type PrivateKeyInfo struct {
- Version int // v1 or v2
- PrivateKeyAlgorithm []asn1.ObjectIdentifier
- PrivateKey []byte
- }
- // reference to https://www.rfc-editor.org/rfc/rfc5958.txt
- type EncryptedPrivateKeyInfo struct {
- EncryptionAlgorithm Pbes2Algorithms
- EncryptedData []byte
- }
- // reference to https://www.ietf.org/rfc/rfc2898.txt
- type Pbes2Algorithms struct {
- IdPBES2 asn1.ObjectIdentifier
- Pbes2Params Pbes2Params
- }
- // reference to https://www.ietf.org/rfc/rfc2898.txt
- type Pbes2Params struct {
- KeyDerivationFunc Pbes2KDfs // PBES2-KDFs
- EncryptionScheme Pbes2Encs // PBES2-Encs
- }
- // reference to https://www.ietf.org/rfc/rfc2898.txt
- type Pbes2KDfs struct {
- IdPBKDF2 asn1.ObjectIdentifier
- Pkdf2Params Pkdf2Params
- }
- type Pbes2Encs struct {
- EncryAlgo asn1.ObjectIdentifier
- IV []byte
- }
- // reference to https://www.ietf.org/rfc/rfc2898.txt
- type Pkdf2Params struct {
- Salt []byte
- IterationCount int
- Prf pkix.AlgorithmIdentifier
- }
- type sm2PrivateKey struct {
- Version int
- PrivateKey []byte
- NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
- PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
- }
- type pkcs8 struct {
- Version int
- Algo pkix.AlgorithmIdentifier
- PrivateKey []byte
- }
- // copy from crypto/pbkdf2.go
- func pbkdf(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
- prf := hmac.New(h, password)
- hashLen := prf.Size()
- numBlocks := (keyLen + hashLen - 1) / hashLen
- var buf [4]byte
- dk := make([]byte, 0, numBlocks*hashLen)
- U := make([]byte, hashLen)
- for block := 1; block <= numBlocks; block++ {
- // N.B.: || means concatenation, ^ means XOR
- // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
- // U_1 = PRF(password, salt || uint(i))
- prf.Reset()
- prf.Write(salt)
- buf[0] = byte(block >> 24)
- buf[1] = byte(block >> 16)
- buf[2] = byte(block >> 8)
- buf[3] = byte(block)
- prf.Write(buf[:4])
- dk = prf.Sum(dk)
- T := dk[len(dk)-hashLen:]
- copy(U, T)
- // U_n = PRF(password, U_(n-1))
- for n := 2; n <= iter; n++ {
- prf.Reset()
- prf.Write(U)
- U = U[:0]
- U = prf.Sum(U)
- for x := range U {
- T[x] ^= U[x]
- }
- }
- }
- return dk[:keyLen]
- }
- func ParseSm2PublicKey(der []byte) (*PublicKey, error) {
- var pubkey pkixPublicKey
- if _, err := asn1.Unmarshal(der, &pubkey); err != nil {
- return nil, err
- }
- if !reflect.DeepEqual(pubkey.Algo.Algorithm, oidSM2) {
- return nil, errors.New("x509: not sm2 elliptic curve")
- }
- curve := P256Sm2()
- x, y := elliptic.Unmarshal(curve, pubkey.BitString.Bytes)
- pub := PublicKey{
- Curve: curve,
- X: x,
- Y: y,
- }
- return &pub, nil
- }
- func MarshalSm2PublicKey(key *PublicKey) ([]byte, error) {
- var r pkixPublicKey
- var algo pkix.AlgorithmIdentifier
- algo.Algorithm = oidSM2
- algo.Parameters.Class = 0
- algo.Parameters.Tag = 6
- algo.Parameters.IsCompound = false
- algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
- r.Algo = algo
- r.BitString = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
- return asn1.Marshal(r)
- }
- func ParseSm2PrivateKey(der []byte) (*PrivateKey, error) {
- var privKey sm2PrivateKey
- if _, err := asn1.Unmarshal(der, &privKey); err != nil {
- return nil, errors.New("x509: failed to parse SM2 private key: " + err.Error())
- }
- curve := P256Sm2()
- k := new(big.Int).SetBytes(privKey.PrivateKey)
- curveOrder := curve.Params().N
- if k.Cmp(curveOrder) >= 0 {
- return nil, errors.New("x509: invalid elliptic curve private key value")
- }
- priv := new(PrivateKey)
- priv.Curve = curve
- priv.D = k
- privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
- for len(privKey.PrivateKey) > len(privateKey) {
- if privKey.PrivateKey[0] != 0 {
- return nil, errors.New("x509: invalid private key length")
- }
- privKey.PrivateKey = privKey.PrivateKey[1:]
- }
- copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
- priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
- return priv, nil
- }
- func ParsePKCS8UnecryptedPrivateKey(der []byte) (*PrivateKey, error) {
- var privKey pkcs8
- if _, err := asn1.Unmarshal(der, &privKey); err != nil {
- return nil, err
- }
- if !reflect.DeepEqual(privKey.Algo.Algorithm, oidSM2) {
- return nil, errors.New("x509: not sm2 elliptic curve")
- }
- return ParseSm2PrivateKey(privKey.PrivateKey)
- }
- func ParsePKCS8EcryptedPrivateKey(der, pwd []byte) (*PrivateKey, error) {
- var keyInfo EncryptedPrivateKeyInfo
- _, err := asn1.Unmarshal(der, &keyInfo)
- if err != nil {
- return nil, errors.New("x509: unknown format")
- }
- if !reflect.DeepEqual(keyInfo.EncryptionAlgorithm.IdPBES2, oidPBES2) {
- return nil, errors.New("x509: only support PBES2")
- }
- encryptionScheme := keyInfo.EncryptionAlgorithm.Pbes2Params.EncryptionScheme
- keyDerivationFunc := keyInfo.EncryptionAlgorithm.Pbes2Params.KeyDerivationFunc
- if !reflect.DeepEqual(keyDerivationFunc.IdPBKDF2, oidPBKDF2) {
- return nil, errors.New("x509: only support PBKDF2")
- }
- pkdf2Params := keyDerivationFunc.Pkdf2Params
- if !reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES128CBC) &&
- !reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES256CBC) {
- return nil, errors.New("x509: unknow encryption algorithm")
- }
- iv := encryptionScheme.IV
- salt := pkdf2Params.Salt
- iter := pkdf2Params.IterationCount
- encryptedKey := keyInfo.EncryptedData
- var key []byte
- switch {
- case pkdf2Params.Prf.Algorithm.Equal(oidKEYMD5):
- key = pbkdf(pwd, salt, iter, 32, md5.New)
- break
- case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA1):
- key = pbkdf(pwd, salt, iter, 32, sha1.New)
- break
- case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA256):
- key = pbkdf(pwd, salt, iter, 32, sha256.New)
- break
- case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA512):
- key = pbkdf(pwd, salt, iter, 32, sha512.New)
- break
- default:
- return nil, errors.New("x509: unknown hash algorithm")
- }
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- mode := cipher.NewCBCDecrypter(block, iv)
- mode.CryptBlocks(encryptedKey, encryptedKey)
- rKey, err := ParsePKCS8UnecryptedPrivateKey(encryptedKey)
- if err != nil {
- return nil, errors.New("pkcs8: incorrect password")
- }
- return rKey, nil
- }
- func ParsePKCS8PrivateKey(der, pwd []byte) (*PrivateKey, error) {
- if pwd == nil {
- return ParsePKCS8UnecryptedPrivateKey(der)
- }
- return ParsePKCS8EcryptedPrivateKey(der, pwd)
- }
- func MarshalSm2UnecryptedPrivateKey(key *PrivateKey) ([]byte, error) {
- var r pkcs8
- var priv sm2PrivateKey
- var algo pkix.AlgorithmIdentifier
- algo.Algorithm = oidSM2
- algo.Parameters.Class = 0
- algo.Parameters.Tag = 6
- algo.Parameters.IsCompound = false
- algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
- priv.Version = 1
- priv.NamedCurveOID = oidNamedCurveP256SM2
- priv.PublicKey = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
- priv.PrivateKey = key.D.Bytes()
- r.Version = 0
- r.Algo = algo
- r.PrivateKey, _ = asn1.Marshal(priv)
- return asn1.Marshal(r)
- }
- func MarshalSm2EcryptedPrivateKey(PrivKey *PrivateKey, pwd []byte) ([]byte, error) {
- der, err := MarshalSm2UnecryptedPrivateKey(PrivKey)
- if err != nil {
- return nil, err
- }
- iter := 2048
- salt := make([]byte, 8)
- iv := make([]byte, 16)
- rand.Reader.Read(salt)
- rand.Reader.Read(iv)
- key := pbkdf(pwd, salt, iter, 32, sha1.New) // 默认是SHA1
- padding := aes.BlockSize - len(der)%aes.BlockSize
- if padding > 0 {
- n := len(der)
- der = append(der, make([]byte, padding)...)
- for i := 0; i < padding; i++ {
- der[n+i] = byte(padding)
- }
- }
- encryptedKey := make([]byte, len(der))
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- mode := cipher.NewCBCEncrypter(block, iv)
- mode.CryptBlocks(encryptedKey, der)
- var algorithmIdentifier pkix.AlgorithmIdentifier
- algorithmIdentifier.Algorithm = oidKEYSHA1
- algorithmIdentifier.Parameters.Tag = 5
- algorithmIdentifier.Parameters.IsCompound = false
- algorithmIdentifier.Parameters.FullBytes = []byte{5, 0}
- keyDerivationFunc := Pbes2KDfs{
- oidPBKDF2,
- Pkdf2Params{
- salt,
- iter,
- algorithmIdentifier,
- },
- }
- encryptionScheme := Pbes2Encs{
- oidAES256CBC,
- iv,
- }
- pbes2Algorithms := Pbes2Algorithms{
- oidPBES2,
- Pbes2Params{
- keyDerivationFunc,
- encryptionScheme,
- },
- }
- encryptedPkey := EncryptedPrivateKeyInfo{
- pbes2Algorithms,
- encryptedKey,
- }
- return asn1.Marshal(encryptedPkey)
- }
- func MarshalSm2PrivateKey(key *PrivateKey, pwd []byte) ([]byte, error) {
- if pwd == nil {
- return MarshalSm2UnecryptedPrivateKey(key)
- }
- return MarshalSm2EcryptedPrivateKey(key, pwd)
- }
- func ReadPrivateKeyFromMem(data []byte, pwd []byte) (*PrivateKey, error) {
- var block *pem.Block
- block, _ = pem.Decode(data)
- if block == nil {
- return nil, errors.New("failed to decode private key")
- }
- priv, err := ParsePKCS8PrivateKey(block.Bytes, pwd)
- return priv, err
- }
- func ReadPrivateKeyFromPem(FileName string, pwd []byte) (*PrivateKey, error) {
- data, err := ioutil.ReadFile(FileName)
- if err != nil {
- return nil, err
- }
- return ReadPrivateKeyFromMem(data, pwd)
- }
- func WritePrivateKeytoMem(key *PrivateKey, pwd []byte) ([]byte, error) {
- var block *pem.Block
- der, err := MarshalSm2PrivateKey(key, pwd)
- if err != nil {
- return nil, err
- }
- if pwd != nil {
- block = &pem.Block{
- Type: "ENCRYPTED PRIVATE KEY",
- Bytes: der,
- }
- } else {
- block = &pem.Block{
- Type: "PRIVATE KEY",
- Bytes: der,
- }
- }
- return pem.EncodeToMemory(block), nil
- }
- func WritePrivateKeytoPem(FileName string, key *PrivateKey, pwd []byte) (bool, error) {
- var block *pem.Block
- der, err := MarshalSm2PrivateKey(key, pwd)
- if err != nil {
- return false, err
- }
- if pwd != nil {
- block = &pem.Block{
- Type: "ENCRYPTED PRIVATE KEY",
- Bytes: der,
- }
- } else {
- block = &pem.Block{
- Type: "PRIVATE KEY",
- Bytes: der,
- }
- }
- file, err := os.Create(FileName)
- if err != nil {
- return false, err
- }
- defer file.Close()
- err = pem.Encode(file, block)
- if err != nil {
- return false, err
- }
- return true, nil
- }
- func ReadPublicKeyFromMem(data []byte, _ []byte) (*PublicKey, error) {
- block, _ := pem.Decode(data)
- if block == nil || block.Type != "PUBLIC KEY" {
- return nil, errors.New("failed to decode public key")
- }
- pub, err := ParseSm2PublicKey(block.Bytes)
- return pub, err
- }
- func ReadPublicKeyFromPem(FileName string, pwd []byte) (*PublicKey, error) {
- data, err := ioutil.ReadFile(FileName)
- if err != nil {
- return nil, err
- }
- return ReadPublicKeyFromMem(data, pwd)
- }
- func WritePublicKeytoMem(key *PublicKey, _ []byte) ([]byte, error) {
- der, err := MarshalSm2PublicKey(key)
- if err != nil {
- return nil, err
- }
- block := &pem.Block{
- Type: "PUBLIC KEY",
- Bytes: der,
- }
- return pem.EncodeToMemory(block), nil
- }
- func WritePublicKeytoPem(FileName string, key *PublicKey, _ []byte) (bool, error) {
- der, err := MarshalSm2PublicKey(key)
- if err != nil {
- return false, err
- }
- block := &pem.Block{
- Type: "PUBLIC KEY",
- Bytes: der,
- }
- file, err := os.Create(FileName)
- defer file.Close()
- if err != nil {
- return false, err
- }
- err = pem.Encode(file, block)
- if err != nil {
- return false, err
- }
- return true, nil
- }
|