mirror of
https://gitee.com/IrisVega/frp.git
synced 2024-11-01 22:31:29 +08:00
489 lines
13 KiB
Go
489 lines
13 KiB
Go
|
/*
|
||
|
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
|
||
|
}
|