coupons chaincode first push

parent 5e9151f1
Pipeline #49 failed with stages
package main
import (
"math/big"
"errors"
"crypto/elliptic"
"crypto/ecdsa"
"crypto"
"strconv"
"fmt"
"encoding/asn1"
"encoding/json"
"hash"
"github.com/coupons/sm_crypto/sm2"
"github.com/coupons/sm_crypto/sm3"
"encoding/hex"
)
type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
DSA
ECDSA
Ed25519
SM2
)
var publicKeyAlgoName = [...]string{
RSA: "RSA",
DSA: "DSA",
ECDSA: "ECDSA",
Ed25519: "Ed25519",
SM2: "SM2",
}
const (
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
// number of bytes in a big.Word
wordBytes = wordBits / 8
)
/*
得到string 类型的PublicKeyAlgorithm
*/
func (algo PublicKeyAlgorithm) String() string {
if 0 < algo && int(algo) < len(publicKeyAlgoName) {
return publicKeyAlgoName[algo]
}
return strconv.Itoa(int(algo))
}
type SignatureAlgorithm int
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
MD2WithRSA
MD5WithRSA
SHA1WithRSA
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
DSAWithSHA1
DSAWithSHA256
ECDSAWithSHA1
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
SHA256WithRSAPSS
SHA384WithRSAPSS
SHA512WithRSAPSS
SM2WithSM3
PureEd25519
)
type CertType int
const (
UnknownCertType CertType = iota
OrganizationCert
ChannelCert
MerchantCert
)
type TxType int
const (
UnknownTxType TxType = iota
CreateCoupon
DisCoupon
ApplyCoupon
UseCoupon
)
type ecdsaSignature dsaSignature
var signatureAlgorithmDetails = []struct {
algo SignatureAlgorithm
name string
pubKeyAlgo PublicKeyAlgorithm
hash crypto.Hash
}{
{ECDSAWithSHA1, "ECDSA-SHA1", ECDSA, crypto.SHA1},
{ECDSAWithSHA256, "ECDSA-SHA256", ECDSA, crypto.SHA256},
{ECDSAWithSHA384, "ECDSA-SHA384", ECDSA, crypto.SHA384},
{ECDSAWithSHA512, "ECDSA-SHA512", ECDSA, crypto.SHA512},
{PureEd25519, "Ed25519", Ed25519, crypto.Hash(0) /* no pre-hashing */},
{SM2WithSM3, "SM2", SM2, crypto.Hash(21) /* no pre-hashing */},
}
// ErrUnsupportedAlgorithm results from attempting to perform an operation that
// involves algorithms that are not currently implemented.
var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey interface{}) error {
return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey)
}
// RFC 5480, 2.1.1.1. Named Curve
//
// secp224r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
//
// secp256r1 OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
// prime(1) 7 }
//
// secp384r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 34 }
//
// secp521r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
//
// NB: secp256r1 is equivalent to prime256v1
var (
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301} // I get the SM2 ID through parsing the pem file generated by gmssl
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
)
// RFC 3279, 2.3 Public Key Algorithms
//
// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
// rsadsi(113549) pkcs(1) 1 }
//
// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
//
// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
// x9-57(10040) x9cm(4) 1 }
//
// RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters
//
// id-ecPublicKey OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
var (
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
oidPublicKeyEd25519 = oidSignatureEd25519
)
type dsaSignature struct {
R, S *big.Int
}
type PrivateKeySerialize struct {
PrivSerialize []byte `json:"priv_serialize"` //私钥序列化的数据
PrivType crypto.Hash`json:"priv_type"`
}
/*
券发行证书格式
*/
type Certificate struct {
PublicKeyHashAlgorithm crypto.Hash `json:"public_key_hash_algorithm""` //公钥算法
PublicKeyByte []byte `json:"public_key_byte""`
PublicKey interface{} `json:"publickey"` //公钥
CertType CertType `json:"cert_type"` //证书类型
Extensions interface{} `json:"extensions"` //拓展字段信息,这个字段的扩展信息与证书的扩展字段不同
NotBefore int64 `json:"not_before"`
NotAfter int64 `json:"not_after"` // Validity bounds.
CertHash []byte `json:"cert_hash"` // 原证书hash,留存
Signature []byte `json:"signature"` //签发者证书签名数据,保证数据不被篡改
SignatureAlgorithm SignatureAlgorithm `json:"signature_algorithm"` //使用的签名and hash 算法
}
/*
验证是否是我们当前支持的签名算法
*/
func isSupportSignatureAlgorithm(algo crypto.Hash) bool {
switch algo {
case crypto.SHA256, crypto.SHA1, crypto.SHA224,crypto.SHA384,crypto.SHA512,crypto.Hash(21):
return true
default:
return false
}
}
/*
验证cert 证书是否是parent证书签发
parent:父签名证书
cert: 子签名整数
*/
func (this *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
if !isSupportSignatureAlgorithm(parent.PublicKeyHashAlgorithm) {
return ErrUnsupportedAlgorithm
}
signature := this.Signature
publicKey := this.PublicKey //公钥信息无法直接unmarshal,所以设为nil
this.Signature = nil
this.PublicKey = nil
certRaw, err := json.Marshal(this)
if err != nil {
return
}
this.Signature = signature
this.PublicKey = publicKey
return parent.CheckSignature(this.SignatureAlgorithm, certRaw, signature)
}
/*
验证数据是否是由this签发
Parameters:
algo:sign和hash 算法,
signed:待签名的原始数据
signature:签名
*/
func (this *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
return checkSignature(algo, signed, signature, this.PublicKey)
}
/*
证书解析
Parameters:
certByte:byte 类型的证书信息,
*/
func ParseCertificate(certByte []byte) (*Certificate, error) {
cert := &Certificate{}
err := json.Unmarshal(certByte, cert)
if err != nil {
return nil, err
}
pub, err := unmarshalPubkey(cert.PublicKeyByte, namedCurveFromHash(cert.PublicKeyHashAlgorithm))
if err != nil {
return nil, err
}
cert.PublicKey = pub
return cert, nil
}
/*
私钥解析
Parameters:
curve: 私钥使用的椭圆曲线参数,
pk: 私钥序列化数据
*/
func PrivKeyFromBytes(curve elliptic.Curve, pk []byte) (priv crypto.Signer,pubKey []byte) {
x, y := curve.ScalarBaseMult(pk)
pubKey = elliptic.Marshal(curve, x, y)
switch curve {
case sm2.P256Sm2():
priv = &sm2.PrivateKey{
PublicKey: sm2.PublicKey{
Curve: curve,
X: x,
Y: y,
},
D: new(big.Int).SetBytes(pk),
}
return
default:
priv = &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
},
D: new(big.Int).SetBytes(pk),
}
return
}
}
/*
证书解析
Parameters:
privHex:十六进制的PrivateKeySerialize 编码信息
*/
func ParsePrivateKey(privHex string)(priv crypto.Signer,pubKey []byte,err error){
privByte,err := hex.DecodeString(privHex)
if err!=nil{
return nil,nil,err
}
privS :=&PrivateKeySerialize{}
err = json.Unmarshal(privByte,privS)
if err!=nil{
return nil,nil,err
}
curve := namedCurveFromHash(privS.PrivType)
priv,pubKey = PrivKeyFromBytes(curve,privS.PrivSerialize)
return
}
/*
私钥解析
Parameters:
curve: 私钥使用的椭圆曲线参数,
d: privateKey.D
*/
func SerializePrivateKey(curve elliptic.Curve,d *big.Int)(privHex string,err error){
hash := namedCurveToHash(curve)
if hash == crypto.Hash(0){
return "", errors.New("invaild curve")
}
privSerialize := &PrivateKeySerialize{
PrivSerialize:Serialize(d),
PrivType:hash,
}
privSByte,err := json.Marshal(privSerialize)
if err!= nil{
return "",err
}
return hex.EncodeToString(privSByte),nil
}
const PrivKeyBytesLen = 32
// 序列化privKey.D。
func Serialize(d *big.Int) []byte {
b := make([]byte, 0, PrivKeyBytesLen)
return paddedAppend(PrivKeyBytesLen, b, d.Bytes())
}
/*
签名验证
Parameters:
algo:签名使用的hash以及私钥算法
signed:待签名数据
signature:签名
publicKey:验证公钥
*/
func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
var hashType crypto.Hash
var pubKeyAlgo PublicKeyAlgorithm
for _, details := range signatureAlgorithmDetails {
if details.algo == algo {
hashType = details.hash
pubKeyAlgo = details.pubKeyAlgo
}
}
switch hashType {
case crypto.Hash(0):
if pubKeyAlgo != Ed25519 {
return ErrUnsupportedAlgorithm
}
case crypto.MD5:
return nil
default:
if !hashType.Available() {
if hashType != crypto.Hash(21) {
return ErrUnsupportedAlgorithm
}
}
var h hash.Hash
if pubKeyAlgo == SM2 {
h = sm3.New()
} else {
h = hashType.New()
}
h.Write(signed)
signed = h.Sum(nil)
}
switch pub := publicKey.(type) {
case *ecdsa.PublicKey:
if !(pubKeyAlgo == ECDSA || pubKeyAlgo == SM2) {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
}
switch pubKeyAlgo {
case SM2:
if len(signature) == 65 {
signature = signature[:64]
}
r := new(big.Int).SetBytes(signature[:32])
s := new(big.Int).SetBytes(signature[32:])
if !sm2.Verify(&sm2.PublicKey{
Curve: pub.Curve,
X: pub.X,
Y: pub.Y,
}, signed, r, s) {
return errors.New("x509: SM2 verification failure")
}
default:
ecdsaSig := new(ecdsaSignature)
if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
return err
} else if len(rest) != 0 {
return errors.New("x509: trailing data after ECDSA signature")
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
return errors.New("x509: ECDSA signature contained zero or negative values")
}
if !ecdsa.Verify(pub, signed, ecdsaSig.R, ecdsaSig.S) {
return errors.New("x509: ECDSA verification failure")
}
}
return
case *sm2.PublicKey:
if pubKeyAlgo != SM2 {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
}
if len(signature) == 65 {
signature = signature[:64]
}
r := new(big.Int).SetBytes(signature[:32])
s := new(big.Int).SetBytes(signature[32:])
if !(sm2.Verify(pub, signed, r, s)) {
return errors.New("SM2 verification failure")
}
return
}
return ErrUnsupportedAlgorithm
}
/*
签名验证
Parameters:
pub:公钥编码数据
curve:私钥使用的椭圆曲线参数,
*/
func unmarshalPubkey(pub []byte, curve elliptic.Curve) (interface{}, error) {
if curve == nil {
return nil, errors.New("public key curve is null")
}
x, y := elliptic.Unmarshal(curve, pub)
if x == nil {
return nil, errors.New("invalid public key")
}
switch curve {
case sm2.P256Sm2():
return &sm2.PublicKey{Curve: curve, X: x, Y: y}, nil
default:
return &ecdsa.PublicKey{Curve: curve, X: x, Y: y}, nil
}
}
func namedCurveFromHash(hash crypto.Hash) elliptic.Curve {
switch hash {
case crypto.SHA224:
return elliptic.P224()
case crypto.SHA256:
return elliptic.P256()
case crypto.SHA384:
return elliptic.P384()
case crypto.SHA512:
return elliptic.P521()
case crypto.Hash(21):
return sm2.P256Sm2()
}
return nil
}
func namedCurveToHash(curve elliptic.Curve) (crypto.Hash ){
switch curve {
case elliptic.P224():
return crypto.SHA256
case elliptic.P256():
return crypto.SHA256
case elliptic.P384():
return crypto.SHA384
case elliptic.P521():
return crypto.SHA512
case sm2.P256Sm2():
return crypto.Hash(21)
}
return crypto.Hash(0)
}
// paddedAppend appends the src byte slice to dst, returning the new slice.
// If the length of the source is smaller than the passed size, leading zero
// bytes are appended to the dst slice before appending src.
func paddedAppend(size uint, dst, src []byte) []byte {
for i := 0; i < int(size)-len(src); i++ {
dst = append(dst, 0)
}
return append(dst, src...)
}
// ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
// that buf has enough space. If buf is too short the result will be incomplete.
func ReadBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
for j := 0; j < wordBytes && i > 0; j++ {
i--
buf[i] = byte(d)
d >>= 8
}
}
}
//func MarshalPublicKey(curve elliptic.Curve,x,y *big.Int ){
//
//}
\ No newline at end of file
package main
import (
"testing"
)
var privateKey = "59726308197758576002974483116926761969892956433287453489015419592282702209339"
func TestCreateCert(t *testing.T) {
}
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
"encoding/hex"
"crypto"
"encoding/json"
"errors"
)
func certManagement(paths, args []string, stub shim.ChaincodeStubInterface) pb.Response {
switch paths[1] {
case "createOrg": //机构认证
return createOrgApi(args, stub)
case "createDitch": //渠道方入驻
return createDitchApi(args, stub)
case "createMerchants": //商户入驻 .证书操作、 注销、解锁 (签名、证书)
return createMerchantsApi(args, stub)
case "ditchCertBurn": //渠道用户证书注销
return certUpdateDitchApi(args, stub)
case "merchantCertBurn": //商户证书注销
return certUpdateMerchantApi(args, stub)
case "ditchCertUnLock": //渠道用户证书解锁
return certUpdateMerchantApi(args, stub)
case "merchantCertUnLock": //商户证书解锁
return certUpdateMerchantApi(args, stub)
default:
return shim.Error(fmt.Sprintf("Unsupported cert function of %s", paths[1]))
}
}
//机构认证
func createOrgApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
if len(args) < 1 {
return shim.Error("put data operation expected more than 2 parameters! ")
}
org := &Orgnazation{}
err := json.Unmarshal([]byte(args[0]),org)
if err != nil{
return shim.Error(err.Error())
}
cert,err := ParseCertificate([]byte(org.Cert))
if err != nil{
return shim.Error(err.Error())
} else if cert.CertType != OrganizationCert {
return shim.Error("certificate type must organization")
}
//TODO 机构的认证规则待定
key := KEY + org.Oid
err = putStateByte(key,[]byte(args[0]),stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(nil)
}
/*渠道方入驻
Parameters:
args:args[0]:为机构签发者 args[1]:为渠道证书
*/
func createDitchApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
if len(args) < 2 {
return shim.Error("put data operation expected more than 2 parameters! ")
}
orgByte,err := getStateByte(KEY + args[0],stub)
if err != nil{
return shim.Error(err.Error())
}
org := &Orgnazation{}
err = json.Unmarshal(orgByte,org)
if err != nil{
return shim.Error(err.Error())
}
cert,err := ParseCertificate([]byte(org.Cert))
if err != nil{
return shim.Error(err.Error())
} else if cert.CertType != OrganizationCert {
return shim.Error("certificate creater type must organization")
}
ditch := &Ditch{}
err = json.Unmarshal([]byte(args[1]),ditch)
if err != nil{
return shim.Error(err.Error())
}
channelCert,err := ParseCertificate([]byte(ditch.Cert))
if err != nil{
return shim.Error(err.Error())
} else if channelCert.CertType != ChannelCert {
return shim.Error("certificate type must channel")
}
err = channelCert.CheckSignatureFrom(cert)
if err != nil{
return shim.Error(err.Error())
}
key := KEY+ditch.Did
err = putStateByte(key,[]byte(args[1]),stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(nil)
}
/*
商户入驻
Parameters:
args:args[0]:为机构签发者 args[1]:为商户证书
*/
func createMerchantsApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
if len(args) < 2 {
return shim.Error("put data operation expected more than 2 parameters! ")
}
orgByte,err := getStateByte(KEY + args[0],stub)
if err != nil{
return shim.Error(err.Error())
}
org := &Orgnazation{}
err = json.Unmarshal(orgByte,org)
if err != nil{
return shim.Error(err.Error())
}
cert,err := ParseCertificate([]byte(org.Cert))
if err != nil{
return shim.Error(err.Error())
} else if cert.CertType != OrganizationCert {
return shim.Error("certificate creater type must organization")
}
merchant := &Merchant{}
err = json.Unmarshal([]byte(args[1]),merchant)
if err != nil{
return shim.Error(err.Error())
}
merchantCert,err := ParseCertificate([]byte(merchant.Cert))
if err != nil{
return shim.Error(err.Error())
} else if merchantCert.CertType != MerchantCert {
return shim.Error("certificate type must merchant ")
}
err = merchantCert.CheckSignatureFrom(cert)
if err != nil{
return shim.Error(err.Error())
}
key := KEY+merchant.Mid
err = putStateByte(key,[]byte(args[1]),stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(nil)
}
/*
证书注销,直接修改证书的过期时间
Parameters:
args:args[0]:为机构签发者 args[1]:为渠道证书
*/
func certUpdateDitchApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
if len(args) < 2 {
return shim.Error("put data operation expected more than 2 parameters! ")
}
orgByte,err := getStateByte(KEY + args[0],stub)
if err != nil{
return shim.Error(err.Error())
}
org := &Orgnazation{}
err = json.Unmarshal(orgByte,org)
if err != nil{
return shim.Error(err.Error())
}
cert,err := ParseCertificate([]byte(org.Cert))
if err != nil{
return shim.Error(err.Error())
}else if cert.CertType != OrganizationCert {
return shim.Error("certificate updater type must organization")
}
ditch := &Ditch{}
err = json.Unmarshal([]byte(args[1]),ditch)
if err != nil{
return shim.Error(err.Error())
}
subCert,err := ParseCertificate([]byte(ditch.Cert))
if err != nil{
return shim.Error(err.Error())
}
err = subCert.CheckSignatureFrom(cert)
if err != nil{
return shim.Error(err.Error())
}
key := KEY+ditch.Did
_,err = getStateByte(key,stub)
if err != nil{
return shim.Error(err.Error())
}
err = putStateByte(key,[]byte(args[1]),stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(nil)
}
/*
证书注销,直接修改证书的过期时间
Parameters:
args:args[0]:为机构签发者 args[1]:为渠道证书
*/
func certUpdateMerchantApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
if len(args) < 2 {
return shim.Error("put data operation expected more than 2 parameters! ")
}
orgByte,err := getStateByte(KEY + args[0],stub)
if err != nil{
return shim.Error(err.Error())
}
org := &Orgnazation{}
err = json.Unmarshal(orgByte,org)
if err != nil{
return shim.Error(err.Error())
}
cert,err := ParseCertificate([]byte(org.Cert))
if err != nil{
return shim.Error(err.Error())
}else if cert.CertType != OrganizationCert {
return shim.Error("certificate updater type must organization")
}
merchant := &Merchant{}
err = json.Unmarshal([]byte(args[1]),merchant)
if err != nil{
return shim.Error(err.Error())
}
subCert,err := ParseCertificate([]byte(merchant.Cert))
if err != nil{
return shim.Error(err.Error())
}
err = subCert.CheckSignatureFrom(cert)
if err != nil{
return shim.Error(err.Error())
}
key := KEY+merchant.Mid
_,err = getStateByte(key,stub)
if err != nil{
return shim.Error(err.Error())
}
err = putStateByte(key,[]byte(args[1]),stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(nil)
}
/*
证书解锁,直接修改证书的过期时间
Parameters:
args:args[0]:为机构签发者 args[1]:为渠道证书
*/
func certUnLockApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
if len(args) < 2 {
return shim.Error("put data operation expected more than 2 parameters! ")
}
return shim.Success(nil)
}
/*
进行用户交易验证
*/
func CheckCertSignature( message *Message,txType TxType,stub shim.ChaincodeStubInterface)(pubKey string,err error){
cert := &Certificate{}
switch txType {
case CreateCoupon:
cert ,err = getCert(message.UserId,0,stub)
if err != nil{
return
}
pubKey = hex.EncodeToString(cert.PublicKeyByte)
if cert.CertType != OrganizationCert{
return "",errors.New("only organization account can create coupon")
}
case DisCoupon:
cert ,err = getCert(message.UserId,0,stub)
if err != nil{
return
}
pubKey = hex.EncodeToString(cert.PublicKeyByte)
if cert.CertType != OrganizationCert{
return "",errors.New("only organization account can distribute coupon")
}
case ApplyCoupon:
cert ,err = getCert(message.UserId,1,stub)
if err != nil{
return
}
pubKey = hex.EncodeToString(cert.PublicKeyByte)
if cert.CertType != ChannelCert{
return "",errors.New("only channel account can create apply coupon transaction")
}
case UseCoupon:
cert ,err = getCert(message.UserId,2,stub)
if err != nil{
return
}
pubKey = hex.EncodeToString(cert.PublicKeyByte)
if cert.CertType != MerchantCert{
return "",errors.New("only merchant account can create use coupon transaction")
}
default:
return "",errors.New("Unsupported transaction types")
}
// 检查交易时间是否在证书有效期内
//timestamp,err := stub.GetTxTimestamp()
//fmt.Println(timestamp.Seconds)
//fmt.Println(cert.NotBefore)
//fmt.Println(cert.NotAfter)
//if !(cert.NotBefore < timestamp.Seconds && cert.NotAfter > timestamp.Seconds) {
// return "",errors.New("cert expired ")
//}
var algo SignatureAlgorithm
if cert.PublicKeyHashAlgorithm == crypto.Hash(21){
algo = SM2WithSM3
}else {
algo = ECDSAWithSHA256
}
//signed,err := hex.DecodeString(message.Data)
//if err != nil{
// return
//}
signature,err := hex.DecodeString(message.Sign)
if err != nil{
return
}
err = cert.CheckSignature(algo,[]byte(message.Data),signature)
return
}
/*
得到证书并解析
*/
func getCert(userId string,userType int,stub shim.ChaincodeStubInterface)( cert *Certificate, err error){
switch userType {
case 0 :
org := &Orgnazation{}
orgByte,err := getStateByte(KEY+userId,stub)
if err != nil{
return nil,err
}
err = json.Unmarshal(orgByte,org)
if err != nil{
return nil,err
}
cert,err = ParseCertificate([]byte(org.Cert))
if err != nil{
return nil,err
} else if cert.CertType != OrganizationCert {
err = errors.New("certificate type must organization")
return nil,err
}
case 1:
ditch := &Ditch{}
ditchByte,err := getStateByte(KEY+userId,stub)
if err != nil{
return nil,err
}
err = json.Unmarshal(ditchByte,ditch)
if err != nil{
return nil,err
}
cert,err = ParseCertificate([]byte(ditch.Cert))
if err != nil{
return nil,err
} else if cert.CertType != ChannelCert {
err = errors.New("certificate type must ditch")
return nil,err
}
case 2:
mer := &Merchant{}
merByte,err := getStateByte(KEY+userId,stub)
if err != nil{
return nil,err
}
err = json.Unmarshal(merByte,mer)
if err != nil{
return nil,err
}
cert,err = ParseCertificate([]byte(mer.Cert))
if err != nil{
return nil,err
} else if cert.CertType != MerchantCert {
err = errors.New("certificate type must merchant")
return nil,err
}
default:
err = errors.New("unsupport user type ")
}
return
}
package main
import "github.com/hyperledger/fabric/core/chaincode/shim"
import (
pb "github.com/hyperledger/fabric/protos/peer"
"fmt"
"encoding/json"
)
const KEY = "COUPONS-"
type CPSChainCode struct {
}
func (t *CPSChainCode) Init(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success([]byte("init successful! "))
}
func (t *CPSChainCode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
functionName, args := stub.GetFunctionAndParameters()
paths := splitPath(functionName)
return Router(paths, args, stub)
}
func Router(paths, args []string, stub shim.ChaincodeStubInterface) pb.Response {
switch paths[0] {
case "certManagement": //证书管理
return certManagement(paths,args, stub)
case "getCoupons": //机构查询发行的券信息
return getCouponsApi(args, stub)
case "getCouponsByAddress": //通过UTXO地址查看资产信息
return getCouponsByAddressApi(args, stub)
case "subsidies": //补贴请求
return subsidiesApi(args, stub)
case "createTx":
return transactionProcess(paths,args, stub)
default:
return shim.Error(fmt.Sprintf("Unsupported function %s", paths[0]))
}
}
//入参:券id、机构证书、机构签名
func getCouponsApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans,_,_,err := messageToTrans(CreateCoupon,args,stub)
if err != nil{
return shim.Error(err.Error())
}
var coupon Coupons
expand, ok := trans.Value.(string) //判断类型
if !ok {
return shim.Error("Error expanding parameter type,must be string")
}
err = json.Unmarshal([]byte(expand), &coupon)
if err != nil {
return shim.Error("Parameter resolution failed" + err.Error())
}
coupByte,err :=getStateByte(KEY+coupon.CoupId,stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(coupByte)
}
// 入参:utxo地址,证书、交易签名
func getCouponsByAddressApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans,_,_,err := messageToTrans(CreateCoupon,args,stub)
if err != nil{
return shim.Error(err.Error())
}
//查询utxo信息
utxoByte,err :=getStateByte(KEY+trans.From,stub)
if err != nil{
return shim.Error(err.Error())
}
return shim.Success(utxoByte)
}
// 入参:商户公钥、机构证书、交易签名
//出参:交易流水
func subsidiesApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans,_, _,err := messageToTrans(CreateCoupon,args,stub)
// 根据商户公钥查询出该商户所有UTXO记录
arg :="{\"selector\":{\"public_key\":\""+trans.ToPub+"\"}}"
transferInfo,err :=getStateByConditions(arg,stub)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(transferInfo)
}
func main() {
err := shim.Start(&CPSChainCode{})
if err != nil {
fmt.Printf("Error starting EncCC chaincode: %s", err)
}
}
\ No newline at end of file
package main
import (
"testing"
"github.com/hyperledger/fabric/core/chaincode/shim"
"fmt"
"encoding/json"
"encoding/hex"
)
var orgPublicKey = "04e57c3ece2608fd0123c78b5905eac3d22523027ae38500f117472135aafb9c09b83e6c9ee8a5358fc109c92eb2292118d672bd338b3ddbafb2e0f97c6f063e0c"
var orgPrivateKey = "7b22707269765f73657269616c697a65223a223451444d4156526a74496d6674734231626941494261446562542b4b6737374173492f632b7a52554744733d222c22707269765f74797065223a32317d"
var orgCert = `{"public_key_hash_algorithm":21,"public_key_byte":"BOV8Ps4mCP0BI8eLWQXqw9IlIwJ644UA8RdHITWq+5wJuD5snuilNY/BCckusikhGNZyvTOLPduvsuD5fG8GPgw=","publickey":null,"cert_type":2,"extensions":100,"not_before":1590481638,"not_after":1587889638,"cert_hash":"Ha472yKk1K4IzZy2OIX3LRoACEHBvAWgz4Mq2lAL99I=","signature":"HTM2m8T/SXY/76G+F5ha26O4fZFtP4UrgjZkJs0dvUgYGct95CAA5fVFvUAXcuujcLmGiUtC9I/LUthCzMALzQ==","signature_algorithm":16}`
var channelPublicKey = "048d9056afe7afb7f0e9626bec6629832641f3b69a5b211f23a43b59075bdc97c1687f180e09dc01e994b161c046f46e35179bf76f66443d0ebb6f099feb9bf009"
var channelPrivateKey = "7b22707269765f73657269616c697a65223a222f686736796e6e4c366858715357784530456479746f743939526a4e69563835793374585a37464e62616f3d222c22707269765f74797065223a32317d"
var channelCert = `{"public_key_hash_algorithm":21,"public_key_byte":"BI2QVq/nr7fw6WJr7GYpgyZB87aaWyEfI6Q7WQdb3JfBaH8YDgncAemUsWHARvRuNReb929mRD0Ou28Jn+ub8Ak=","publickey":null,"cert_type":2,"extensions":100,"not_before":1590481745,"not_after":1587889745,"cert_hash":"HcVbsa7IyEy28DbuUTSbyG7TqxM7CXd3IQwlD+1QR/A=","signature":"/H74hQgN6hEL7c2+p2hfCgmzKw/uXxVtsMWf5xtxH+FgRAyaz2nLr1pdmcszZRJmEGTeBenR+bU0rtTmog7b6w==","signature_algorithm":16}`
var merchantPublicKey = "041922e1019b52daa86246b1a330efc2e7308f9019000bda3103bd863a05776ff3d6d274b368778bbbfccfcb07179dae39ae55cb79aba3da14ecdbb20bb9239bf7"
var merchantPrivateKey = "7b22707269765f73657269616c697a65223a226e68724c34536c454d6b7431356c2b385651576b466d6d724c516333674b364a62527565757a39594451413d222c22707269765f74797065223a32317d"
var merchantCert = `{"public_key_hash_algorithm":21,"public_key_byte":"BBki4QGbUtqoYkaxozDvwucwj5AZAAvaMQO9hjoFd2/z1tJ0s2h3i7v8z8sHF52uOa5Vy3mro9oU7NuyC7kjm/c=","publickey":null,"cert_type":3,"extensions":100,"not_before":1590482496,"not_after":1587890496,"cert_hash":"C/L+z0ZZPnbPX8mkab88feMYNlSPRx9s5Xsitls7zoU=","signature":"5o/BpTdBedJea7w/yYpIjuj1OJa/g5hh5c2oAYDN0pmOQlHw/nftJTERMpl8GqwU3sEXh5My3tFmuI6WbLyuXA==","signature_algorithm":16}`
//var createCouponsData = `{"expand": {"coup_id": "0001","coup_type": "XJQ","coup_valid": "2017-01-13 23:59:59","coup_available_time": "券可用时间段","coup_description": "券使用说明","coup_quantity": 1000000,"coup_amount": 10.00,"coup_total_amount": 10000000,"floor_amount": 10.00},"to":"org123"}`
//var createCouponsData = `{"value":"{\"coup_id\":\"0001\",\"coup_type\":\"XJQ\",\"coup_valid\":\"2017-01-13 23:59:59\",\"coup_available_time\":\"券可用时间段\",\"coup_description\":\"券描述\",\"coup_quantity\":1000000,\"coup_amount\":10,\"coup_discount\":0.5,\"coup_total_amount\":10000000,\"floor_amount\":10,\"extensions\":null}","fromAddress":"","toAddress":"org123","toPublicKey":""}`
var createCouponsData = `{"value": "{\"uAddress\":\"wwe=rrrrr\",\"mid\":\"0001\"}"}`
var createCouponsDataSign =[]byte{207 ,240, 50, 5, 177, 135, 76 ,137, 236 ,206, 203, 228, 77, 16 ,230, 64 ,57 ,97, 237, 151, 184, 122, 214, 119 ,20, 51, 130 ,35 ,49 ,218, 32, 17, 121 ,70 ,57 ,241 ,163, 172, 191, 6 ,126, 40 ,98, 228, 197, 88 ,44 ,79 ,253 ,13, 245, 85, 129 ,204 ,254, 196 ,26 ,60, 114 ,120, 65, 172, 95 ,200}
var disCouponsData =`{"from":"org123","to":"channel123","to_pub":"04aa7cf4f0950be19033848ab8956160f2ecb461e7034d4d2e95990f233c2166de4969eec6e69988d5cfbcf3461a2a5a53dd131bfab343dcefdc24a466d0faf09e","value":10000}`
var disCouponsDataSign =[]byte{115, 165, 9 ,100, 154 ,56 ,79 ,35 ,146, 86 ,229 ,88 ,160, 82 ,228, 62 ,242 ,32 ,244 ,183, 221 ,174, 172, 186 ,53 ,200, 168, 250, 230, 21, 90, 92 ,128 ,103 ,117 ,234, 168, 145 ,224, 178, 202, 9 ,206, 121, 0 ,139 ,38 ,78, 247, 161, 147 ,60 ,20, 115 ,131, 14, 161, 110, 232, 102, 37, 109, 167, 179}
var applyCouponsData =` {"from":"channel123","to":"user123","to_pub":"123456789"}`
var applyCouponsDataSign =[]byte{154,81,233,239,237,59,16,126,169,142,112,144,255,5,43,22,101,250,208,159,199,203,100,221,24,156,14,194,149,173,47,97,113,75,80,106,37,154,220,231,181,60,150,182,109,53,175,158,175,138,93,165,161,127,39,110,85,119,8,236,143,96,16,160}
var useCouponsData =` {"expand":"订单信息","from":"user123","to":"mert123","to_pub":"123456789"}`
var useCouponsDataSign =[]byte{146,15,96,112,62,182,206,85,28,253,120,129,194,242,121,150,74,147,144,171,164,196,54,187,76,79,69,228,236,208,5,194,112,184,191,20,74,120,48,39,161,14,44,160,238,52,13,1,172,8,155,132,43,145,157,245,253,52,74,48,14,164,10,50}
var getCouponsData = `{"expand": {"coup_id": "0001"}}`
var getCouponsByAddress = `{"from":"mert123"}`
var subsidiesData = `{"to_pub":"048014f3e260f1e202259c0e0dcf9a70478c8d8e808ec91f27af1320c31c4e9183b7a12813a4a524b07b0fa83850babff2194f18e7eed38cd639f3eb6c86b61d50"}`
func TestCreateCoupons(t *testing.T) {
cc := new(CPSChainCode)
stub := shim.NewMockStub("CPSCC",cc)
stub.MockInit("init",nil)
fmt.Println()
//fmt.Println("========================================invoke certManagement createOrg============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("certManagement/createOrg"),[]byte(orgCert),[]byte(orgPublicKey)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//
//fmt.Println("========================================invoke certManagement createDitch============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("certManagement/createDitch"),[]byte(orgPublicKey),[]byte(channelCert)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//fmt.Println("========================================invoke certManagement createMerchantsApi============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("certManagement/createMerchants"),[]byte(orgPublicKey),[]byte(merchantCert)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke createTx createCoupons============================================")
fmt.Println()
fmt.Println()
responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/updateMertUtxo"), []byte(orgPublicKey),[]byte(createCouponsData),[]byte(createCouponsDataSign)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//fmt.Println("========================================invoke createTx disCoupon============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/disCoupon"),[]byte(orgPublicKey),[]byte(disCouponsData),[]byte(disCouponsDataSign)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//fmt.Println("========================================invoke createTx userApplyCoupon============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/userApplyCoupon"),[]byte(channelPublicKey),[]byte(applyCouponsData),[]byte(applyCouponsDataSign)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//fmt.Println("========================================invoke createTx useCoupon============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/useCoupon"),[]byte(merchantPublicKey),[]byte(useCouponsData),[]byte(useCouponsDataSign)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//
//fmt.Println("========================================query getCoupons============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("getCoupons"),[]byte(orgPublicKey),[]byte(getCouponsData),[]byte(useCouponsDataSign)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//fmt.Println("========================================query getCouponsByAddress============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("getCouponsByAddress"),[]byte(orgPublicKey),[]byte(getCouponsByAddress),[]byte(useCouponsDataSign)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
//
//fmt.Println("========================================query subsidiesApi============================================")
//fmt.Println()
//fmt.Println()
//responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("subsidies"),[]byte(orgPublicKey),[]byte(subsidiesData),[]byte(useCouponsDataSign)})
//fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
}
var orgUser = `{"oid":"1","name":"","cert":"{\"public_key_hash_algorithm\":21,\"public_key_byte\":\"BOV8Ps4mCP0BI8eLWQXqw9IlIwJ644UA8RdHITWq+5wJuD5snuilNY/BCckusikhGNZyvTOLPduvsuD5fG8GPgw=\",\"publickey\":null,\"cert_type\":1,\"extensions\":100,\"not_before\":1590481638,\"not_after\":1587889638,\"cert_hash\":\"Ha472yKk1K4IzZy2OIX3LRoACEHBvAWgz4Mq2lAL99I=\",\"signature\":\"HTM2m8T/SXY/76G+F5ha26O4fZFtP4UrgjZkJs0dvUgYGct95CAA5fVFvUAXcuujcLmGiUtC9I/LUthCzMALzQ==\",\"signature_algorithm\":16}","create_time":"0001-01-01T00:00:00Z"}`
var ditchUser = `{"did":"11","name":"","cert":"{\"public_key_hash_algorithm\":21,\"public_key_byte\":\"BI2QVq/nr7fw6WJr7GYpgyZB87aaWyEfI6Q7WQdb3JfBaH8YDgncAemUsWHARvRuNReb929mRD0Ou28Jn+ub8Ak=\",\"publickey\":null,\"cert_type\":2,\"extensions\":100,\"not_before\":1590481745,\"not_after\":1587889745,\"cert_hash\":\"HcVbsa7IyEy28DbuUTSbyG7TqxM7CXd3IQwlD+1QR/A=\",\"signature\":\"/H74hQgN6hEL7c2+p2hfCgmzKw/uXxVtsMWf5xtxH+FgRAyaz2nLr1pdmcszZRJmEGTeBenR+bU0rtTmog7b6w==\",\"signature_algorithm\":16}","create_time":"0001-01-01T00:00:00Z"}`
var merUser =`{"mid":"111","type":"","name":"","address":"","cert":"{\"public_key_hash_algorithm\":21,\"public_key_byte\":\"BBki4QGbUtqoYkaxozDvwucwj5AZAAvaMQO9hjoFd2/z1tJ0s2h3i7v8z8sHF52uOa5Vy3mro9oU7NuyC7kjm/c=\",\"publickey\":null,\"cert_type\":3,\"extensions\":100,\"not_before\":1590482496,\"not_after\":1587890496,\"cert_hash\":\"C/L+z0ZZPnbPX8mkab88feMYNlSPRx9s5Xsitls7zoU=\",\"signature\":\"5o/BpTdBedJea7w/yYpIjuj1OJa/g5hh5c2oAYDN0pmOQlHw/nftJTERMpl8GqwU3sEXh5My3tFmuI6WbLyuXA==\",\"signature_algorithm\":16}","create_time":"0001-01-01T00:00:00Z"}`
func TestCreateUser(t *testing.T){
org := &Orgnazation{}
org.Cert = orgCert
org.Oid = "1"
orgByte,err := json.Marshal(org)
if err!=nil{
t.Error(err)
}
fmt.Println(string(orgByte))
ditch := &Ditch{}
ditch.Cert = channelCert
ditch.Did = "11"
ditchByte,err := json.Marshal(ditch)
if err!=nil{
t.Error(err)
}
fmt.Println(string(ditchByte))
mer := &Merchant{}
mer.Cert = merchantCert
mer.Mid = "111"
merByte,err := json.Marshal(mer)
if err!=nil{
t.Error(err)
}
fmt.Println(string(merByte))
}
func TestRouterest(t *testing.T) {
//coupon := &Coupons{
// CoupId:"0001",
// CoupType:"XJQ",
// CoupValid:"2017-01-13 23:59:59",
// CoupAvailableTime:"券可用时间段",
// CoupDescription:"券描述",
// CoupQuantity:1000000,
// CoupAmount:10.00,
// CoupDiscount:0.5,
// CoupTotalAmount:10000000.00,
// FloorAmount:10.00,
// Extensions:nil,
//}
type Test struct {
UAddress []string `json:"uAddress"`
Mid string `json:"mid"`
}
test := &Test{
UAddress:[]string{"qqqqq","wwwwww","eeeeee"},
Mid:"0001",
}
couponByte,err := json.Marshal(test)
if err!=nil{
fmt.Println("err",err)
}
fmt.Println("couponByte",couponByte)
tx:= Trans{
Value:string(couponByte),
}
txByte,err := json.Marshal(tx)
if err!=nil{
fmt.Println("err",err)
}
fmt.Println(string(txByte))
}
func TestParse(t *testing.T){
_,err := ParseCertificate([]byte(channelCert))
if err!=nil{
t.Error(err)
}
}
var userPubHex = `04e6496ec8db3af69f1efbe12dc6e6c28402d2ff928e69160040cd4e293402d224785cf12912635306a65dc08f2dc840daa71cc30049fb77d3a95480f09d011c7d`
var usePrivHex = `7b22707269765f73657269616c697a65223a223453384363544476374a4862767867747076516969653961506a784e756c316b46324431496850765574553d222c22707269765f74797065223a32317d`
func TestCreateTx(t *testing.T){
//coupons:= &Coupons{
// CoupId:"c1",
// IssueOrgId:"1",
// CoupQuantity:100,
// UseMerchats:[]string{"111"},
//}
//couponsByte,err := json.Marshal(coupons)
//if err !=nil{
// t.Error(err)
//}
//disvalue:= make( map[string]interface{})
//disvalue["did"] = "11"
//disvalue["amount"] = 99
//disByte,err := json.Marshal(disvalue)
//if err !=nil{
// t.Error(err)
//}
//user:= UserInfo{
//
//}
//userByte,err := json.Marshal(user)
//if err !=nil{
// t.Error(err)
//}
//tx := Trans{
// Value:string(userByte),
// From:"utxo2",
//To:"utxo3",
//ToPub:userPubHex,
//}
usevalue:= make( map[string]interface{})
usevalue["privHex"] = usePrivHex
useByte,err := json.Marshal(usevalue)
if err !=nil{
t.Error(err)
}
tx := Trans{
Value:string(useByte),
From:"utxo3",
To:"utxo4",
ToPub:userPubHex,
}
txByte,err := json.Marshal(tx)
if err !=nil{
t.Error(err)
}
fmt.Println(hex.EncodeToString(txByte))
fmt.Println(string(txByte))
message := &Message{
UserId:"1",
Data:string(txByte),
Sign:"c384f2bc27a9abc87b07ce798fd4a65323aab9ddbd4aee8b379c1a987e6cf272b9becc5fb4bcd2f3d8495fe715ed4c263c6b4c5ce68067d39922df12fd075fc9",
}
messageByte,err := json.Marshal(message)
if err !=nil{
t.Error(err)
}
fmt.Println(string(messageByte))
}
var createCouponsSign =`e99c297f03c1f3b5bbf1602dc15ff61bb05fb2617abc1e29f28f9d59c8445e39d19d3897827a85567032a7e0e711e20c6092e6e733a3a886de87ab3bf6b9e671`
var createCouponsDate =`{"value":"{\"coup_id\":\"c1\",\"issue_org_id\":\"1\",\"coup_type\":\"\",\"coup_valid\":\"\",\"coup_available_time\":\"\",\"coup_description\":\"\",\"coup_quantity\":100,\"coup_amount\":0,\"coup_discount\":0,\"coup_total_amount\":0,\"floor_amount\":0,\"use_merchats\":[\"111\"],\"use_merchants_type\":null,\"extensions\":null}","fromAddress":"","toAddress":"utxo1","toPublicKey":"1"}`
var disCouponsSign = `54063e3edce3905d44312a7e4038d9a06f819eae0991d04a4b8e944c721d716eaaab47befba449c2bf4e4634847daad3f2c4ed49ae80e50b4f051a1a8675cb99`
var disCouponsDate = `{"value":"{\"amount\":99,\"did\":\"11\"}","fromAddress":"utxo1","toAddress":"utxo2","toPublicKey":"11"}`
var ApplyCouponsSign = `7092dde322c376f5d43541f219ffe3234b8cea365a7e5aa49983865a36516e2c0e7b875cc5750e61b6a1bf3d22e0f004ae42d73aaad655fe972047b70ff91246`
var ApplyCouponsDate = `{"value":"{\"uid\":\"\",\"name\":\"\",\"number\":\"\",\"phone\":\"\",\"create_time\":\"0001-01-01T00:00:00Z\"}","fromAddress":"utxo2","toAddress":"utxo3","toPublicKey":"04e6496ec8db3af69f1efbe12dc6e6c28402d2ff928e69160040cd4e293402d224785cf12912635306a65dc08f2dc840daa71cc30049fb77d3a95480f09d011c7d"}`
var useCouponsSign = `a0a253661923245cdc2eef15ab665d96fd7383608587a652baa68303687f1b6e5fb86fe2bda2b94b68e9bf5478793154c7420c3688d61996c95d87d43a49649b`
var useCouponsDate = `{"value":"{\"privHex\":\"7b22707269765f73657269616c697a65223a223453384363544476374a4862767867747076516969653961506a784e756c316b46324431496850765574553d222c22707269765f74797065223a32317d\"}","fromAddress":"utxo3","toAddress":"utxo4","toPublicKey":"04e6496ec8db3af69f1efbe12dc6e6c28402d2ff928e69160040cd4e293402d224785cf12912635306a65dc08f2dc840daa71cc30049fb77d3a95480f09d011c7d"}`
func TestCouponsFlow(t *testing.T){
cc := new(CPSChainCode)
stub := shim.NewMockStub("CPSCC",cc)
stub.MockInit("init",nil)
fmt.Println()
fmt.Println("========================================invoke certManagement createOrg============================================")
fmt.Println()
fmt.Println()
responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("certManagement/createOrg"),[]byte(orgUser)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke certManagement createDitch============================================")
fmt.Println()
fmt.Println()
responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("certManagement/createDitch"),[]byte("1"),[]byte(ditchUser)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke certManagement createMerchantsApi============================================")
fmt.Println()
fmt.Println()
responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("certManagement/createMerchants"),[]byte("1"),[]byte(merUser)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke createTx createCoupons============================================")
fmt.Println()
fmt.Println()
responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/createCoupons"), []byte("1"),[]byte(createCouponsDate),[]byte(createCouponsSign)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke createTx disCoupon============================================")
fmt.Println()
fmt.Println()
responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/disCoupon"),[]byte("1"),[]byte(disCouponsDate),[]byte(disCouponsSign)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke createTx userApplyCoupon============================================")
fmt.Println()
fmt.Println()
responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/userApplyCoupon"),[]byte("11"),[]byte(ApplyCouponsDate),[]byte(ApplyCouponsSign)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
fmt.Println("========================================invoke createTx useCoupon============================================")
fmt.Println()
fmt.Println()
responseByPutschema = stub.MockInvoke("invoke1",[][]byte{[]byte("createTx/useCoupon"),[]byte("111"),[]byte(useCouponsDate),[]byte(useCouponsSign)})
fmt.Printf("Invoke status %d,message %s and payload %s\n",responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"time"
)
//券结构
type Coupons struct {
CoupId string `json:"coup_id"` //券id
IssueOrgId string `json:"issue_org_id"` //券发行机构ID
CoupType string `json:"coup_type"` //券类型
CoupValid string `json:"coup_valid"` //券有效期
CoupAvailableTime string `json:"coup_available_time"` //券可用时间段
CoupDescription string `json:"coup_description"` //券使用说明
CoupQuantity int `json:"coup_quantity"` //发行数量
CoupAmount float64 `json:"coup_amount"` //面额
CoupDiscount float64 `json:"coup_discount"` //折扣
CoupTotalAmount float64 `json:"coup_total_amount"` //券总金额
FloorAmount float64 `json:"floor_amount"` //券使用门槛,最低消费金额
UseMerchats []string `json:"use_merchats"` //当前券支持的商户Id
UseMerchantsType *MerchantsType `json:"use_merchants_type"`
Extensions interface{} `json:"extensions"` //拓展信息,机构自定义
}
type MerchantsType struct {
UseMerchatsType []int `json:"use_merchats_type"` //当前券支持的商户类型
OrgMerchatsType []string `json:"org_merchats_type"` //支持的机构签发类别,len 为0 表示只支持自己机构签发的
IsAll []bool `json:"is_all"` //当前券支持的商户类型是只支持自己签发的商户还是支持全部机构签发的商户
}
//券可用时间段
type CoupAvailable struct {
AvailableDay string `json:"available_day"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
}
//UTXO结构
type Utxo struct {
Address string `json:"address"` //Utxo记录地址
PublicKey string `json:"public_key"` //公钥
UserId string `json:"user_id"` //用户Id,代替公钥
Status string `json:"status"` //utxo状态.0发行 1分发 2领取 3 已使用
CoupType string `json:"coup_type"` //券类型
CoupQuantity int `json:"coup_quantity"` //券总量
CoupAmount float64 `json:"coup_amount"` //面额
CoupDiscount float64 `json:"coup_discount"` //折扣
FloorAmount float64 `json:"floor_amount"` //券使用门槛,最低消费金额
PreAddress []string `json:"pre_address"` //前置utxo地址
CoupId string `json:"coup_id"` //券id
}
//订单结构
type Order struct {
OrderId string `json:"order_id"`
CreateTime time.Time `json:"create_time"`
OrderMoney float32 `json:"order_money"`
}
//用户信息
type UserInfo struct {
Uid string `json:"uid"` //用户id
Name string `json:"name"` //用户名
Number string `json:"number"` //身份证号
Phone string `json:"phone"` //手机号
CreateTime time.Time `json:"create_time"` //创建时间
}
//商户信息
type Merchant struct {
Mid string `json:"mid"` //商户id
Type string `json:"type"` //商户类型
Name string `json:"name"` //商户名称
Address string `json:"address"` //商户地址
Cert string `json:"cert"` //证书
CreateTime time.Time `json:"create_time"` //创建时间
}
//渠道信息
type Ditch struct {
Did string `json:"did"` //渠道id
Name string `json:"name"` //渠道名称
Cert string `json:"cert"` //证书
CreateTime time.Time `json:"create_time"` //创建时间
}
//机构信息
type Orgnazation struct {
Oid string `json:"oid"`
Name string `json:"name"` //渠道名称
Cert string `json:"cert"` //证书
CreateTime time.Time `json:"create_time"` //创建时间
}
// 前端传递的数据
type Message struct {
UserId string `json:"user_id"` // 交易发起人的用户Id
Data string `json:"data"` // 交易参数
Sign string `json:"sign"` // 交易签名信息,if是商户交易,这里是券公钥
}
//交易体
type Trans struct {
Value interface{} `json:"value"` // 拓展字段,1、用发行卡券时代表卡券信息。2、使用卡券时代表订单信息.3、查询卡券信息时代表卡券编号。
From string `json:"fromAddress"` //发起方utxo地址
To string `json:"toAddress"` // 接收方utxo地址
ToPub string `json:"toPublicKey"` //接收者公钥
}
func putStateUtxo(key string, utxo *Utxo, stub shim.ChaincodeStubInterface) error {
valueByte, err := json.Marshal(utxo)
if err != nil {
return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
}
err = stub.PutState(key, valueByte)
if err != nil {
return fmt.Errorf("putState %s data fail,err: %s", key, err)
}
return nil
}
func putStateStruct(key string, value interface{}, stub shim.ChaincodeStubInterface) error {
valueByte, err := json.Marshal(value)
if err != nil {
return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
}
err = stub.PutState(key, valueByte)
if err != nil {
return fmt.Errorf("putState %s data fail,err: %s", key, err)
}
return nil
}
func putStateByte(key string, value []byte, stub shim.ChaincodeStubInterface) error {
err := stub.PutState(key, value)
if err != nil {
return fmt.Errorf("putState %s data fail,err: %s", key, err)
}
return nil
}
func putStateCoup(key string, coupons Coupons, stub shim.ChaincodeStubInterface) error {
valueByte, err := json.Marshal(coupons)
if err != nil {
return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
}
err = stub.PutState(key, valueByte)
if err != nil {
return fmt.Errorf("putState %s data fail,err: %s", key, err)
}
return nil
}
func getStateUtxo(key string, stub shim.ChaincodeStubInterface) (*Utxo, error) {
var utxo *Utxo
utxoByteInfo, err := stub.GetState(key)
if err != nil {
return nil, err
}
if utxoByteInfo == nil {
return nil, fmt.Errorf("The query information is empty")
}
err = json.Unmarshal(utxoByteInfo, &utxo)
if err != nil {
return nil, fmt.Errorf("Byte array serialization failed")
}
return utxo, nil
}
func getStateCoupons(key string, stub shim.ChaincodeStubInterface) (*Coupons, error) {
coupons := &Coupons{}
couponsByteInfo, err := stub.GetState(key)
if err != nil {
return nil, err
}
if couponsByteInfo == nil {
return nil, fmt.Errorf("The query information is empty")
}
err = json.Unmarshal(couponsByteInfo, coupons)
if err != nil {
return nil, fmt.Errorf("Byte array serialization failed")
}
return coupons, nil
}
func getStateByte(key string, stub shim.ChaincodeStubInterface) ([]byte, error) {
byteInfo, err := stub.GetState(key)
if err != nil {
return nil, err
}
if byteInfo == nil {
return nil, fmt.Errorf("The query information is empty")
}
return byteInfo, nil
}
func getStateStruct(key string, value interface{}, stub shim.ChaincodeStubInterface) (err error) {
byteInfo, err := stub.GetState(key)
if err != nil {
return err
}
if byteInfo == nil {
return fmt.Errorf("The query information is empty")
}
return json.Unmarshal(byteInfo, value)
}
func getStateByConditions(key string, stub shim.ChaincodeStubInterface) ([]byte, error) {
resultsIterator, err := stub.GetQueryResult(key)
defer resultsIterator.Close()
if err != nil {
return nil, err
}
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
fmt.Println(queryResponse.String())
if err != nil {
return nil, err
}
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
return buffer.Bytes(), nil
}
//判断key是否存在
func checkKey(key string, stub shim.ChaincodeStubInterface) (bool, error) {
info, err := stub.GetState(key)
if err != nil {
return false, err
}
if info == nil {
return false, nil
}
return true, nil
}
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
"encoding/json"
"strings"
"encoding/hex"
)
func transactionProcess(paths, args []string, stub shim.ChaincodeStubInterface) pb.Response {
switch paths[1] {
case "createCoupons": //发行卡券
return createCouponsApi(args, stub)
case "disCoupon": //分发卡券
return disCouponApi(args, stub)
case "userApplyCoupon": //用户申请券
return userApplyCouponApi(args, stub)
case "useCoupon": //使用卡券
return useCouponApi(args, stub)
case "updateMertUtxo":
return updateMertUtxoApi(args,stub)
default:
return shim.Error(fmt.Sprintf("Unsupported schema function of %s", paths[1]))
}
}
//发行卡券:卡券信息
// 入参:券信息(券id、券类型、发放开始时间、券有效期、可用时间段、使用说明、发行数量、面额、券总金额、最低额度使用门槛、拓展信息)、UTXO地址、机构证书、机构签名
func createCouponsApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans, message, _,err := messageToTrans(CreateCoupon, args, stub)
if err != nil {
return shim.Error(err.Error())
}
//解析卡券信息
var coupon Coupons
expand, ok := trans.Value.(string) //判断类型
if !ok {
return shim.Error("Error expanding parameter type,must be string")
}
err = json.Unmarshal([]byte(expand), &coupon)
if err != nil {
return shim.Error("Parameter error" + err.Error())
}
boo, err := checkKey(KEY+coupon.CoupId, stub)
if err != nil {
return shim.Error(err.Error())
}
if boo {
return shim.Error("Coupon issue failed, coupon number already exists")
}
boo, err = checkKey(KEY+trans.To, stub)
if err != nil {
return shim.Error(err.Error())
}
if boo {
return shim.Error("Coupon issue failed, coupon number already exists")
}
//创建UTXO资产
utxo := &Utxo{
Address: trans.To,
UserId: message.UserId,
Status: "0",
CoupType: coupon.CoupType,
CoupQuantity: coupon.CoupQuantity,
CoupAmount: coupon.CoupAmount,
CoupDiscount: coupon.CoupDiscount,
FloorAmount: coupon.FloorAmount,
PreAddress: []string{""},
CoupId: coupon.CoupId,
}
err = putStateCoup(KEY+coupon.CoupId, coupon, stub)
if err != nil {
return shim.Error(err.Error())
}
err = putStateUtxo(KEY+trans.To, utxo, stub)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte(stub.GetTxID()))
}
//分发卡券:
// 入参:渠道方证书、券数量、渠道utxo地址、机构utxo地址、机构签名
func disCouponApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans, message, _,err := messageToTrans(DisCoupon, args, stub)
if err != nil {
return shim.Error(err.Error())
}
expand, ok := trans.Value.(string) //判断类型
if !ok {
return shim.Error("Error expanding parameter type,must be string")
}
var dat map[string]interface{}
err =json.Unmarshal([]byte(expand), &dat)
if err != nil{
fmt.Println(err)
}
//拿到机构id。
did ,ok:= dat["did"].(string)
if !ok {
return shim.Error("Error expanding did parameter type,must be string")
}
//机构UTXO
orgUtxo, err := getStateUtxo(KEY+trans.From, stub)
if err != nil {
return shim.Error("getStateUtxo error" + err.Error())
}
//判断渠道UTXO的地址是否已存在
boo, err := checkKey(KEY+trans.To, stub)
if err != nil {
return shim.Error(err.Error())
}
if boo {
return shim.Error("Coupon distribution failed, utxo address already exists")
}
if orgUtxo.UserId != message.UserId {
return shim.Error("UserId alignment error")
}
if orgUtxo.Status != "0" {
return shim.Error("Card coupon status is abnormal and cannot be dis")
}
//分发卡券,资产拆分
_amount,ok :=dat["amount"].(float64)
if !ok {
fmt.Println("Error expanding parameter type,amount must be int")
}
if orgUtxo.CoupQuantity < int(_amount){
return shim.Error("Distribution failed, margin insufficient")
}
orgUtxo.CoupQuantity -= int(_amount)
dictUtxo := &Utxo{
Address: trans.To,
UserId: did,
Status: "1",
CoupType: orgUtxo.CoupType,
CoupQuantity: int(_amount),
CoupAmount: orgUtxo.CoupAmount,
CoupDiscount: orgUtxo.CoupDiscount,
FloorAmount: orgUtxo.FloorAmount,
PreAddress: []string{trans.From},
CoupId: orgUtxo.CoupId,
}
err = putStateUtxo(KEY+trans.From, orgUtxo, stub)
if err != nil {
return shim.Error("putStateUtxo error " + err.Error())
}
err = putStateUtxo(KEY+trans.To, dictUtxo, stub)
if err != nil {
return shim.Error("putStateUtxo error" + err.Error())
}
return shim.Success([]byte(stub.GetTxID()))
}
//用户领取卡券: 一个用户只能领取一张
// 入参:utxo地址、渠道utxo地址、渠道交易签名、渠道公钥
func userApplyCouponApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans, message,_, err := messageToTrans(ApplyCoupon, args, stub)
if err != nil {
return shim.Error(err.Error())
}
//解析用户信息
var user UserInfo
expand, ok := trans.Value.(string) //判断类型
if !ok {
return shim.Error("Error expanding parameter type,must be string")
}
err = json.Unmarshal([]byte(expand), &user)
if err != nil {
return shim.Error("Parameter error" + err.Error())
}
//TODO 用户领取规则过滤
//渠道UTXO
dictUtxo, err := getStateUtxo(KEY+trans.From, stub)
if err != nil {
return shim.Error(err.Error())
}
boo, err := checkKey(KEY+trans.To, stub)
if err != nil {
return shim.Error(err.Error())
}
if boo {
return shim.Error("Coupon apply failed, utxo address already exists")
}
if dictUtxo.Status != "1" {
return shim.Error("Card coupon status is abnormal and cannot be apply")
}
if dictUtxo.UserId != message.UserId {
return shim.Error("UserId alignment error")
}
if dictUtxo.CoupQuantity < 1 {
return shim.Error("Drawing failure, insufficient margin")
}
dictUtxo.CoupQuantity -= 1
userUtxo := &Utxo{
Address: trans.To,
PublicKey: trans.ToPub,
UserId: user.Uid,
Status: "2",
CoupType: dictUtxo.CoupType,
CoupQuantity: 1,
CoupAmount: dictUtxo.CoupAmount,
CoupDiscount: dictUtxo.CoupDiscount,
FloorAmount: dictUtxo.FloorAmount,
PreAddress: []string{dictUtxo.Address},
CoupId: dictUtxo.CoupId,
}
err = putStateUtxo(KEY+trans.To, userUtxo, stub)
if err != nil {
return shim.Error(err.Error())
}
err = putStateUtxo(KEY+trans.From, dictUtxo, stub)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte(stub.GetTxID()))
}
//使用卡券:
// 入参:utxo地址、商户utxo地址、订单信息签名、商户证书、商户交易签名
func useCouponApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans, message,_, err := messageToTrans(UseCoupon, args, stub)
if err != nil {
return shim.Error(err.Error())
}
utxo, err := getStateUtxo(KEY+trans.From, stub)
if err != nil {
return shim.Error(err.Error())
}
if utxo.Status != "2" {
return shim.Error("Card coupon status is abnormal and cannot be used")
}
//TODO 解析订单信息,校验券使用条件是否满足.待定。
isSupport,err := isSupportMerchants(utxo.CoupId,message.UserId,stub)
if err != nil{
return shim.Error(err.Error())
}
if !isSupport {
shim.Error(fmt.Sprintf("coupon %s unsupport merchant %s use",utxo.CoupId,message.UserId))
}
expand, ok := trans.Value.(string) //判断类型
if !ok {
return shim.Error("Error expanding parameter type,must be string")
}
var dat map[string]interface{}
err =json.Unmarshal([]byte(expand), &dat)
if err != nil{
fmt.Println(err)
}
privHex, ok := dat["privHex"].(string)
if !ok {
return shim.Error("Error privHex parameter type,must be string")
}
_,pubKey,err := ParsePrivateKey(privHex)
pubHex := hex.EncodeToString(pubKey)
if utxo.PublicKey != pubHex {
return shim.Error("coupons verify error")
}
utxo.Status = "3"
var mertNewUtxo Utxo
mertByteUtxo, _ := stub.GetState(KEY+trans.To)
//判断是否存在。存在修改,不存在初始化一条
if mertByteUtxo == nil {
mertNewUtxo = Utxo{
Address: trans.To,
UserId: message.UserId ,
Status: "4",
CoupType: utxo.CoupType,
CoupQuantity: utxo.CoupQuantity,
CoupAmount: utxo.CoupAmount,
CoupDiscount: utxo.CoupDiscount,
FloorAmount: utxo.FloorAmount,
PreAddress: []string{trans.From},
CoupId: utxo.CoupId,
}
}else {
_ =json.Unmarshal(mertByteUtxo,&mertNewUtxo)
mertNewUtxo.CoupQuantity += 1
mertNewUtxo.PreAddress = append(mertNewUtxo.PreAddress,trans.From)
}
err = putStateUtxo(KEY+trans.From, utxo, stub)
if err != nil {
return shim.Error(err.Error())
}
err = putStateUtxo(KEY+trans.To, &mertNewUtxo, stub)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte(stub.GetTxID()))
}
//修改商户utxo===清分。券未被领取、领取了未使用。
//入参:商户utxo地址、公钥、二维码utxo地址(数组)
func updateMertUtxoApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
// 解析请求数据
trans, _, _,err := messageToTrans(UseCoupon, args, stub)
if err != nil {
return shim.Error(err.Error())
}
expand, ok := trans.Value.(string) //判断类型
if !ok {
return shim.Error("Error expanding parameter type,must be string")
}
var dat map[string]interface{}
err =json.Unmarshal([]byte(expand),&dat)
if err != nil {
return shim.Error("Unmarshal error" + err.Error())
}
str,ok :=dat["uAddress"].(string)
if !ok {
return shim.Error("Error expanding parameter type,uAddress must be string")
}
//mid,ok :=dat["mid"].(string)
//if !ok {
// return shim.Error("Error expanding parameter type,mid must be string")
//}
utxo,err :=getStateUtxo(trans.From,stub)
if err != nil {
return shim.Error(err.Error())
}
if utxo.PublicKey != trans.ToPub {
return shim.Error("")
}
arr :=strings.Split(str,"=")
for _,value1 := range arr{
for b,value2 := range utxo.PreAddress{
if value1 == value2{
fmt.Println(b)
}
}
}
return shim.Success(nil)
}
/*
检查商户是否支持券使用
*/
func isSupportMerchants(couponId,merId string ,stub shim.ChaincodeStubInterface)(support bool,err error){
coupons ,err := getStateCoupons(KEY+couponId,stub)
if err!=nil{
return
}
for _,id:= range coupons.UseMerchats{
if merId == id{
support = true
return
}
}
return
}
\ No newline at end of file
package main
import (
"strings"
"fmt"
"encoding/json"
"github.com/hyperledger/fabric/core/chaincode/shim"
)
func splitPath(key string) []string {
key = strings.Trim(key, "/ ")
if key == "" {
return []string{}
}
return strings.Split(key, "/")
}
//解析前端数据 证书验证 和 签名验证
func messageToTrans(operation TxType,args []string,stub shim.ChaincodeStubInterface) (*Trans,*Message, string ,error) {
if len(args) != 3 {
return nil,nil, "",fmt.Errorf("put data operation expected more than 3 parameters! ")
}
message := &Message{
UserId: args[0],
Data: args[1],
Sign: args[2],
}
if message.UserId == "" || message.Sign == "" || message.Data == "" {
return nil,nil,"" ,fmt.Errorf("Parameter exception, cannot be null!")
}
//验证证书和签名
pubKey ,err := CheckCertSignature(message,operation,stub)
if err != nil{
return nil,nil,"",err
}
fmt.Println("1",message.Data)
var trans Trans
err = json.Unmarshal([]byte(message.Data), &trans)
if err != nil {
return nil,nil,"", fmt.Errorf("参数解析失败"+err.Error())
}
return &trans,message,pubKey , nil
}
//package main
package sm_crypto
import (
"crypto/elliptic"
"encoding/hex"
"errors"
"fmt"
"github.com/TMChain/go-TMChain/common"
"github.com/TMChain/go-TMChain/common/math"
"github.com/TMChain/go-TMChain/crypto/crypto_interface"
"github.com/TMChain/go-TMChain/crypto/sm_crypto/sm2"
"github.com/TMChain/go-TMChain/crypto/sm_crypto/sm3"
"github.com/TMChain/go-TMChain/rlp"
"io"
"io/ioutil"
"math/big"
"os"
"C"
"github.com/TMChain/go-TMChain/common/hexutil"
)
func main() {
}
var errInvalidSm2Pubkey = errors.New("invalid sm2 public key")
//export C_Hash256
func C_Hash256(dataC *C.char) *C.char {
data := C.GoString(dataC)
s := sm3.New()
s.Write(common.FromHex(data))
return C.CString(hexutil.Encode(s.Sum(nil)))
}
//export C_Hash256Bysha3
func C_Hash256Bysha3(dataC *C.char) *C.char {
//data := C.GoString(dataC)
////s := sha3.New256()
//s := sha3.NewLegacyKeccak256()
//s.Write(common.FromHex(data))
//
//return C.CString(hexutil.Encode(s.Sum(nil)))
return nil
}
//export C_Sign
func C_Sign(hashC *C.char, prvC *C.char) (*C.char) {
hash := C.GoString(hashC)
prv := C.GoString(prvC)
priv, err := toPriKey_c(common.FromHex(prv))
if err != nil {
return C.CString("")
}
if len(common.FromHex(hash)) != 32 {
return C.CString("")
}
sigRet, err := sm2.SM2Sign(&sm2.PrivateKey{
PublicKey: sm2.PublicKey{Curve: priv.Curve, X: priv.X, Y: priv.Y},
D: priv.D,
}, common.FromHex(hash))
if err != nil {
return C.CString("")
}
return C.CString(hexutil.Encode(sigRet))
}
//export C_GenerateKey
func C_GenerateKey() (*C.char) {
eprk, err := sm2.GenerateKey()
if err != nil {
return C.CString("")
}
priv := &icrypto.PrivateKey{
PublicKey: icrypto.PublicKey{
Curve: eprk.Curve,
X: eprk.X,
Y: eprk.Y,
},
D: eprk.D,
}
return C.CString(fromPriKey_c(priv))
}
//export C_FromPrv
func C_FromPrv(prvC *C.char)(*C.char) {
prv := C.GoString(prvC)
priv, err := toPriKey_c(common.FromHex(prv))
if err != nil {
return C.CString("")
}
smC := new(SmCrypto)
pubByte := smC.FromPub(&priv.PublicKey)
return C.CString(hexutil.Encode(pubByte))
}
//export C_VerifySignature
func C_VerifySignature(pubkeyC, hashC, signatureC *C.char) bool {
hash := C.GoString(hashC)
pubkey := C.GoString(pubkeyC)
signature := C.GoString(signatureC)
pub, err := unmarshalPubkey_c(common.FromHex(pubkey))
if err != nil {
return false
}
if sm2.VerifySign(&sm2.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}, common.FromHex(hash), common.FromHex(signature)) {
return true
}
return false
}
// FromECDSA exports a private key into a binary dump.
func fromSm2_c(priv *icrypto.PrivateKey) []byte {
if priv == nil {
return nil
}
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
}
func fromPriKey_c(priv *icrypto.PrivateKey) string {
return common.ToHex(fromSm2_c(priv))
}
func toPriKey_c(d []byte) (*icrypto.PrivateKey, error) {
return toSm2_c(d)
}
func toSm2_c(d []byte) (*icrypto.PrivateKey, error) {
return toSm2(d, true)
}
func unmarshalPubkey_c(pub []byte) (*icrypto.PublicKey, error) {
x, y := elliptic.Unmarshal(sm2.P256Sm2(), pub)
if x == nil {
return nil, errInvalidSm2Pubkey
}
return &icrypto.PublicKey{Curve: sm2.P256Sm2(), X: x, Y: y}, nil
}
//sm2加密抽象
type SmCrypto struct {
}
// Keccak256 calculates and returns the Keccak256 hash of the input data.
func (e *SmCrypto) X256(data ...[]byte) []byte {
s := sm3.New()
for _, b := range data {
s.Write(b)
}
return s.Sum(nil)
}
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
// converting it to an internal Hash data structure.
func (e *SmCrypto) X256Hash(data ...[]byte) (h common.Hash) {
s := sm3.New()
for _, b := range data {
s.Write(b)
}
s.Sum(h[:0])
return h
}
// Keccak512 calculates and returns the Keccak512 hash of the input data.
func (e *SmCrypto) X512(data ...[]byte) []byte {
//d := sha3.NewLegacyKeccak512()
//for _, b := range data {
// d.Write(b)
//}
//return d.Sum(nil)
return nil
}
// CreateAddress creates an ethereum address given the bytes and the nonce
func (e *SmCrypto) CreateAddress(b common.Address, nonce uint64) common.Address {
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
return common.BytesToAddress(e.X256(data)[12:])
}
// CreateAddress2 creates an ethereum address given the address bytes, initial
// contract code hash and a salt.
func (e *SmCrypto) CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address {
return common.BytesToAddress(e.X256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:])
}
func (e *SmCrypto) ToPriKey(d []byte) (*icrypto.PrivateKey, error) {
return e.ToSm2(d)
}
// ToECDSA creates a private key with the given D value.
func (e *SmCrypto) ToSm2(d []byte) (*icrypto.PrivateKey, error) {
return toSm2(d, true)
}
func (e *SmCrypto) ToPriKeyUnsafe(d []byte) *icrypto.PrivateKey {
return e.ToSm2Unsafe(d)
}
// ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost
// never be used unless you are sure the input is valid and want to avoid hitting
// errors due to bad origin encoding (0 prefixes cut off).
func (e *SmCrypto) ToSm2Unsafe(d []byte) *icrypto.PrivateKey {
priv, _ := toSm2(d, false)
return priv
}
// toECDSA creates a private key with the given D value. The strict parameter
// controls whether the key's length should be enforced at the curve size or
// it can also accept legacy encodings (0 prefixes).
func toSm2(d []byte, strict bool) (*icrypto.PrivateKey, error) {
priv := new(sm2.PrivateKey)
priv.PublicKey.Curve = sm2.P256Sm2()
if strict && 8*len(d) != priv.Params().BitSize {
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
}
priv.D = new(big.Int).SetBytes(d)
// The priv.D must < N
//if priv.D.Cmp(secp256k1N) >= 0 {
// return nil, fmt.Errorf("invalid private key, >=N")
//}
// The priv.D must not be zero or negative.
if priv.D.Sign() <= 0 {
return nil, fmt.Errorf("invalid private key, zero or negative")
}
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
if priv.PublicKey.X == nil {
return nil, errors.New("invalid private key")
}
//需要赋值转换为接口定义的私钥形式
return &icrypto.PrivateKey{
D: priv.D,
PublicKey: icrypto.PublicKey{
Curve: priv.Curve,
X: priv.X,
Y: priv.Y,
},
}, nil
}
func (e *SmCrypto) FromPriKey(priv *icrypto.PrivateKey) []byte {
return e.FromSm2(priv)
}
// FromECDSA exports a private key into a binary dump.
func (e *SmCrypto) FromSm2(priv *icrypto.PrivateKey) []byte {
if priv == nil {
return nil
}
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
}
// UnmarshalPubkey converts bytes to a secp256k1 public key.
func (e *SmCrypto) UnmarshalPubkey(pub []byte) (*icrypto.PublicKey, error) {
x, y := elliptic.Unmarshal(sm2.P256Sm2(), pub)
if x == nil {
return nil, errInvalidSm2Pubkey
}
return &icrypto.PublicKey{Curve: sm2.P256Sm2(), X: x, Y: y}, nil
}
func (e *SmCrypto) FromPub(pub *icrypto.PublicKey) []byte {
return e.FromSM2Pub(pub)
}
func (e *SmCrypto) FromSM2Pub(pub *icrypto.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(sm2.P256Sm2(), pub.X, pub.Y)
}
func (e *SmCrypto) HexToPriKey(hexkey string) (*icrypto.PrivateKey, error) {
return e.HexToSm2(hexkey)
}
// HexToECDSA parses a secp256k1 private key.
func (e *SmCrypto) HexToSm2(hexkey string) (*icrypto.PrivateKey, error) {
b, err := hex.DecodeString(hexkey)
if err != nil {
return nil, errors.New("invalid hex string")
}
return e.ToSm2(b)
}
func (e *SmCrypto) LoadPriKey(file string) (*icrypto.PrivateKey, error) {
return e.LoadSm2(file)
}
// LoadECDSA loads a secp256k1 private key from the given file.
func (e *SmCrypto) LoadSm2(file string) (*icrypto.PrivateKey, error) {
buf := make([]byte, 64)
fd, err := os.Open(file)
if err != nil {
return nil, err
}
defer fd.Close()
if _, err := io.ReadFull(fd, buf); err != nil {
return nil, err
}
key, err := hex.DecodeString(string(buf))
if err != nil {
return nil, err
}
return e.ToSm2(key)
}
func (e *SmCrypto) SavePriKey(file string, key *icrypto.PrivateKey) error {
return e.SaveSm2(file, key)
}
// SaveECDSA saves a secp256k1 private key to the given file with
// restrictive permissions. The key data is saved hex-encoded.
func (e *SmCrypto) SaveSm2(file string, key *icrypto.PrivateKey) error {
k := hex.EncodeToString(e.FromSm2(key))
return ioutil.WriteFile(file, []byte(k), 0600)
}
func (e *SmCrypto) GenerateKey() (*icrypto.PrivateKey, error) {
eprk, err := sm2.GenerateKey()
return &icrypto.PrivateKey{
PublicKey: icrypto.PublicKey{
Curve: eprk.Curve,
X: eprk.X,
Y: eprk.Y,
},
D: eprk.D,
}, err
}
func (e *SmCrypto) GenerateKey2(rand io.Reader) (*icrypto.PrivateKey, error) {
eprk, err := sm2.GenerateKey2(rand)
return &icrypto.PrivateKey{
PublicKey: icrypto.PublicKey{
Curve: eprk.Curve,
X: eprk.X,
Y: eprk.Y,
},
D: eprk.D,
}, err
}
// ValidateSignatureValues verifies whether the signature values are valid with
// the given chain rules. The v value is assumed to be either 0 or 1.
func (e *SmCrypto) ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
//if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 {
// return false
//}
// reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h
//if homestead && s.Cmp(secp256k1halfN) > 0 {
// return false
//}
// Frontier: allow s to be in full N range
//return r.Cmp(secp256k1N) < 0 && s.Cmp(secp256k1N) < 0 && (v == 0 || v == 1)
return true
}
func (e *SmCrypto) PubkeyToAddress(p *icrypto.PublicKey) common.Address {
pubBytes := e.FromSM2Pub(p)
return common.BytesToAddress(e.X256(pubBytes[1:])[12:])
}
func zeroBytes(bytes []byte) {
for i := range bytes {
bytes[i] = 0
}
}
// Ecrecover returns the uncompressed public key that created the given signature.
func (e *SmCrypto) Ecrecover(pub, hash, sig []byte) ([]byte, error) {
pk, err := e.UnmarshalPubkey(pub)
if err != nil {
return nil, errors.New("sm2 Ecrecover-UnmarshalPubkey err")
}
if sm2.VerifySign(&sm2.PublicKey{Curve: pk.Curve, X: pk.X, Y: pk.Y}, hash, sig) {
return pub, nil
}
return nil, errors.New("sm2 Ecrecover-VerifySign err")
}
// SigToPub returns the public key that created the given signature.
func (e *SmCrypto) SigToPub(pub, hash, sig []byte) (*icrypto.PublicKey, error) {
s, err := e.Ecrecover(pub, hash, sig)
if err != nil {
return nil, err
}
x, y := elliptic.Unmarshal(sm2.P256Sm2(), s)
return &icrypto.PublicKey{Curve: sm2.P256Sm2(), X: x, Y: y}, nil
}
// Sign calculates an ECDSA signature.
//
// This function is susceptible to chosen plaintext attacks that can leak
// information about the private key that is used for signing. Callers must
// be aware that the given hash cannot be chosen by an adversery. Common
// solution is to hash any input before calculating the signature.
//
// The produced signature is in the [R || S || V] format where V is 0 or 1.
func (e *SmCrypto) Sign(hash []byte, prv *icrypto.PrivateKey) (sig []byte, err error) {
if len(hash) != 32 {
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
}
return sm2.SM2Sign(&sm2.PrivateKey{
PublicKey: sm2.PublicKey{Curve: prv.Curve, X: prv.X, Y: prv.Y},
D: prv.D,
}, hash)
}
// VerifySignature checks that the given public key created signature over hash.
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
// The signature should have the 64 byte [R || S] format.
func (e *SmCrypto) VerifySignature(pubkey, hash, signature []byte) bool {
pub, err := e.UnmarshalPubkey(pubkey)
if err != nil {
return false
}
if sm2.VerifySign(&sm2.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}, hash, signature) {
return true
}
return false
}
// DecompressPubkey parses a public key in the 33-byte compressed format.
func (e *SmCrypto) DecompressPubkey(pubkey []byte) (*icrypto.PublicKey, error) {
pk := sm2.Decompress(pubkey)
return &icrypto.PublicKey{Curve: pk.Curve, X: pk.X, Y: pk.Y}, nil
}
// CompressPubkey encodes a public key to the 33-byte compressed format.
func (e *SmCrypto) CompressPubkey(pubkey *icrypto.PublicKey) []byte {
return sm2.Compress(&sm2.PublicKey{Curve: pubkey.Curve, X: pubkey.X, Y: pubkey.Y})
}
// S256 returns an instance of the secp256k1 curve.
func (e *SmCrypto) S256() elliptic.Curve {
return sm2.P256Sm2()
}
/* Created by "go tool cgo" - DO NOT EDIT. */
/* package command-line-arguments */
#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t below */
#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
#endif
/* Start of preamble from import "C" comments. */
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
#line 1 "cgo-gcc-export-header-prolog"
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
typedef _GoString_ GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C" {
#endif
extern char* C_Hash256(char* p0);
extern char* C_Hash256Bysha3(char* p0);
extern char* C_Sign(char* p0, char* p1);
extern char* C_GenerateKey();
extern char* C_FromPrv(char* p0);
extern GoUint8 C_VerifySignature(char* p0, char* p1, char* p2);
#ifdef __cplusplus
}
#endif
/*
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 (
"encoding/pem"
"errors"
"io/ioutil"
"os"
"runtime"
"sync"
)
// Possible certificate files; stop after finding one.
var certFiles = []string{
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
"/etc/ssl/ca-bundle.pem", // OpenSUSE
"/etc/pki/tls/cacert.pem", // OpenELEC
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
}
// CertPool is a set of certificates.
type CertPool struct {
bySubjectKeyId map[string][]int
byName map[string][]int
certs []*Certificate
}
// NewCertPool returns a new, empty CertPool.
func NewCertPool() *CertPool {
return &CertPool{
bySubjectKeyId: make(map[string][]int),
byName: make(map[string][]int),
}
}
// Possible directories with certificate files; stop after successfully
// reading at least one file from a directory.
var certDirectories = []string{
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
"/system/etc/security/cacerts", // Android
}
var (
once sync.Once
systemRoots *CertPool
systemRootsErr error
)
func systemRootsPool() *CertPool {
once.Do(initSystemRoots)
return systemRoots
}
func initSystemRoots() {
systemRoots, systemRootsErr = loadSystemRoots()
}
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
func loadSystemRoots() (*CertPool, error) {
roots := NewCertPool()
var firstErr error
for _, file := range certFiles {
data, err := ioutil.ReadFile(file)
if err == nil {
roots.AppendCertsFromPEM(data)
return roots, nil
}
if firstErr == nil && !os.IsNotExist(err) {
firstErr = err
}
}
for _, directory := range certDirectories {
fis, err := ioutil.ReadDir(directory)
if err != nil {
if firstErr == nil && !os.IsNotExist(err) {
firstErr = err
}
continue
}
rootsAdded := false
for _, fi := range fis {
data, err := ioutil.ReadFile(directory + "/" + fi.Name())
if err == nil && roots.AppendCertsFromPEM(data) {
rootsAdded = true
}
}
if rootsAdded {
return roots, nil
}
}
return nil, firstErr
}
// SystemCertPool returns a copy of the system cert pool.
//
// Any mutations to the returned pool are not written to disk and do
// not affect any other pool.
func SystemCertPool() (*CertPool, error) {
if runtime.GOOS == "windows" {
// Issue 16736, 18609:
return nil, errors.New("crypto/x509: system root pool is not available on Windows")
}
return loadSystemRoots()
}
// findVerifiedParents attempts to find certificates in s which have signed the
// given certificate. If any candidates were rejected then errCert will be set
// to one of them, arbitrarily, and err will contain the reason that it was
// rejected.
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
if s == nil {
return
}
var candidates []int
if len(cert.AuthorityKeyId) > 0 {
candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
}
if len(candidates) == 0 {
candidates = s.byName[string(cert.RawIssuer)]
}
for _, c := range candidates {
if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
parents = append(parents, c)
} else {
errCert = s.certs[c]
}
}
return
}
func (s *CertPool) contains(cert *Certificate) bool {
if s == nil {
return false
}
candidates := s.byName[string(cert.RawSubject)]
for _, c := range candidates {
if s.certs[c].Equal(cert) {
return true
}
}
return false
}
// AddCert adds a certificate to a pool.
func (s *CertPool) AddCert(cert *Certificate) {
if cert == nil {
panic("adding nil Certificate to CertPool")
}
// Check that the certificate isn't being added twice.
if s.contains(cert) {
return
}
n := len(s.certs)
s.certs = append(s.certs, cert)
if len(cert.SubjectKeyId) > 0 {
keyId := string(cert.SubjectKeyId)
s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
}
name := string(cert.RawSubject)
s.byName[name] = append(s.byName[name], n)
}
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
// It appends any certificates found to s and reports whether any certificates
// were successfully parsed.
//
// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
// of root CAs in a format suitable for this function.
func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
for len(pemCerts) > 0 {
var block *pem.Block
block, pemCerts = pem.Decode(pemCerts)
if block == nil {
break
}
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
continue
}
cert, err := ParseCertificate(block.Bytes)
if err != nil {
continue
}
s.AddCert(cert)
ok = true
}
return
}
// Subjects returns a list of the DER-encoded subjects of
// all of the certificates in the pool.
func (s *CertPool) Subjects() [][]byte {
res := make([][]byte, len(s.certs))
for i, c := range s.certs {
res[i] = c.RawSubject
}
return res
}
/*
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/elliptic"
"math/big"
"sync"
)
/** 学习标准库p256的优化方法实现sm2的快速版本
* 标准库的p256的代码实现有些晦涩难懂,当然sm2的同样如此,有兴趣的大家可以研究研究,最后神兽压阵。。。
*
* ━━━━━━animal━━━━━━
*    ┏┓   ┏┓
*   ┏┛┻━━━┛┻┓
*   ┃       ┃
*   ┃   ━   ┃
*   ┃ ┳┛ ┗┳ ┃
*   ┃       ┃
*   ┃   ┻   ┃
*   ┃       ┃
*   ┗━┓   ┏━┛
*    ┃   ┃
*    ┃   ┃
*    ┃   ┗━━━┓
*  ┃     ┣┓
*   ┃     ┏┛
*    ┗┓┓┏━┳┓┏┛
*    ┃┫┫ ┃┫┫
*    ┗┻┛ ┗┻┛
*
* ━━━━━Kawaii ━━━━━━
*/
type sm2P256Curve struct {
RInverse *big.Int
*elliptic.CurveParams
a, b, gx, gy sm2P256FieldElement
}
var initonce sync.Once
var sm2P256 sm2P256Curve
type sm2P256FieldElement [9]uint32
type sm2P256LargeFieldElement [17]uint64
const (
bottom28Bits = 0xFFFFFFF
bottom29Bits = 0x1FFFFFFF
)
func initP256Sm2() {
sm2P256.CurveParams = &elliptic.CurveParams{Name: "SM2-P-256"} // sm2
A, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16)
//SM2椭 椭 圆 曲 线 公 钥 密 码 算 法 推 荐 曲 线 参 数
sm2P256.P, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
sm2P256.N, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
sm2P256.B, _ = new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
sm2P256.Gx, _ = new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
sm2P256.Gy, _ = new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
sm2P256.RInverse, _ = new(big.Int).SetString("7ffffffd80000002fffffffe000000017ffffffe800000037ffffffc80000002", 16)
sm2P256.BitSize = 256
sm2P256FromBig(&sm2P256.a, A)
sm2P256FromBig(&sm2P256.gx, sm2P256.Gx)
sm2P256FromBig(&sm2P256.gy, sm2P256.Gy)
sm2P256FromBig(&sm2P256.b, sm2P256.B)
}
func P256Sm2() elliptic.Curve {
initonce.Do(initP256Sm2)
return sm2P256
}
func (curve sm2P256Curve) Params() *elliptic.CurveParams {
return sm2P256.CurveParams
}
// y^2 = x^3 + ax + b
func (curve sm2P256Curve) IsOnCurve(X, Y *big.Int) bool {
var a, x, y, y2, x3 sm2P256FieldElement
sm2P256FromBig(&x, X)
sm2P256FromBig(&y, Y)
sm2P256Square(&x3, &x) // x3 = x ^ 2
sm2P256Mul(&x3, &x3, &x) // x3 = x ^ 2 * x
sm2P256Mul(&a, &curve.a, &x) // a = a * x
sm2P256Add(&x3, &x3, &a)
sm2P256Add(&x3, &x3, &curve.b)
sm2P256Square(&y2, &y) // y2 = y ^ 2
return sm2P256ToBig(&x3).Cmp(sm2P256ToBig(&y2)) == 0
}
func zForAffine(x, y *big.Int) *big.Int {
z := new(big.Int)
if x.Sign() != 0 || y.Sign() != 0 {
z.SetInt64(1)
}
return z
}
func (curve sm2P256Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
var X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3 sm2P256FieldElement
z1 := zForAffine(x1, y1)
z2 := zForAffine(x2, y2)
sm2P256FromBig(&X1, x1)
sm2P256FromBig(&Y1, y1)
sm2P256FromBig(&Z1, z1)
sm2P256FromBig(&X2, x2)
sm2P256FromBig(&Y2, y2)
sm2P256FromBig(&Z2, z2)
sm2P256PointAdd(&X1, &Y1, &Z1, &X2, &Y2, &Z2, &X3, &Y3, &Z3)
return sm2P256ToAffine(&X3, &Y3, &Z3)
}
func (curve sm2P256Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
var X1, Y1, Z1 sm2P256FieldElement
z1 := zForAffine(x1, y1)
sm2P256FromBig(&X1, x1)
sm2P256FromBig(&Y1, y1)
sm2P256FromBig(&Z1, z1)
sm2P256PointDouble(&X1, &Y1, &Z1, &X1, &Y1, &Z1)
return sm2P256ToAffine(&X1, &Y1, &Z1)
}
func (curve sm2P256Curve) ScalarMult(x1, y1 *big.Int, k []byte) (*big.Int, *big.Int) {
var scalarReversed [32]byte
var X, Y, Z, X1, Y1 sm2P256FieldElement
sm2P256FromBig(&X1, x1)
sm2P256FromBig(&Y1, y1)
sm2P256GetScalar(&scalarReversed, k)
sm2P256ScalarMult(&X, &Y, &Z, &X1, &Y1, &scalarReversed)
return sm2P256ToAffine(&X, &Y, &Z)
}
func (curve sm2P256Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
var scalarReversed [32]byte
var X, Y, Z sm2P256FieldElement
sm2P256GetScalar(&scalarReversed, k)
sm2P256ScalarBaseMult(&X, &Y, &Z, &scalarReversed)
return sm2P256ToAffine(&X, &Y, &Z)
}
var sm2P256Precomputed = [9 * 2 * 15 * 2]uint32{
0x830053d, 0x328990f, 0x6c04fe1, 0xc0f72e5, 0x1e19f3c, 0x666b093, 0x175a87b, 0xec38276, 0x222cf4b,
0x185a1bba, 0x354e593, 0x1295fac1, 0xf2bc469, 0x47c60fa, 0xc19b8a9, 0xf63533e, 0x903ae6b, 0xc79acba,
0x15b061a4, 0x33e020b, 0xdffb34b, 0xfcf2c8, 0x16582e08, 0x262f203, 0xfb34381, 0xa55452, 0x604f0ff,
0x41f1f90, 0xd64ced2, 0xee377bf, 0x75f05f0, 0x189467ae, 0xe2244e, 0x1e7700e8, 0x3fbc464, 0x9612d2e,
0x1341b3b8, 0xee84e23, 0x1edfa5b4, 0x14e6030, 0x19e87be9, 0x92f533c, 0x1665d96c, 0x226653e, 0xa238d3e,
0xf5c62c, 0x95bb7a, 0x1f0e5a41, 0x28789c3, 0x1f251d23, 0x8726609, 0xe918910, 0x8096848, 0xf63d028,
0x152296a1, 0x9f561a8, 0x14d376fb, 0x898788a, 0x61a95fb, 0xa59466d, 0x159a003d, 0x1ad1698, 0x93cca08,
0x1b314662, 0x706e006, 0x11ce1e30, 0x97b710, 0x172fbc0d, 0x8f50158, 0x11c7ffe7, 0xd182cce, 0xc6ad9e8,
0x12ea31b2, 0xc4e4f38, 0x175b0d96, 0xec06337, 0x75a9c12, 0xb001fdf, 0x93e82f5, 0x34607de, 0xb8035ed,
0x17f97924, 0x75cf9e6, 0xdceaedd, 0x2529924, 0x1a10c5ff, 0xb1a54dc, 0x19464d8, 0x2d1997, 0xde6a110,
0x1e276ee5, 0x95c510c, 0x1aca7c7a, 0xfe48aca, 0x121ad4d9, 0xe4132c6, 0x8239b9d, 0x40ea9cd, 0x816c7b,
0x632d7a4, 0xa679813, 0x5911fcf, 0x82b0f7c, 0x57b0ad5, 0xbef65, 0xd541365, 0x7f9921f, 0xc62e7a,
0x3f4b32d, 0x58e50e1, 0x6427aed, 0xdcdda67, 0xe8c2d3e, 0x6aa54a4, 0x18df4c35, 0x49a6a8e, 0x3cd3d0c,
0xd7adf2, 0xcbca97, 0x1bda5f2d, 0x3258579, 0x606b1e6, 0x6fc1b5b, 0x1ac27317, 0x503ca16, 0xa677435,
0x57bc73, 0x3992a42, 0xbab987b, 0xfab25eb, 0x128912a4, 0x90a1dc4, 0x1402d591, 0x9ffbcfc, 0xaa48856,
0x7a7c2dc, 0xcefd08a, 0x1b29bda6, 0xa785641, 0x16462d8c, 0x76241b7, 0x79b6c3b, 0x204ae18, 0xf41212b,
0x1f567a4d, 0xd6ce6db, 0xedf1784, 0x111df34, 0x85d7955, 0x55fc189, 0x1b7ae265, 0xf9281ac, 0xded7740,
0xf19468b, 0x83763bb, 0x8ff7234, 0x3da7df8, 0x9590ac3, 0xdc96f2a, 0x16e44896, 0x7931009, 0x99d5acc,
0x10f7b842, 0xaef5e84, 0xc0310d7, 0xdebac2c, 0x2a7b137, 0x4342344, 0x19633649, 0x3a10624, 0x4b4cb56,
0x1d809c59, 0xac007f, 0x1f0f4bcd, 0xa1ab06e, 0xc5042cf, 0x82c0c77, 0x76c7563, 0x22c30f3, 0x3bf1568,
0x7a895be, 0xfcca554, 0x12e90e4c, 0x7b4ab5f, 0x13aeb76b, 0x5887e2c, 0x1d7fe1e3, 0x908c8e3, 0x95800ee,
0xb36bd54, 0xf08905d, 0x4e73ae8, 0xf5a7e48, 0xa67cb0, 0x50e1067, 0x1b944a0a, 0xf29c83a, 0xb23cfb9,
0xbe1db1, 0x54de6e8, 0xd4707f2, 0x8ebcc2d, 0x2c77056, 0x1568ce4, 0x15fcc849, 0x4069712, 0xe2ed85f,
0x2c5ff09, 0x42a6929, 0x628e7ea, 0xbd5b355, 0xaf0bd79, 0xaa03699, 0xdb99816, 0x4379cef, 0x81d57b,
0x11237f01, 0xe2a820b, 0xfd53b95, 0x6beb5ee, 0x1aeb790c, 0xe470d53, 0x2c2cfee, 0x1c1d8d8, 0xa520fc4,
0x1518e034, 0xa584dd4, 0x29e572b, 0xd4594fc, 0x141a8f6f, 0x8dfccf3, 0x5d20ba3, 0x2eb60c3, 0x9f16eb0,
0x11cec356, 0xf039f84, 0x1b0990c1, 0xc91e526, 0x10b65bae, 0xf0616e8, 0x173fa3ff, 0xec8ccf9, 0xbe32790,
0x11da3e79, 0xe2f35c7, 0x908875c, 0xdacf7bd, 0x538c165, 0x8d1487f, 0x7c31aed, 0x21af228, 0x7e1689d,
0xdfc23ca, 0x24f15dc, 0x25ef3c4, 0x35248cd, 0x99a0f43, 0xa4b6ecc, 0xd066b3, 0x2481152, 0x37a7688,
0x15a444b6, 0xb62300c, 0x4b841b, 0xa655e79, 0xd53226d, 0xbeb348a, 0x127f3c2, 0xb989247, 0x71a277d,
0x19e9dfcb, 0xb8f92d0, 0xe2d226c, 0x390a8b0, 0x183cc462, 0x7bd8167, 0x1f32a552, 0x5e02db4, 0xa146ee9,
0x1a003957, 0x1c95f61, 0x1eeec155, 0x26f811f, 0xf9596ba, 0x3082bfb, 0x96df083, 0x3e3a289, 0x7e2d8be,
0x157a63e0, 0x99b8941, 0x1da7d345, 0xcc6cd0, 0x10beed9a, 0x48e83c0, 0x13aa2e25, 0x7cad710, 0x4029988,
0x13dfa9dd, 0xb94f884, 0x1f4adfef, 0xb88543, 0x16f5f8dc, 0xa6a67f4, 0x14e274e2, 0x5e56cf4, 0x2f24ef,
0x1e9ef967, 0xfe09bad, 0xfe079b3, 0xcc0ae9e, 0xb3edf6d, 0x3e961bc, 0x130d7831, 0x31043d6, 0xba986f9,
0x1d28055, 0x65240ca, 0x4971fa3, 0x81b17f8, 0x11ec34a5, 0x8366ddc, 0x1471809, 0xfa5f1c6, 0xc911e15,
0x8849491, 0xcf4c2e2, 0x14471b91, 0x39f75be, 0x445c21e, 0xf1585e9, 0x72cc11f, 0x4c79f0c, 0xe5522e1,
0x1874c1ee, 0x4444211, 0x7914884, 0x3d1b133, 0x25ba3c, 0x4194f65, 0x1c0457ef, 0xac4899d, 0xe1fa66c,
0x130a7918, 0x9b8d312, 0x4b1c5c8, 0x61ccac3, 0x18c8aa6f, 0xe93cb0a, 0xdccb12c, 0xde10825, 0x969737d,
0xf58c0c3, 0x7cee6a9, 0xc2c329a, 0xc7f9ed9, 0x107b3981, 0x696a40e, 0x152847ff, 0x4d88754, 0xb141f47,
0x5a16ffe, 0x3a7870a, 0x18667659, 0x3b72b03, 0xb1c9435, 0x9285394, 0xa00005a, 0x37506c, 0x2edc0bb,
0x19afe392, 0xeb39cac, 0x177ef286, 0xdf87197, 0x19f844ed, 0x31fe8, 0x15f9bfd, 0x80dbec, 0x342e96e,
0x497aced, 0xe88e909, 0x1f5fa9ba, 0x530a6ee, 0x1ef4e3f1, 0x69ffd12, 0x583006d, 0x2ecc9b1, 0x362db70,
0x18c7bdc5, 0xf4bb3c5, 0x1c90b957, 0xf067c09, 0x9768f2b, 0xf73566a, 0x1939a900, 0x198c38a, 0x202a2a1,
0x4bbf5a6, 0x4e265bc, 0x1f44b6e7, 0x185ca49, 0xa39e81b, 0x24aff5b, 0x4acc9c2, 0x638bdd3, 0xb65b2a8,
0x6def8be, 0xb94537a, 0x10b81dee, 0xe00ec55, 0x2f2cdf7, 0xc20622d, 0x2d20f36, 0xe03c8c9, 0x898ea76,
0x8e3921b, 0x8905bff, 0x1e94b6c8, 0xee7ad86, 0x154797f2, 0xa620863, 0x3fbd0d9, 0x1f3caab, 0x30c24bd,
0x19d3892f, 0x59c17a2, 0x1ab4b0ae, 0xf8714ee, 0x90c4098, 0xa9c800d, 0x1910236b, 0xea808d3, 0x9ae2f31,
0x1a15ad64, 0xa48c8d1, 0x184635a4, 0xb725ef1, 0x11921dcc, 0x3f866df, 0x16c27568, 0xbdf580a, 0xb08f55c,
0x186ee1c, 0xb1627fa, 0x34e82f6, 0x933837e, 0xf311be5, 0xfedb03b, 0x167f72cd, 0xa5469c0, 0x9c82531,
0xb92a24b, 0x14fdc8b, 0x141980d1, 0xbdc3a49, 0x7e02bb1, 0xaf4e6dd, 0x106d99e1, 0xd4616fc, 0x93c2717,
0x1c0a0507, 0xc6d5fed, 0x9a03d8b, 0xa1d22b0, 0x127853e3, 0xc4ac6b8, 0x1a048cf7, 0x9afb72c, 0x65d485d,
0x72d5998, 0xe9fa744, 0xe49e82c, 0x253cf80, 0x5f777ce, 0xa3799a5, 0x17270cbb, 0xc1d1ef0, 0xdf74977,
0x114cb859, 0xfa8e037, 0xb8f3fe5, 0xc734cc6, 0x70d3d61, 0xeadac62, 0x12093dd0, 0x9add67d, 0x87200d6,
0x175bcbb, 0xb29b49f, 0x1806b79c, 0x12fb61f, 0x170b3a10, 0x3aaf1cf, 0xa224085, 0x79d26af, 0x97759e2,
0x92e19f1, 0xb32714d, 0x1f00d9f1, 0xc728619, 0x9e6f627, 0xe745e24, 0x18ea4ace, 0xfc60a41, 0x125f5b2,
0xc3cf512, 0x39ed486, 0xf4d15fa, 0xf9167fd, 0x1c1f5dd5, 0xc21a53e, 0x1897930, 0x957a112, 0x21059a0,
0x1f9e3ddc, 0xa4dfced, 0x8427f6f, 0x726fbe7, 0x1ea658f8, 0x2fdcd4c, 0x17e9b66f, 0xb2e7c2e, 0x39923bf,
0x1bae104, 0x3973ce5, 0xc6f264c, 0x3511b84, 0x124195d7, 0x11996bd, 0x20be23d, 0xdc437c4, 0x4b4f16b,
0x11902a0, 0x6c29cc9, 0x1d5ffbe6, 0xdb0b4c7, 0x10144c14, 0x2f2b719, 0x301189, 0x2343336, 0xa0bf2ac,
}
func sm2P256GetScalar(b *[32]byte, a []byte) {
var scalarBytes []byte
n := new(big.Int).SetBytes(a)
if n.Cmp(sm2P256.N) >= 0 {
n.Mod(n, sm2P256.N)
scalarBytes = n.Bytes()
} else {
scalarBytes = a
}
for i, v := range scalarBytes {
b[len(scalarBytes)-(1+i)] = v
}
}
func sm2P256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *sm2P256FieldElement) {
var z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp sm2P256FieldElement
sm2P256Square(&z1z1, z1)
sm2P256Add(&tmp, z1, z1)
sm2P256Mul(&u2, x2, &z1z1)
sm2P256Mul(&z1z1z1, z1, &z1z1)
sm2P256Mul(&s2, y2, &z1z1z1)
sm2P256Sub(&h, &u2, x1)
sm2P256Add(&i, &h, &h)
sm2P256Square(&i, &i)
sm2P256Mul(&j, &h, &i)
sm2P256Sub(&r, &s2, y1)
sm2P256Add(&r, &r, &r)
sm2P256Mul(&v, x1, &i)
sm2P256Mul(zOut, &tmp, &h)
sm2P256Square(&rr, &r)
sm2P256Sub(xOut, &rr, &j)
sm2P256Sub(xOut, xOut, &v)
sm2P256Sub(xOut, xOut, &v)
sm2P256Sub(&tmp, &v, xOut)
sm2P256Mul(yOut, &tmp, &r)
sm2P256Mul(&tmp, y1, &j)
sm2P256Sub(yOut, yOut, &tmp)
sm2P256Sub(yOut, yOut, &tmp)
}
// sm2P256CopyConditional sets out=in if mask = 0xffffffff in constant time.
//
// On entry: mask is either 0 or 0xffffffff.
func sm2P256CopyConditional(out, in *sm2P256FieldElement, mask uint32) {
for i := 0; i < 9; i++ {
tmp := mask & (in[i] ^ out[i])
out[i] ^= tmp
}
}
// sm2P256SelectAffinePoint sets {out_x,out_y} to the index'th entry of table.
// On entry: index < 16, table[0] must be zero.
func sm2P256SelectAffinePoint(xOut, yOut *sm2P256FieldElement, table []uint32, index uint32) {
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := uint32(1); i < 16; i++ {
mask := i ^ index
mask |= mask >> 2
mask |= mask >> 1
mask &= 1
mask--
for j := range xOut {
xOut[j] |= table[0] & mask
table = table[1:]
}
for j := range yOut {
yOut[j] |= table[0] & mask
table = table[1:]
}
}
}
// sm2P256SelectJacobianPoint sets {out_x,out_y,out_z} to the index'th entry of
// table.
// On entry: index < 16, table[0] must be zero.
func sm2P256SelectJacobianPoint(xOut, yOut, zOut *sm2P256FieldElement, table *[16][3]sm2P256FieldElement, index uint32) {
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := range zOut {
zOut[i] = 0
}
// The implicit value at index 0 is all zero. We don't need to perform that
// iteration of the loop because we already set out_* to zero.
for i := uint32(1); i < 16; i++ {
mask := i ^ index
mask |= mask >> 2
mask |= mask >> 1
mask &= 1
mask--
for j := range xOut {
xOut[j] |= table[i][0][j] & mask
}
for j := range yOut {
yOut[j] |= table[i][1][j] & mask
}
for j := range zOut {
zOut[j] |= table[i][2][j] & mask
}
}
}
// sm2P256GetBit returns the bit'th bit of scalar.
func sm2P256GetBit(scalar *[32]uint8, bit uint) uint32 {
return uint32(((scalar[bit>>3]) >> (bit & 7)) & 1)
}
// sm2P256ScalarBaseMult sets {xOut,yOut,zOut} = scalar*G where scalar is a
// little-endian number. Note that the value of scalar must be less than the
// order of the group.
func sm2P256ScalarBaseMult(xOut, yOut, zOut *sm2P256FieldElement, scalar *[32]uint8) {
nIsInfinityMask := ^uint32(0)
var px, py, tx, ty, tz sm2P256FieldElement
var pIsNoninfiniteMask, mask, tableOffset uint32
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := range zOut {
zOut[i] = 0
}
// The loop adds bits at positions 0, 64, 128 and 192, followed by
// positions 32,96,160 and 224 and does this 32 times.
for i := uint(0); i < 32; i++ {
if i != 0 {
sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
}
tableOffset = 0
for j := uint(0); j <= 32; j += 32 {
bit0 := sm2P256GetBit(scalar, 31-i+j)
bit1 := sm2P256GetBit(scalar, 95-i+j)
bit2 := sm2P256GetBit(scalar, 159-i+j)
bit3 := sm2P256GetBit(scalar, 223-i+j)
index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
sm2P256SelectAffinePoint(&px, &py, sm2P256Precomputed[tableOffset:], index)
tableOffset += 30 * 9
// Since scalar is less than the order of the group, we know that
// {xOut,yOut,zOut} != {px,py,1}, unless both are zero, which we handle
// below.
sm2P256PointAddMixed(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py)
// The result of pointAddMixed is incorrect if {xOut,yOut,zOut} is zero
// (a.k.a. the point at infinity). We handle that situation by
// copying the point from the table.
sm2P256CopyConditional(xOut, &px, nIsInfinityMask)
sm2P256CopyConditional(yOut, &py, nIsInfinityMask)
sm2P256CopyConditional(zOut, &sm2P256Factor[1], nIsInfinityMask)
// Equally, the result is also wrong if the point from the table is
// zero, which happens when the index is zero. We handle that by
// only copying from {tx,ty,tz} to {xOut,yOut,zOut} if index != 0.
pIsNoninfiniteMask = nonZeroToAllOnes(index)
mask = pIsNoninfiniteMask & ^nIsInfinityMask
sm2P256CopyConditional(xOut, &tx, mask)
sm2P256CopyConditional(yOut, &ty, mask)
sm2P256CopyConditional(zOut, &tz, mask)
// If p was not zero, then n is now non-zero.
nIsInfinityMask &^= pIsNoninfiniteMask
}
}
}
func sm2P256ScalarMult(xOut, yOut, zOut, x, y *sm2P256FieldElement, scalar *[32]uint8) {
var precomp [16][3]sm2P256FieldElement
var px, py, pz, tx, ty, tz sm2P256FieldElement
var nIsInfinityMask, index, pIsNoninfiniteMask, mask uint32
// We precompute 0,1,2,... times {x,y}.
precomp[1][0] = *x
precomp[1][1] = *y
precomp[1][2] = sm2P256Factor[1]
for i := 2; i < 16; i += 2 {
sm2P256PointDouble(&precomp[i][0], &precomp[i][1], &precomp[i][2], &precomp[i/2][0], &precomp[i/2][1], &precomp[i/2][2])
sm2P256PointAddMixed(&precomp[i+1][0], &precomp[i+1][1], &precomp[i+1][2], &precomp[i][0], &precomp[i][1], &precomp[i][2], x, y)
}
for i := range xOut {
xOut[i] = 0
}
for i := range yOut {
yOut[i] = 0
}
for i := range zOut {
zOut[i] = 0
}
nIsInfinityMask = ^uint32(0)
// We add in a window of four bits each iteration and do this 64 times.
for i := 0; i < 64; i++ {
if i != 0 {
sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
sm2P256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut)
}
index = uint32(scalar[31-i/2])
if (i & 1) == 1 {
index &= 15
} else {
index >>= 4
}
// See the comments in scalarBaseMult about handling infinities.
sm2P256SelectJacobianPoint(&px, &py, &pz, &precomp, index)
sm2P256PointAdd(xOut, yOut, zOut, &px, &py, &pz, &tx, &ty, &tz)
sm2P256CopyConditional(xOut, &px, nIsInfinityMask)
sm2P256CopyConditional(yOut, &py, nIsInfinityMask)
sm2P256CopyConditional(zOut, &pz, nIsInfinityMask)
pIsNoninfiniteMask = nonZeroToAllOnes(index)
mask = pIsNoninfiniteMask & ^nIsInfinityMask
sm2P256CopyConditional(xOut, &tx, mask)
sm2P256CopyConditional(yOut, &ty, mask)
sm2P256CopyConditional(zOut, &tz, mask)
nIsInfinityMask &^= pIsNoninfiniteMask
}
}
func sm2P256PointToAffine(xOut, yOut, x, y, z *sm2P256FieldElement) {
var zInv, zInvSq sm2P256FieldElement
zz := sm2P256ToBig(z)
zz.ModInverse(zz, sm2P256.P)
sm2P256FromBig(&zInv, zz)
sm2P256Square(&zInvSq, &zInv)
sm2P256Mul(xOut, x, &zInvSq)
sm2P256Mul(&zInv, &zInv, &zInvSq)
sm2P256Mul(yOut, y, &zInv)
}
func sm2P256ToAffine(x, y, z *sm2P256FieldElement) (xOut, yOut *big.Int) {
var xx, yy sm2P256FieldElement
sm2P256PointToAffine(&xx, &yy, x, y, z)
return sm2P256ToBig(&xx), sm2P256ToBig(&yy)
}
var sm2P256Factor = []sm2P256FieldElement{
sm2P256FieldElement{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
sm2P256FieldElement{0x2, 0x0, 0x1FFFFF00, 0x7FF, 0x0, 0x0, 0x0, 0x2000000, 0x0},
sm2P256FieldElement{0x4, 0x0, 0x1FFFFE00, 0xFFF, 0x0, 0x0, 0x0, 0x4000000, 0x0},
sm2P256FieldElement{0x6, 0x0, 0x1FFFFD00, 0x17FF, 0x0, 0x0, 0x0, 0x6000000, 0x0},
sm2P256FieldElement{0x8, 0x0, 0x1FFFFC00, 0x1FFF, 0x0, 0x0, 0x0, 0x8000000, 0x0},
sm2P256FieldElement{0xA, 0x0, 0x1FFFFB00, 0x27FF, 0x0, 0x0, 0x0, 0xA000000, 0x0},
sm2P256FieldElement{0xC, 0x0, 0x1FFFFA00, 0x2FFF, 0x0, 0x0, 0x0, 0xC000000, 0x0},
sm2P256FieldElement{0xE, 0x0, 0x1FFFF900, 0x37FF, 0x0, 0x0, 0x0, 0xE000000, 0x0},
sm2P256FieldElement{0x10, 0x0, 0x1FFFF800, 0x3FFF, 0x0, 0x0, 0x0, 0x0, 0x01},
}
func sm2P256Scalar(b *sm2P256FieldElement, a int) {
sm2P256Mul(b, b, &sm2P256Factor[a])
}
// (x3, y3, z3) = (x1, y1, z1) + (x2, y2, z2)
func sm2P256PointAdd(x1, y1, z1, x2, y2, z2, x3, y3, z3 *sm2P256FieldElement) {
var u1, u2, z22, z12, z23, z13, s1, s2, h, h2, r, r2, tm sm2P256FieldElement
if sm2P256ToBig(z1).Sign() == 0 {
sm2P256Dup(x3, x2)
sm2P256Dup(y3, y2)
sm2P256Dup(z3, z2)
return
}
if sm2P256ToBig(z2).Sign() == 0 {
sm2P256Dup(x3, x1)
sm2P256Dup(y3, y1)
sm2P256Dup(z3, z1)
return
}
sm2P256Square(&z12, z1) // z12 = z1 ^ 2
sm2P256Square(&z22, z2) // z22 = z2 ^ 2
sm2P256Mul(&z13, &z12, z1) // z13 = z1 ^ 3
sm2P256Mul(&z23, &z22, z2) // z23 = z2 ^ 3
sm2P256Mul(&u1, x1, &z22) // u1 = x1 * z2 ^ 2
sm2P256Mul(&u2, x2, &z12) // u2 = x2 * z1 ^ 2
sm2P256Mul(&s1, y1, &z23) // s1 = y1 * z2 ^ 3
sm2P256Mul(&s2, y2, &z13) // s2 = y2 * z1 ^ 3
if sm2P256ToBig(&u1).Cmp(sm2P256ToBig(&u2)) == 0 &&
sm2P256ToBig(&s1).Cmp(sm2P256ToBig(&s2)) == 0 {
sm2P256PointDouble(x1, y1, z1, x1, y1, z1)
}
sm2P256Sub(&h, &u2, &u1) // h = u2 - u1
sm2P256Sub(&r, &s2, &s1) // r = s2 - s1
sm2P256Square(&r2, &r) // r2 = r ^ 2
sm2P256Square(&h2, &h) // h2 = h ^ 2
sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3
sm2P256Sub(x3, &r2, &tm)
sm2P256Mul(&tm, &u1, &h2)
sm2P256Scalar(&tm, 2) // tm = 2 * (u1 * h ^ 2)
sm2P256Sub(x3, x3, &tm) // x3 = r ^ 2 - h ^ 3 - 2 * u1 * h ^ 2
sm2P256Mul(&tm, &u1, &h2) // tm = u1 * h ^ 2
sm2P256Sub(&tm, &tm, x3) // tm = u1 * h ^ 2 - x3
sm2P256Mul(y3, &r, &tm)
sm2P256Mul(&tm, &h2, &h) // tm = h ^ 3
sm2P256Mul(&tm, &tm, &s1) // tm = s1 * h ^ 3
sm2P256Sub(y3, y3, &tm) // y3 = r * (u1 * h ^ 2 - x3) - s1 * h ^ 3
sm2P256Mul(z3, z1, z2)
sm2P256Mul(z3, z3, &h) // z3 = z1 * z3 * h
}
func sm2P256PointDouble(x3, y3, z3, x, y, z *sm2P256FieldElement) {
var s, m, m2, x2, y2, z2, z4, y4, az4 sm2P256FieldElement
sm2P256Square(&x2, x) // x2 = x ^ 2
sm2P256Square(&y2, y) // y2 = y ^ 2
sm2P256Square(&z2, z) // z2 = z ^ 2
sm2P256Square(&z4, z) // z4 = z ^ 2
sm2P256Mul(&z4, &z4, z) // z4 = z ^ 3
sm2P256Mul(&z4, &z4, z) // z4 = z ^ 4
sm2P256Square(&y4, y) // y4 = y ^ 2
sm2P256Mul(&y4, &y4, y) // y4 = y ^ 3
sm2P256Mul(&y4, &y4, y) // y4 = y ^ 4
sm2P256Scalar(&y4, 8) // y4 = 8 * y ^ 4
sm2P256Mul(&s, x, &y2)
sm2P256Scalar(&s, 4) // s = 4 * x * y ^ 2
sm2P256Dup(&m, &x2)
sm2P256Scalar(&m, 3)
sm2P256Mul(&az4, &sm2P256.a, &z4)
sm2P256Add(&m, &m, &az4) // m = 3 * x ^ 2 + a * z ^ 4
sm2P256Square(&m2, &m) // m2 = m ^ 2
sm2P256Add(z3, y, z)
sm2P256Square(z3, z3)
sm2P256Sub(z3, z3, &z2)
sm2P256Sub(z3, z3, &y2) // z' = (y + z) ^2 - z ^ 2 - y ^ 2
sm2P256Sub(x3, &m2, &s)
sm2P256Sub(x3, x3, &s) // x' = m2 - 2 * s
sm2P256Sub(y3, &s, x3)
sm2P256Mul(y3, y3, &m)
sm2P256Sub(y3, y3, &y4) // y' = m * (s - x') - 8 * y ^ 4
}
// p256Zero31 is 0 mod p.
var sm2P256Zero31 = sm2P256FieldElement{0x7FFFFFF8, 0x3FFFFFFC, 0x800003FC, 0x3FFFDFFC, 0x7FFFFFFC, 0x3FFFFFFC, 0x7FFFFFFC, 0x37FFFFFC, 0x7FFFFFFC}
// c = a + b
func sm2P256Add(c, a, b *sm2P256FieldElement) {
carry := uint32(0)
for i := 0; ; i++ {
c[i] = a[i] + b[i]
c[i] += carry
carry = c[i] >> 29
c[i] &= bottom29Bits
i++
if i == 9 {
break
}
c[i] = a[i] + b[i]
c[i] += carry
carry = c[i] >> 28
c[i] &= bottom28Bits
}
sm2P256ReduceCarry(c, carry)
}
// c = a - b
func sm2P256Sub(c, a, b *sm2P256FieldElement) {
var carry uint32
for i := 0; ; i++ {
c[i] = a[i] - b[i]
c[i] += sm2P256Zero31[i]
c[i] += carry
carry = c[i] >> 29
c[i] &= bottom29Bits
i++
if i == 9 {
break
}
c[i] = a[i] - b[i]
c[i] += sm2P256Zero31[i]
c[i] += carry
carry = c[i] >> 28
c[i] &= bottom28Bits
}
sm2P256ReduceCarry(c, carry)
}
// c = a * b
func sm2P256Mul(c, a, b *sm2P256FieldElement) {
var tmp sm2P256LargeFieldElement
tmp[0] = uint64(a[0]) * uint64(b[0])
tmp[1] = uint64(a[0])*(uint64(b[1])<<0) +
uint64(a[1])*(uint64(b[0])<<0)
tmp[2] = uint64(a[0])*(uint64(b[2])<<0) +
uint64(a[1])*(uint64(b[1])<<1) +
uint64(a[2])*(uint64(b[0])<<0)
tmp[3] = uint64(a[0])*(uint64(b[3])<<0) +
uint64(a[1])*(uint64(b[2])<<0) +
uint64(a[2])*(uint64(b[1])<<0) +
uint64(a[3])*(uint64(b[0])<<0)
tmp[4] = uint64(a[0])*(uint64(b[4])<<0) +
uint64(a[1])*(uint64(b[3])<<1) +
uint64(a[2])*(uint64(b[2])<<0) +
uint64(a[3])*(uint64(b[1])<<1) +
uint64(a[4])*(uint64(b[0])<<0)
tmp[5] = uint64(a[0])*(uint64(b[5])<<0) +
uint64(a[1])*(uint64(b[4])<<0) +
uint64(a[2])*(uint64(b[3])<<0) +
uint64(a[3])*(uint64(b[2])<<0) +
uint64(a[4])*(uint64(b[1])<<0) +
uint64(a[5])*(uint64(b[0])<<0)
tmp[6] = uint64(a[0])*(uint64(b[6])<<0) +
uint64(a[1])*(uint64(b[5])<<1) +
uint64(a[2])*(uint64(b[4])<<0) +
uint64(a[3])*(uint64(b[3])<<1) +
uint64(a[4])*(uint64(b[2])<<0) +
uint64(a[5])*(uint64(b[1])<<1) +
uint64(a[6])*(uint64(b[0])<<0)
tmp[7] = uint64(a[0])*(uint64(b[7])<<0) +
uint64(a[1])*(uint64(b[6])<<0) +
uint64(a[2])*(uint64(b[5])<<0) +
uint64(a[3])*(uint64(b[4])<<0) +
uint64(a[4])*(uint64(b[3])<<0) +
uint64(a[5])*(uint64(b[2])<<0) +
uint64(a[6])*(uint64(b[1])<<0) +
uint64(a[7])*(uint64(b[0])<<0)
// tmp[8] has the greatest value but doesn't overflow. See logic in
// p256Square.
tmp[8] = uint64(a[0])*(uint64(b[8])<<0) +
uint64(a[1])*(uint64(b[7])<<1) +
uint64(a[2])*(uint64(b[6])<<0) +
uint64(a[3])*(uint64(b[5])<<1) +
uint64(a[4])*(uint64(b[4])<<0) +
uint64(a[5])*(uint64(b[3])<<1) +
uint64(a[6])*(uint64(b[2])<<0) +
uint64(a[7])*(uint64(b[1])<<1) +
uint64(a[8])*(uint64(b[0])<<0)
tmp[9] = uint64(a[1])*(uint64(b[8])<<0) +
uint64(a[2])*(uint64(b[7])<<0) +
uint64(a[3])*(uint64(b[6])<<0) +
uint64(a[4])*(uint64(b[5])<<0) +
uint64(a[5])*(uint64(b[4])<<0) +
uint64(a[6])*(uint64(b[3])<<0) +
uint64(a[7])*(uint64(b[2])<<0) +
uint64(a[8])*(uint64(b[1])<<0)
tmp[10] = uint64(a[2])*(uint64(b[8])<<0) +
uint64(a[3])*(uint64(b[7])<<1) +
uint64(a[4])*(uint64(b[6])<<0) +
uint64(a[5])*(uint64(b[5])<<1) +
uint64(a[6])*(uint64(b[4])<<0) +
uint64(a[7])*(uint64(b[3])<<1) +
uint64(a[8])*(uint64(b[2])<<0)
tmp[11] = uint64(a[3])*(uint64(b[8])<<0) +
uint64(a[4])*(uint64(b[7])<<0) +
uint64(a[5])*(uint64(b[6])<<0) +
uint64(a[6])*(uint64(b[5])<<0) +
uint64(a[7])*(uint64(b[4])<<0) +
uint64(a[8])*(uint64(b[3])<<0)
tmp[12] = uint64(a[4])*(uint64(b[8])<<0) +
uint64(a[5])*(uint64(b[7])<<1) +
uint64(a[6])*(uint64(b[6])<<0) +
uint64(a[7])*(uint64(b[5])<<1) +
uint64(a[8])*(uint64(b[4])<<0)
tmp[13] = uint64(a[5])*(uint64(b[8])<<0) +
uint64(a[6])*(uint64(b[7])<<0) +
uint64(a[7])*(uint64(b[6])<<0) +
uint64(a[8])*(uint64(b[5])<<0)
tmp[14] = uint64(a[6])*(uint64(b[8])<<0) +
uint64(a[7])*(uint64(b[7])<<1) +
uint64(a[8])*(uint64(b[6])<<0)
tmp[15] = uint64(a[7])*(uint64(b[8])<<0) +
uint64(a[8])*(uint64(b[7])<<0)
tmp[16] = uint64(a[8]) * (uint64(b[8]) << 0)
sm2P256ReduceDegree(c, &tmp)
}
// b = a * a
func sm2P256Square(b, a *sm2P256FieldElement) {
var tmp sm2P256LargeFieldElement
tmp[0] = uint64(a[0]) * uint64(a[0])
tmp[1] = uint64(a[0]) * (uint64(a[1]) << 1)
tmp[2] = uint64(a[0])*(uint64(a[2])<<1) +
uint64(a[1])*(uint64(a[1])<<1)
tmp[3] = uint64(a[0])*(uint64(a[3])<<1) +
uint64(a[1])*(uint64(a[2])<<1)
tmp[4] = uint64(a[0])*(uint64(a[4])<<1) +
uint64(a[1])*(uint64(a[3])<<2) +
uint64(a[2])*uint64(a[2])
tmp[5] = uint64(a[0])*(uint64(a[5])<<1) +
uint64(a[1])*(uint64(a[4])<<1) +
uint64(a[2])*(uint64(a[3])<<1)
tmp[6] = uint64(a[0])*(uint64(a[6])<<1) +
uint64(a[1])*(uint64(a[5])<<2) +
uint64(a[2])*(uint64(a[4])<<1) +
uint64(a[3])*(uint64(a[3])<<1)
tmp[7] = uint64(a[0])*(uint64(a[7])<<1) +
uint64(a[1])*(uint64(a[6])<<1) +
uint64(a[2])*(uint64(a[5])<<1) +
uint64(a[3])*(uint64(a[4])<<1)
// tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
// which is < 2**64 as required.
tmp[8] = uint64(a[0])*(uint64(a[8])<<1) +
uint64(a[1])*(uint64(a[7])<<2) +
uint64(a[2])*(uint64(a[6])<<1) +
uint64(a[3])*(uint64(a[5])<<2) +
uint64(a[4])*uint64(a[4])
tmp[9] = uint64(a[1])*(uint64(a[8])<<1) +
uint64(a[2])*(uint64(a[7])<<1) +
uint64(a[3])*(uint64(a[6])<<1) +
uint64(a[4])*(uint64(a[5])<<1)
tmp[10] = uint64(a[2])*(uint64(a[8])<<1) +
uint64(a[3])*(uint64(a[7])<<2) +
uint64(a[4])*(uint64(a[6])<<1) +
uint64(a[5])*(uint64(a[5])<<1)
tmp[11] = uint64(a[3])*(uint64(a[8])<<1) +
uint64(a[4])*(uint64(a[7])<<1) +
uint64(a[5])*(uint64(a[6])<<1)
tmp[12] = uint64(a[4])*(uint64(a[8])<<1) +
uint64(a[5])*(uint64(a[7])<<2) +
uint64(a[6])*uint64(a[6])
tmp[13] = uint64(a[5])*(uint64(a[8])<<1) +
uint64(a[6])*(uint64(a[7])<<1)
tmp[14] = uint64(a[6])*(uint64(a[8])<<1) +
uint64(a[7])*(uint64(a[7])<<1)
tmp[15] = uint64(a[7]) * (uint64(a[8]) << 1)
tmp[16] = uint64(a[8]) * uint64(a[8])
sm2P256ReduceDegree(b, &tmp)
}
// nonZeroToAllOnes returns:
// 0xffffffff for 0 < x <= 2**31
// 0 for x == 0 or x > 2**31.
func nonZeroToAllOnes(x uint32) uint32 {
return ((x - 1) >> 31) - 1
}
var sm2P256Carry = [8 * 9]uint32{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x2, 0x0, 0x1FFFFF00, 0x7FF, 0x0, 0x0, 0x0, 0x2000000, 0x0,
0x4, 0x0, 0x1FFFFE00, 0xFFF, 0x0, 0x0, 0x0, 0x4000000, 0x0,
0x6, 0x0, 0x1FFFFD00, 0x17FF, 0x0, 0x0, 0x0, 0x6000000, 0x0,
0x8, 0x0, 0x1FFFFC00, 0x1FFF, 0x0, 0x0, 0x0, 0x8000000, 0x0,
0xA, 0x0, 0x1FFFFB00, 0x27FF, 0x0, 0x0, 0x0, 0xA000000, 0x0,
0xC, 0x0, 0x1FFFFA00, 0x2FFF, 0x0, 0x0, 0x0, 0xC000000, 0x0,
0xE, 0x0, 0x1FFFF900, 0x37FF, 0x0, 0x0, 0x0, 0xE000000, 0x0,
}
// carry < 2 ^ 3
func sm2P256ReduceCarry(a *sm2P256FieldElement, carry uint32) {
a[0] += sm2P256Carry[carry*9+0]
a[2] += sm2P256Carry[carry*9+2]
a[3] += sm2P256Carry[carry*9+3]
a[7] += sm2P256Carry[carry*9+7]
}
// 这代码真是丑比了,我也是对自己醉了。。。
// 你最好别改这个代码,不然你会死的很惨。。
func sm2P256ReduceDegree(a *sm2P256FieldElement, b *sm2P256LargeFieldElement) {
var tmp [18]uint32
var carry, x, xMask uint32
// tmp
// 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 ...
// 29 | 28 | 29 | 28 | 29 | 28 | 29 | 28 | 29 | 28 | 29 ...
tmp[0] = uint32(b[0]) & bottom29Bits
tmp[1] = uint32(b[0]) >> 29
tmp[1] |= (uint32(b[0]>>32) << 3) & bottom28Bits
tmp[1] += uint32(b[1]) & bottom28Bits
carry = tmp[1] >> 28
tmp[1] &= bottom28Bits
for i := 2; i < 17; i++ {
tmp[i] = (uint32(b[i-2] >> 32)) >> 25
tmp[i] += (uint32(b[i-1])) >> 28
tmp[i] += (uint32(b[i-1]>>32) << 4) & bottom29Bits
tmp[i] += uint32(b[i]) & bottom29Bits
tmp[i] += carry
carry = tmp[i] >> 29
tmp[i] &= bottom29Bits
i++
if i == 17 {
break
}
tmp[i] = uint32(b[i-2]>>32) >> 25
tmp[i] += uint32(b[i-1]) >> 29
tmp[i] += ((uint32(b[i-1] >> 32)) << 3) & bottom28Bits
tmp[i] += uint32(b[i]) & bottom28Bits
tmp[i] += carry
carry = tmp[i] >> 28
tmp[i] &= bottom28Bits
}
tmp[17] = uint32(b[15]>>32) >> 25
tmp[17] += uint32(b[16]) >> 29
tmp[17] += uint32(b[16]>>32) << 3
tmp[17] += carry
for i := 0; ; i += 2 {
tmp[i+1] += tmp[i] >> 29
x = tmp[i] & bottom29Bits
tmp[i] = 0
if x > 0 {
set4 := uint32(0)
set7 := uint32(0)
xMask = nonZeroToAllOnes(x)
tmp[i+2] += (x << 7) & bottom29Bits
tmp[i+3] += x >> 22
if tmp[i+3] < 0x10000000 {
set4 = 1
tmp[i+3] += 0x10000000 & xMask
tmp[i+3] -= (x << 10) & bottom28Bits
} else {
tmp[i+3] -= (x << 10) & bottom28Bits
}
if tmp[i+4] < 0x20000000 {
tmp[i+4] += 0x20000000 & xMask
tmp[i+4] -= set4 // 借位
tmp[i+4] -= x >> 18
if tmp[i+5] < 0x10000000 {
tmp[i+5] += 0x10000000 & xMask
tmp[i+5] -= 1 // 借位
if tmp[i+6] < 0x20000000 {
set7 = 1
tmp[i+6] += 0x20000000 & xMask
tmp[i+6] -= 1 // 借位
} else {
tmp[i+6] -= 1 // 借位
}
} else {
tmp[i+5] -= 1
}
} else {
tmp[i+4] -= set4 // 借位
tmp[i+4] -= x >> 18
}
if tmp[i+7] < 0x10000000 {
tmp[i+7] += 0x10000000 & xMask
tmp[i+7] -= set7
tmp[i+7] -= (x << 24) & bottom28Bits
tmp[i+8] += (x << 28) & bottom29Bits
if tmp[i+8] < 0x20000000 {
tmp[i+8] += 0x20000000 & xMask
tmp[i+8] -= 1
tmp[i+8] -= x >> 4
tmp[i+9] += ((x >> 1) - 1) & xMask
} else {
tmp[i+8] -= 1
tmp[i+8] -= x >> 4
tmp[i+9] += (x >> 1) & xMask
}
} else {
tmp[i+7] -= set7 // 借位
tmp[i+7] -= (x << 24) & bottom28Bits
tmp[i+8] += (x << 28) & bottom29Bits
if tmp[i+8] < 0x20000000 {
tmp[i+8] += 0x20000000 & xMask
tmp[i+8] -= x >> 4
tmp[i+9] += ((x >> 1) - 1) & xMask
} else {
tmp[i+8] -= x >> 4
tmp[i+9] += (x >> 1) & xMask
}
}
}
if i+1 == 9 {
break
}
tmp[i+2] += tmp[i+1] >> 28
x = tmp[i+1] & bottom28Bits
tmp[i+1] = 0
if x > 0 {
set5 := uint32(0)
set8 := uint32(0)
set9 := uint32(0)
xMask = nonZeroToAllOnes(x)
tmp[i+3] += (x << 7) & bottom28Bits
tmp[i+4] += x >> 21
if tmp[i+4] < 0x20000000 {
set5 = 1
tmp[i+4] += 0x20000000 & xMask
tmp[i+4] -= (x << 11) & bottom29Bits
} else {
tmp[i+4] -= (x << 11) & bottom29Bits
}
if tmp[i+5] < 0x10000000 {
tmp[i+5] += 0x10000000 & xMask
tmp[i+5] -= set5 // 借位
tmp[i+5] -= x >> 18
if tmp[i+6] < 0x20000000 {
tmp[i+6] += 0x20000000 & xMask
tmp[i+6] -= 1 // 借位
if tmp[i+7] < 0x10000000 {
set8 = 1
tmp[i+7] += 0x10000000 & xMask
tmp[i+7] -= 1 // 借位
} else {
tmp[i+7] -= 1 // 借位
}
} else {
tmp[i+6] -= 1 // 借位
}
} else {
tmp[i+5] -= set5 // 借位
tmp[i+5] -= x >> 18
}
if tmp[i+8] < 0x20000000 {
set9 = 1
tmp[i+8] += 0x20000000 & xMask
tmp[i+8] -= set8
tmp[i+8] -= (x << 25) & bottom29Bits
} else {
tmp[i+8] -= set8
tmp[i+8] -= (x << 25) & bottom29Bits
}
if tmp[i+9] < 0x10000000 {
tmp[i+9] += 0x10000000 & xMask
tmp[i+9] -= set9 // 借位
tmp[i+9] -= x >> 4
tmp[i+10] += (x - 1) & xMask
} else {
tmp[i+9] -= set9 // 借位
tmp[i+9] -= x >> 4
tmp[i+10] += x & xMask
}
}
}
carry = uint32(0)
for i := 0; i < 8; i++ {
a[i] = tmp[i+9]
a[i] += carry
a[i] += (tmp[i+10] << 28) & bottom29Bits
carry = a[i] >> 29
a[i] &= bottom29Bits
i++
a[i] = tmp[i+9] >> 1
a[i] += carry
carry = a[i] >> 28
a[i] &= bottom28Bits
}
a[8] = tmp[17]
a[8] += carry
carry = a[8] >> 29
a[8] &= bottom29Bits
sm2P256ReduceCarry(a, carry)
}
// b = a
func sm2P256Dup(b, a *sm2P256FieldElement) {
*b = *a
}
// X = a * R mod P
func sm2P256FromBig(X *sm2P256FieldElement, a *big.Int) {
x := new(big.Int).Lsh(a, 257)
x.Mod(x, sm2P256.P)
for i := 0; i < 9; i++ {
if bits := x.Bits(); len(bits) > 0 {
X[i] = uint32(bits[0]) & bottom29Bits
} else {
X[i] = 0
}
x.Rsh(x, 29)
i++
if i == 9 {
break
}
if bits := x.Bits(); len(bits) > 0 {
X[i] = uint32(bits[0]) & bottom28Bits
} else {
X[i] = 0
}
x.Rsh(x, 28)
}
}
// X = r * R mod P
// r = X * R' mod P
func sm2P256ToBig(X *sm2P256FieldElement) *big.Int {
r, tm := new(big.Int), new(big.Int)
r.SetInt64(int64(X[8]))
for i := 7; i >= 0; i-- {
if (i & 1) == 0 {
r.Lsh(r, 29)
} else {
r.Lsh(r, 28)
}
tm.SetInt64(int64(X[i]))
r.Add(r, tm)
}
r.Mul(r, sm2P256.RInverse)
r.Mod(r, sm2P256.P)
return r
}
/*
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/rsa"
"encoding/asn1"
"errors"
"math/big"
)
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
type pkcs1PrivateKey struct {
Version int
N *big.Int
E int
D *big.Int
P *big.Int
Q *big.Int
// We ignore these values, if present, because rsa will calculate them.
Dp *big.Int `asn1:"optional"`
Dq *big.Int `asn1:"optional"`
Qinv *big.Int `asn1:"optional"`
AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
}
type pkcs1AdditionalRSAPrime struct {
Prime *big.Int
// We ignore these values because rsa will calculate them.
Exp *big.Int
Coeff *big.Int
}
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
var priv pkcs1PrivateKey
rest, err := asn1.Unmarshal(der, &priv)
if len(rest) > 0 {
return nil, asn1.SyntaxError{Msg: "trailing data"}
}
if err != nil {
return nil, err
}
if priv.Version > 1 {
return nil, errors.New("x509: unsupported private key version")
}
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
return nil, errors.New("x509: private key contains zero or negative value")
}
key := new(rsa.PrivateKey)
key.PublicKey = rsa.PublicKey{
E: priv.E,
N: priv.N,
}
key.D = priv.D
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
key.Primes[0] = priv.P
key.Primes[1] = priv.Q
for i, a := range priv.AdditionalPrimes {
if a.Prime.Sign() <= 0 {
return nil, errors.New("x509: private key contains zero or negative prime")
}
key.Primes[i+2] = a.Prime
// We ignore the other two values because rsa will calculate
// them as needed.
}
err = key.Validate()
if err != nil {
return nil, err
}
key.Precompute()
return key, nil
}
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
key.Precompute()
version := 0
if len(key.Primes) > 2 {
version = 1
}
priv := pkcs1PrivateKey{
Version: version,
N: key.N,
E: key.PublicKey.E,
D: key.D,
P: key.Primes[0],
Q: key.Primes[1],
Dp: key.Precomputed.Dp,
Dq: key.Precomputed.Dq,
Qinv: key.Precomputed.Qinv,
}
priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
for i, values := range key.Precomputed.CRTValues {
priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
priv.AdditionalPrimes[i].Exp = values.Exp
priv.AdditionalPrimes[i].Coeff = values.Coeff
}
b, _ := asn1.Marshal(priv)
return b
}
// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key.
type rsaPublicKey struct {
N *big.Int
E int
}
/*
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
}
/*
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
// reference to ecdsa
import (
"bytes"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/elliptic"
"crypto/rand"
"crypto/sha512"
"encoding/binary"
"errors"
"io"
"math/big"
"github.com/TMChain/go-TMChain_test/crypto/crypto_interface"
"github.com/chaincodecert/sm_crypto/sm3"
)
const (
aesIV = "IV for <SM2> CTR"
)
type PublicKey struct {
elliptic.Curve
X, Y *big.Int
}
type PrivateKey struct {
PublicKey
D *big.Int
}
// The SM2's private key contains the public key
func (priv *PrivateKey) Public() crypto.PublicKey {
return &priv.PublicKey
}
// sign format = 30 + len(z) + 02 + len(r) + r + 02 + len(s) + s, z being what follows its size, ie 02+len(r)+r+02+len(s)+s
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
r, s, err := Sign(priv, msg)
if err != nil {
return nil, err
}
sig := icrypto.FormatSm2SigTo64(r, s)
return sig, nil
}
func SM2Sign(priv *PrivateKey, hash []byte) ([]byte, error) {
r, s, err := Sign(priv, hash)
if err != nil {
return nil, err
}
sig := icrypto.FormatSm2SigTo64(r, s)
return sig, nil
}
func (priv *PrivateKey) Decrypt(data []byte) ([]byte, error) {
return Decrypt(priv, data)
}
func VerifySign(pub *PublicKey, msg []byte, sign []byte) bool {
return pub.Verify(msg, sign)
}
func (pub *PublicKey) Verify(msg []byte, sign []byte) bool {
//兼容处理ecdsa签名数据多余V的byte
if len(sign) == 65 {
sign = sign[:64]
}
r := new(big.Int).SetBytes(sign[:32])
s := new(big.Int).SetBytes(sign[32:])
return Verify(pub, msg, r, s)
}
func (pub *PublicKey) Encrypt(data []byte) ([]byte, error) {
return Encrypt(pub, data)
}
var one = new(big.Int).SetInt64(1)
func intToBytes(x int) []byte {
var buf = make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(x))
return buf
}
func kdf(x, y []byte, length int) ([]byte, bool) {
var c []byte
ct := 1
h := sm3.New()
x = append(x, y...)
for i, j := 0, (length+31)/32; i < j; i++ {
h.Reset()
h.Write(x)
h.Write(intToBytes(ct))
hash := h.Sum(nil)
if i+1 == j && length%32 != 0 {
c = append(c, hash[:length%32]...)
} else {
c = append(c, hash...)
}
ct++
}
for i := 0; i < length; i++ {
if c[i] != 0 {
return c, true
}
}
return c, false
}
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
params := c.Params()
b := make([]byte, params.BitSize/8+8)
_, err = io.ReadFull(rand, b)
if err != nil {
return
}
k = new(big.Int).SetBytes(b)
n := new(big.Int).Sub(params.N, one)
k.Mod(k, n)
k.Add(k, one)
return
}
func GenerateKey() (*PrivateKey, error) {
c := P256Sm2()
k, err := randFieldElement(c, rand.Reader)
if err != nil {
return nil, err
}
priv := new(PrivateKey)
priv.PublicKey.Curve = c
priv.D = k
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
return priv, nil
}
func GenerateKey2(rand io.Reader) (*PrivateKey, error) {
c := P256Sm2()
k, err := randFieldElement(c, rand)
if err != nil {
return nil, err
}
priv := new(PrivateKey)
priv.PublicKey.Curve = c
priv.D = k
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
return priv, nil
}
var errZeroParam = errors.New("zero parameter")
func Sign(priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
entropylen := (priv.Curve.Params().BitSize + 7) / 16
if entropylen > 32 {
entropylen = 32
}
entropy := make([]byte, entropylen)
_, err = io.ReadFull(rand.Reader, entropy)
if err != nil {
return
}
// Initialize an SHA-512 hash context; digest ...
md := sha512.New()
md.Write(priv.D.Bytes()) // the private key,
md.Write(entropy) // the entropy,
md.Write(hash) // and the input hash;
key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512),
// which is an indifferentiable MAC.
// Create an AES-CTR instance to use as a CSPRNG.
block, err := aes.NewCipher(key)
if err != nil {
return nil, nil, err
}
// Create a CSPRNG that xors a stream of zeros with
// the output of the AES-CTR instance.
csprng := cipher.StreamReader{
R: zeroReader,
S: cipher.NewCTR(block, []byte(aesIV)),
}
// See [NSA] 3.4.1
c := priv.PublicKey.Curve
N := c.Params().N
if N.Sign() == 0 {
return nil, nil, errZeroParam
}
var k *big.Int
e := new(big.Int).SetBytes(hash)
for { // 调整算法细节以实现SM2
for {
k, err = randFieldElement(c, csprng)
if err != nil {
r = nil
return
}
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
r.Add(r, e)
r.Mod(r, N)
if r.Sign() != 0 {
break
}
if t := new(big.Int).Add(r, k); t.Cmp(N) == 0 {
break
}
}
rD := new(big.Int).Mul(priv.D, r)
s = new(big.Int).Sub(k, rD)
d1 := new(big.Int).Add(priv.D, one)
d1Inv := new(big.Int).ModInverse(d1, N)
s.Mul(s, d1Inv)
s.Mod(s, N)
if s.Sign() != 0 {
break
}
}
return
}
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
c := pub.Curve
N := c.Params().N
if r.Sign() <= 0 || s.Sign() <= 0 {
return false
}
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
return false
}
// 调整算法细节以实现SM2
t := new(big.Int).Add(r, s)
t.Mod(t, N)
if N.Sign() == 0 {
return false
}
var x *big.Int
x1, y1 := c.ScalarBaseMult(s.Bytes())
x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
x, _ = c.Add(x1, y1, x2, y2)
e := new(big.Int).SetBytes(hash)
x.Add(x, e)
x.Mod(x, N)
return x.Cmp(r) == 0
}
// 32byte
var zeroByteSlice = []byte{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
}
/*
* sm2密文结构如下:
* x
* y
* hash
* CipherText
*/
func Encrypt(pub *PublicKey, data []byte) ([]byte, error) {
lenx1 := 0
leny1 := 0
lenx2 := 0
leny2 := 0
length := len(data)
for {
c := []byte{}
curve := pub.Curve
k, err := randFieldElement(curve, rand.Reader)
if err != nil {
return nil, err
}
x1, y1 := curve.ScalarBaseMult(k.Bytes())
x2, y2 := curve.ScalarMult(pub.X, pub.Y, k.Bytes())
lenx1 = len(x1.Bytes())
leny1 = len(y1.Bytes())
lenx2 = len(x2.Bytes())
leny2 = len(y2.Bytes())
if lenx1 < 32 {
c = append(c, zeroByteSlice[:(32-lenx1)]...)
}
c = append(c, x1.Bytes()...) // x分量
if leny1 < 32 {
c = append(c, zeroByteSlice[:(32-leny1)]...)
}
c = append(c, y1.Bytes()...) // y分量
tm := []byte{}
if lenx2 < 32 {
tm = append(tm, zeroByteSlice[:(32-lenx2)]...)
}
tm = append(tm, x2.Bytes()...)
tm = append(tm, data...)
if leny2 < 32 {
tm = append(tm, zeroByteSlice[:(32-leny2)]...)
}
tm = append(tm, y2.Bytes()...)
h := sm3.Sm3Sum(tm)
c = append(c, h...)
ct, ok := kdf(x2.Bytes(), y2.Bytes(), length) // 密文
if !ok {
continue
}
c = append(c, ct...)
for i := 0; i < length; i++ {
c[96+i] ^= data[i]
}
return c, nil
}
}
func Decrypt(priv *PrivateKey, data []byte) ([]byte, error) {
length := len(data) - 96
curve := priv.Curve
x := new(big.Int).SetBytes(data[:32])
y := new(big.Int).SetBytes(data[32:64])
x2, y2 := curve.ScalarMult(x, y, priv.D.Bytes())
c, ok := kdf(x2.Bytes(), y2.Bytes(), length)
if !ok {
return nil, errors.New("Decrypt: failed to decrypt")
}
for i := 0; i < length; i++ {
c[i] ^= data[i+96]
}
tm := []byte{}
tm = append(tm, x2.Bytes()...)
tm = append(tm, c...)
tm = append(tm, y2.Bytes()...)
h := sm3.Sm3Sum(tm)
if bytes.Compare(h, data[64:96]) != 0 {
return c, errors.New("Decrypt: failed to decrypt")
}
return c, nil
}
func getLastBit(a *big.Int) uint {
return a.Bit(0)
}
// 32byte
func zeroByteSlice2() []byte {
return []byte{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
}
}
// Compress transform publickey point struct to 33 bytes publickey.
func Compress(a *PublicKey) []byte {
buf := []byte{}
yp := getLastBit(a.Y)
buf = append(buf, a.X.Bytes()...)
if n := len(a.X.Bytes()); n < 32 {
buf = append(zeroByteSlice2()[:(32-n)], buf...)
}
// RFC: GB/T 32918.1-2016 4.2.9
// if yp = 0, buf = 02||x
// if yp = 0, buf = 03||x
if yp == uint(0) {
buf = append([]byte{byte(2)}, buf...)
}
if yp == uint(1) {
buf = append([]byte{byte(3)}, buf...)
}
return buf
}
// Decompress transform 33 bytes publickey to publickey point struct.
func Decompress(a []byte) *PublicKey {
var aa, xx, xx3 sm2P256FieldElement
P256Sm2()
x := new(big.Int).SetBytes(a[1:])
curve := sm2P256
sm2P256FromBig(&xx, x)
sm2P256Square(&xx3, &xx) // x3 = x ^ 2
sm2P256Mul(&xx3, &xx3, &xx) // x3 = x ^ 2 * x
sm2P256Mul(&aa, &curve.a, &xx) // a = a * x
sm2P256Add(&xx3, &xx3, &aa)
sm2P256Add(&xx3, &xx3, &curve.b)
y2 := sm2P256ToBig(&xx3)
y := new(big.Int).ModSqrt(y2, sm2P256.P)
// RFC: GB/T 32918.1-2016 4.2.10
// if a[0] = 02, getLastBit(y) = 0
// if a[0] = 03, getLastBit(y) = 1
// if yp = 0, buf = 03||x
if getLastBit(y) != uint(a[0])-2 {
y.Sub(sm2P256.P, y)
}
return &PublicKey{
Curve: P256Sm2(),
X: x,
Y: y,
}
}
type zr struct {
io.Reader
}
func (z *zr) Read(dst []byte) (n int, err error) {
for i := range dst {
dst[i] = 0
}
return len(dst), nil
}
var zeroReader = &zr{}
/*
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 (
"bytes"
"errors"
"fmt"
"net"
"runtime"
"strings"
"time"
"unicode/utf8"
)
type InvalidReason int
const (
// NotAuthorizedToSign results when a certificate is signed by another
// which isn't marked as a CA certificate.
NotAuthorizedToSign InvalidReason = iota
// Expired results when a certificate has expired, based on the time
// given in the VerifyOptions.
Expired
// CANotAuthorizedForThisName results when an intermediate or root
// certificate has a name constraint which doesn't include the name
// being checked.
CANotAuthorizedForThisName
// TooManyIntermediates results when a path length constraint is
// violated.
TooManyIntermediates
// IncompatibleUsage results when the certificate's key usage indicates
// that it may only be used for a different purpose.
IncompatibleUsage
// NameMismatch results when the subject name of a parent certificate
// does not match the issuer name in the child.
NameMismatch
)
// CertificateInvalidError results when an odd error occurs. Users of this
// library probably want to handle all these errors uniformly.
type CertificateInvalidError struct {
Cert *Certificate
Reason InvalidReason
}
func (e CertificateInvalidError) Error() string {
switch e.Reason {
case NotAuthorizedToSign:
return "x509: certificate is not authorized to sign other certificates"
case Expired:
return "x509: certificate has expired or is not yet valid"
case CANotAuthorizedForThisName:
return "x509: a root or intermediate certificate is not authorized to sign in this domain"
case TooManyIntermediates:
return "x509: too many intermediates for path length constraint"
case IncompatibleUsage:
return "x509: certificate specifies an incompatible key usage"
case NameMismatch:
return "x509: issuer name does not match subject from issuing certificate"
}
return "x509: unknown error"
}
// HostnameError results when the set of authorized names doesn't match the
// requested name.
type HostnameError struct {
Certificate *Certificate
Host string
}
func (h HostnameError) Error() string {
c := h.Certificate
var valid string
if ip := net.ParseIP(h.Host); ip != nil {
// Trying to validate an IP
if len(c.IPAddresses) == 0 {
return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
}
for _, san := range c.IPAddresses {
if len(valid) > 0 {
valid += ", "
}
valid += san.String()
}
} else {
if len(c.DNSNames) > 0 {
valid = strings.Join(c.DNSNames, ", ")
} else {
valid = c.Subject.CommonName
}
}
if len(valid) == 0 {
return "x509: certificate is not valid for any names, but wanted to match " + h.Host
}
return "x509: certificate is valid for " + valid + ", not " + h.Host
}
// UnknownAuthorityError results when the certificate issuer is unknown
type UnknownAuthorityError struct {
Cert *Certificate
// hintErr contains an error that may be helpful in determining why an
// authority wasn't found.
hintErr error
// hintCert contains a possible authority certificate that was rejected
// because of the error in hintErr.
hintCert *Certificate
}
func (e UnknownAuthorityError) Error() string {
s := "x509: certificate signed by unknown authority"
if e.hintErr != nil {
certName := e.hintCert.Subject.CommonName
if len(certName) == 0 {
if len(e.hintCert.Subject.Organization) > 0 {
certName = e.hintCert.Subject.Organization[0]
} else {
certName = "serial:" + e.hintCert.SerialNumber.String()
}
}
s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
}
return s
}
// SystemRootsError results when we fail to load the system root certificates.
type SystemRootsError struct {
Err error
}
func (se SystemRootsError) Error() string {
msg := "x509: failed to load system roots and no roots provided"
if se.Err != nil {
return msg + "; " + se.Err.Error()
}
return msg
}
// errNotParsed is returned when a certificate without ASN.1 contents is
// verified. Platform-specific verification needs the ASN.1 contents.
var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
// VerifyOptions contains parameters for Certificate.Verify. It's a structure
// because other PKIX verification APIs have ended up needing many options.
type VerifyOptions struct {
DNSName string
Intermediates *CertPool
Roots *CertPool // if nil, the system roots are used
CurrentTime time.Time // if zero, the current time is used
// KeyUsage specifies which Extended Key Usage values are acceptable.
// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
// constraint down the chain which mirrors Windows CryptoAPI behavior,
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
KeyUsages []ExtKeyUsage
}
const (
leafCertificate = iota
intermediateCertificate
rootCertificate
)
func matchNameConstraint(domain, constraint string) bool {
// The meaning of zero length constraints is not specified, but this
// code follows NSS and accepts them as valid for everything.
if len(constraint) == 0 {
return true
}
if len(domain) < len(constraint) {
return false
}
prefixLen := len(domain) - len(constraint)
if !strings.EqualFold(domain[prefixLen:], constraint) {
return false
}
if prefixLen == 0 {
return true
}
isSubdomain := domain[prefixLen-1] == '.'
constraintHasLeadingDot := constraint[0] == '.'
return isSubdomain != constraintHasLeadingDot
}
// isValid performs validity checks on the c.
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
if len(currentChain) > 0 {
child := currentChain[len(currentChain)-1]
if !bytes.Equal(child.RawIssuer, c.RawSubject) {
return CertificateInvalidError{c, NameMismatch}
}
}
now := opts.CurrentTime
if now.IsZero() {
now = time.Now()
}
if now.Before(c.NotBefore) || now.After(c.NotAfter) {
return CertificateInvalidError{c, Expired}
}
if len(c.PermittedDNSDomains) > 0 {
ok := false
for _, constraint := range c.PermittedDNSDomains {
ok = matchNameConstraint(opts.DNSName, constraint)
if ok {
break
}
}
if !ok {
return CertificateInvalidError{c, CANotAuthorizedForThisName}
}
}
// KeyUsage status flags are ignored. From Engineering Security, Peter
// Gutmann: A European government CA marked its signing certificates as
// being valid for encryption only, but no-one noticed. Another
// European CA marked its signature keys as not being valid for
// signatures. A different CA marked its own trusted root certificate
// as being invalid for certificate signing. Another national CA
// distributed a certificate to be used to encrypt data for the
// country’s tax authority that was marked as only being usable for
// digital signatures but not for encryption. Yet another CA reversed
// the order of the bit flags in the keyUsage due to confusion over
// encoding endianness, essentially setting a random keyUsage in
// certificates that it issued. Another CA created a self-invalidating
// certificate by adding a certificate policy statement stipulating
// that the certificate had to be used strictly as specified in the
// keyUsage, and a keyUsage containing a flag indicating that the RSA
// encryption key could only be used for Diffie-Hellman key agreement.
if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
return CertificateInvalidError{c, NotAuthorizedToSign}
}
if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
numIntermediates := len(currentChain) - 1
if numIntermediates > c.MaxPathLen {
return CertificateInvalidError{c, TooManyIntermediates}
}
}
return nil
}
// Verify attempts to verify c by building one or more chains from c to a
// certificate in opts.Roots, using certificates in opts.Intermediates if
// needed. If successful, it returns one or more chains where the first
// element of the chain is c and the last element is from opts.Roots.
//
// If opts.Roots is nil and system roots are unavailable the returned error
// will be of type SystemRootsError.
//
// WARNING: this doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
// Platform-specific verification needs the ASN.1 contents so
// this makes the behavior consistent across platforms.
if len(c.Raw) == 0 {
return nil, errNotParsed
}
if opts.Intermediates != nil {
for _, intermediate := range opts.Intermediates.certs {
if len(intermediate.Raw) == 0 {
return nil, errNotParsed
}
}
}
// Use Windows's own verification and chain building.
if opts.Roots == nil && runtime.GOOS == "windows" {
return c.systemVerify(&opts)
}
if len(c.UnhandledCriticalExtensions) > 0 {
return nil, UnhandledCriticalExtension{}
}
if opts.Roots == nil {
opts.Roots = systemRootsPool()
if opts.Roots == nil {
return nil, SystemRootsError{systemRootsErr}
}
}
err = c.isValid(leafCertificate, nil, &opts)
if err != nil {
return
}
if len(opts.DNSName) > 0 {
err = c.VerifyHostname(opts.DNSName)
if err != nil {
return
}
}
var candidateChains [][]*Certificate
if opts.Roots.contains(c) {
candidateChains = append(candidateChains, []*Certificate{c})
} else {
if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
return nil, err
}
}
keyUsages := opts.KeyUsages
if len(keyUsages) == 0 {
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
}
// If any key usage is acceptable then we're done.
for _, usage := range keyUsages {
if usage == ExtKeyUsageAny {
chains = candidateChains
return
}
}
for _, candidate := range candidateChains {
if checkChainForKeyUsage(candidate, keyUsages) {
chains = append(chains, candidate)
}
}
if len(chains) == 0 {
err = CertificateInvalidError{c, IncompatibleUsage}
}
return
}
func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
n := make([]*Certificate, len(chain)+1)
copy(n, chain)
n[len(chain)] = cert
return n
}
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
nextRoot:
for _, rootNum := range possibleRoots {
root := opts.Roots.certs[rootNum]
for _, cert := range currentChain {
if cert.Equal(root) {
continue nextRoot
}
}
err = root.isValid(rootCertificate, currentChain, opts)
if err != nil {
continue
}
chains = append(chains, appendToFreshChain(currentChain, root))
}
possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
nextIntermediate:
for _, intermediateNum := range possibleIntermediates {
intermediate := opts.Intermediates.certs[intermediateNum]
for _, cert := range currentChain {
if cert.Equal(intermediate) {
continue nextIntermediate
}
}
err = intermediate.isValid(intermediateCertificate, currentChain, opts)
if err != nil {
continue
}
var childChains [][]*Certificate
childChains, ok := cache[intermediateNum]
if !ok {
childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
cache[intermediateNum] = childChains
}
chains = append(chains, childChains...)
}
if len(chains) > 0 {
err = nil
}
if len(chains) == 0 && err == nil {
hintErr := rootErr
hintCert := failedRoot
if hintErr == nil {
hintErr = intermediateErr
hintCert = failedIntermediate
}
err = UnknownAuthorityError{c, hintErr, hintCert}
}
return
}
func matchHostnames(pattern, host string) bool {
host = strings.TrimSuffix(host, ".")
pattern = strings.TrimSuffix(pattern, ".")
if len(pattern) == 0 || len(host) == 0 {
return false
}
patternParts := strings.Split(pattern, ".")
hostParts := strings.Split(host, ".")
if len(patternParts) != len(hostParts) {
return false
}
for i, patternPart := range patternParts {
if i == 0 && patternPart == "*" {
continue
}
if patternPart != hostParts[i] {
return false
}
}
return true
}
// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
// an explicitly ASCII function to avoid any sharp corners resulting from
// performing Unicode operations on DNS labels.
func toLowerCaseASCII(in string) string {
// If the string is already lower-case then there's nothing to do.
isAlreadyLowerCase := true
for _, c := range in {
if c == utf8.RuneError {
// If we get a UTF-8 error then there might be
// upper-case ASCII bytes in the invalid sequence.
isAlreadyLowerCase = false
break
}
if 'A' <= c && c <= 'Z' {
isAlreadyLowerCase = false
break
}
}
if isAlreadyLowerCase {
return in
}
out := []byte(in)
for i, c := range out {
if 'A' <= c && c <= 'Z' {
out[i] += 'a' - 'A'
}
}
return string(out)
}
// VerifyHostname returns nil if c is a valid certificate for the named host.
// Otherwise it returns an error describing the mismatch.
func (c *Certificate) VerifyHostname(h string) error {
// IP addresses may be written in [ ].
candidateIP := h
if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
candidateIP = h[1 : len(h)-1]
}
if ip := net.ParseIP(candidateIP); ip != nil {
// We only match IP addresses against IP SANs.
// https://tools.ietf.org/html/rfc6125#appendix-B.2
for _, candidate := range c.IPAddresses {
if ip.Equal(candidate) {
return nil
}
}
return HostnameError{c, candidateIP}
}
lowered := toLowerCaseASCII(h)
if len(c.DNSNames) > 0 {
for _, match := range c.DNSNames {
if matchHostnames(toLowerCaseASCII(match), lowered) {
return nil
}
}
// If Subject Alt Name is given, we ignore the common name.
} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
return nil
}
return HostnameError{c, h}
}
func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
usages := make([]ExtKeyUsage, len(keyUsages))
copy(usages, keyUsages)
if len(chain) == 0 {
return false
}
usagesRemaining := len(usages)
// We walk down the list and cross out any usages that aren't supported
// by each certificate. If we cross out all the usages, then the chain
// is unacceptable.
NextCert:
for i := len(chain) - 1; i >= 0; i-- {
cert := chain[i]
if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
// The certificate doesn't have any extended key usage specified.
continue
}
for _, usage := range cert.ExtKeyUsage {
if usage == ExtKeyUsageAny {
// The certificate is explicitly good for any usage.
continue NextCert
}
}
const invalidUsage ExtKeyUsage = -1
NextRequestedUsage:
for i, requestedUsage := range usages {
if requestedUsage == invalidUsage {
continue
}
for _, usage := range cert.ExtKeyUsage {
if requestedUsage == usage {
continue NextRequestedUsage
} else if requestedUsage == ExtKeyUsageServerAuth &&
(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
// In order to support COMODO
// certificate chains, we have to
// accept Netscape or Microsoft SGC
// usages as equal to ServerAuth.
continue NextRequestedUsage
}
}
usages[i] = invalidUsage
usagesRemaining--
if usagesRemaining == 0 {
return false
}
}
}
return true
}
/*
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.
*/
// crypto/x509 add sm2 support
package sm2
import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"hash"
"io"
"io/ioutil"
"math/big"
"net"
"os"
"strconv"
"time"
"github.com/chaincodecert/sm_crypto/sm3"
)
// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
// in RFC 3280.
type pkixPublicKey struct {
Algo pkix.AlgorithmIdentifier
BitString asn1.BitString
}
// ParsePKIXPublicKey parses a DER encoded public key. These values are
// typically found in PEM blocks with "BEGIN PUBLIC KEY".
//
// Supported key types include RSA, DSA, and ECDSA. Unknown key
// types result in an error.
//
// On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey,
// or *ecdsa.PublicKey.
func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
var pki publicKeyInfo
if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after ASN.1 of public-key")
}
algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
if algo == UnknownPublicKeyAlgorithm {
return nil, errors.New("x509: unknown public key algorithm")
}
return parsePublicKey(algo, &pki)
}
func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
switch pub := pub.(type) {
case *rsa.PublicKey:
publicKeyBytes, err = asn1.Marshal(rsaPublicKey{
N: pub.N,
E: pub.E,
})
if err != nil {
return nil, pkix.AlgorithmIdentifier{}, err
}
publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
// This is a NULL parameters value which is required by
// https://tools.ietf.org/html/rfc3279#section-2.3.1.
publicKeyAlgorithm.Parameters = asn1.RawValue{
Tag: 5,
}
case *ecdsa.PublicKey:
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
oid, ok := oidFromNamedCurve(pub.Curve)
if !ok {
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
}
publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
var paramBytes []byte
paramBytes, err = asn1.Marshal(oid)
if err != nil {
return
}
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
case *PublicKey:
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
oid, ok := oidFromNamedCurve(pub.Curve)
if !ok {
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported SM2 curve")
}
publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
var paramBytes []byte
paramBytes, err = asn1.Marshal(oid)
if err != nil {
return
}
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
default:
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: only RSA and ECDSA(SM2) public keys supported")
}
return publicKeyBytes, publicKeyAlgorithm, nil
}
// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.
func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {
var publicKeyBytes []byte
var publicKeyAlgorithm pkix.AlgorithmIdentifier
var err error
if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil {
return nil, err
}
pkix := pkixPublicKey{
Algo: publicKeyAlgorithm,
BitString: asn1.BitString{
Bytes: publicKeyBytes,
BitLength: 8 * len(publicKeyBytes),
},
}
ret, _ := asn1.Marshal(pkix)
return ret, nil
}
// These structures reflect the ASN.1 structure of X.509 certificates.:
type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Raw asn1.RawContent
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
type dsaAlgorithmParameters struct {
P, Q, G *big.Int
}
type dsaSignature struct {
R, S *big.Int
}
type ecdsaSignature dsaSignature
type validity struct {
NotBefore, NotAfter time.Time
}
type publicKeyInfo struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
// RFC 5280, 4.2.1.1
type authKeyId struct {
Id []byte `asn1:"optional,tag:0"`
}
type SignatureAlgorithm int
type Hash uint
func init() {
RegisterHash(MD4, nil)
RegisterHash(MD5, md5.New)
RegisterHash(SHA1, sha1.New)
RegisterHash(SHA224, sha256.New224)
RegisterHash(SHA256, sha256.New)
RegisterHash(SHA384, sha512.New384)
RegisterHash(SHA512, sha512.New)
RegisterHash(MD5SHA1, nil)
//RegisterHash(RIPEMD160, ripemd160.New)
//RegisterHash(SHA3_224, sha3.New224)
//RegisterHash(SHA3_256, sha3.New256)
//RegisterHash(SHA3_384, sha3.New384)
//RegisterHash(SHA3_512, sha3.New512)
RegisterHash(SHA512_224, sha512.New512_224)
RegisterHash(SHA512_256, sha512.New512_256)
RegisterHash(SM3, sm3.New)
}
// HashFunc simply returns the value of h so that Hash implements SignerOpts.
func (h Hash) HashFunc() crypto.Hash {
return crypto.Hash(h)
}
const (
MD4 Hash = 1 + iota // import golang.org/x/crypto/md4
MD5 // import crypto/md5
SHA1 // import crypto/sha1
SHA224 // import crypto/sha256
SHA256 // import crypto/sha256
SHA384 // import crypto/sha512
SHA512 // import crypto/sha512
MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA
RIPEMD160 // import golang.org/x/crypto/ripemd160
SHA3_224 // import golang.org/x/crypto/sha3
SHA3_256 // import golang.org/x/crypto/sha3
SHA3_384 // import golang.org/x/crypto/sha3
SHA3_512 // import golang.org/x/crypto/sha3
SHA512_224 // import crypto/sha512
SHA512_256 // import crypto/sha512
SM3
maxHash
)
var digestSizes = []uint8{
MD4: 16,
MD5: 16,
SHA1: 20,
SHA224: 28,
SHA256: 32,
SHA384: 48,
SHA512: 64,
SHA512_224: 28,
SHA512_256: 32,
SHA3_224: 28,
SHA3_256: 32,
SHA3_384: 48,
SHA3_512: 64,
MD5SHA1: 36,
RIPEMD160: 20,
SM3: 32,
}
// Size returns the length, in bytes, of a digest resulting from the given hash
// function. It doesn't require that the hash function in question be linked
// into the program.
func (h Hash) Size() int {
if h > 0 && h < maxHash {
return int(digestSizes[h])
}
panic("crypto: Size of unknown hash function")
}
var hashes = make([]func() hash.Hash, maxHash)
// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
if h > 0 && h < maxHash {
f := hashes[h]
if f != nil {
return f()
}
}
panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}
// Available reports whether the given hash function is linked into the binary.
func (h Hash) Available() bool {
return h < maxHash && hashes[h] != nil
}
// RegisterHash registers a function that returns a new instance of the given
// hash function. This is intended to be called from the init function in
// packages that implement hash functions.
func RegisterHash(h Hash, f func() hash.Hash) {
if h >= maxHash {
panic("crypto: RegisterHash of unknown hash function")
}
hashes[h] = f
}
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
MD2WithRSA
MD5WithRSA
// SM3WithRSA reserve
SHA1WithRSA
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
DSAWithSHA1
DSAWithSHA256
ECDSAWithSHA1
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
SHA256WithRSAPSS
SHA384WithRSAPSS
SHA512WithRSAPSS
SM2WithSM3
SM2WithSHA1
SM2WithSHA256
)
func (algo SignatureAlgorithm) isRSAPSS() bool {
switch algo {
case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
return true
default:
return false
}
}
var algoName = [...]string{
MD2WithRSA: "MD2-RSA",
MD5WithRSA: "MD5-RSA",
SHA1WithRSA: "SHA1-RSA",
// SM3WithRSA: "SM3-RSA", reserve
SHA256WithRSA: "SHA256-RSA",
SHA384WithRSA: "SHA384-RSA",
SHA512WithRSA: "SHA512-RSA",
SHA256WithRSAPSS: "SHA256-RSAPSS",
SHA384WithRSAPSS: "SHA384-RSAPSS",
SHA512WithRSAPSS: "SHA512-RSAPSS",
DSAWithSHA1: "DSA-SHA1",
DSAWithSHA256: "DSA-SHA256",
ECDSAWithSHA1: "ECDSA-SHA1",
ECDSAWithSHA256: "ECDSA-SHA256",
ECDSAWithSHA384: "ECDSA-SHA384",
ECDSAWithSHA512: "ECDSA-SHA512",
SM2WithSM3: "SM2-SM3",
SM2WithSHA1: "SM2-SHA1",
SM2WithSHA256: "SM2-SHA256",
}
func (algo SignatureAlgorithm) String() string {
if 0 < algo && int(algo) < len(algoName) {
return algoName[algo]
}
return strconv.Itoa(int(algo))
}
type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
DSA
ECDSA
)
// OIDs for signature algorithms
//
// pkcs-1 OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
//
//
// RFC 3279 2.2.1 RSA Signature Algorithms
//
// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
//
// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
//
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
//
// dsaWithSha1 OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
//
// RFC 3279 2.2.3 ECDSA Signature Algorithm
//
// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-x962(10045)
// signatures(4) ecdsa-with-SHA1(1)}
//
//
// RFC 4055 5 PKCS #1 Version 1.5
//
// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
//
// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
//
// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
//
//
// RFC 5758 3.1 DSA Signature Algorithms
//
// dsaWithSha256 OBJECT IDENTIFIER ::= {
// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
// csor(3) algorithms(4) id-dsa-with-sha2(3) 2}
//
// RFC 5758 3.2 ECDSA Signature Algorithm
//
// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
//
// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
//
// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
var (
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
oidSignatureSM2WithSM3 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 501}
oidSignatureSM2WithSHA1 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 502}
oidSignatureSM2WithSHA256 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 503}
// oidSignatureSM3WithRSA = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 504}
oidSM3 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 401, 1}
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
// but it's specified by ISO. Microsoft's makecert.exe has been known
// to produce certificates with this OID.
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
)
var signatureAlgorithmDetails = []struct {
algo SignatureAlgorithm
oid asn1.ObjectIdentifier
pubKeyAlgo PublicKeyAlgorithm
hash Hash
}{
{MD2WithRSA, oidSignatureMD2WithRSA, RSA, Hash(0) /* no value for MD2 */},
{MD5WithRSA, oidSignatureMD5WithRSA, RSA, MD5},
{SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, SHA1},
{SHA1WithRSA, oidISOSignatureSHA1WithRSA, RSA, SHA1},
{SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, SHA256},
{SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, SHA384},
{SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, SHA512},
{SHA256WithRSAPSS, oidSignatureRSAPSS, RSA, SHA256},
{SHA384WithRSAPSS, oidSignatureRSAPSS, RSA, SHA384},
{SHA512WithRSAPSS, oidSignatureRSAPSS, RSA, SHA512},
{DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, SHA1},
{DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, SHA256},
{ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, SHA1},
{ECDSAWithSHA256, oidSignatureECDSAWithSHA256, ECDSA, SHA256},
{ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, SHA384},
{ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, SHA512},
{SM2WithSM3, oidSignatureSM2WithSM3, ECDSA, SM3},
{SM2WithSHA1, oidSignatureSM2WithSHA1, ECDSA, SHA1},
{SM2WithSHA256, oidSignatureSM2WithSHA256, ECDSA, SHA256},
// {SM3WithRSA, oidSignatureSM3WithRSA, RSA, SM3},
}
// pssParameters reflects the parameters in an AlgorithmIdentifier that
// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
type pssParameters struct {
// The following three fields are not marked as
// optional because the default values specify SHA-1,
// which is no longer suitable for use in signatures.
Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
SaltLength int `asn1:"explicit,tag:2"`
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
}
// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
// in an AlgorithmIdentifier that specifies RSA PSS.
func rsaPSSParameters(hashFunc Hash) asn1.RawValue {
var hashOID asn1.ObjectIdentifier
switch hashFunc {
case SHA256:
hashOID = oidSHA256
case SHA384:
hashOID = oidSHA384
case SHA512:
hashOID = oidSHA512
}
params := pssParameters{
Hash: pkix.AlgorithmIdentifier{
Algorithm: hashOID,
Parameters: asn1.RawValue{
Tag: 5, /* ASN.1 NULL */
},
},
MGF: pkix.AlgorithmIdentifier{
Algorithm: oidMGF1,
},
SaltLength: hashFunc.Size(),
TrailerField: 1,
}
mgf1Params := pkix.AlgorithmIdentifier{
Algorithm: hashOID,
Parameters: asn1.RawValue{
Tag: 5, /* ASN.1 NULL */
},
}
var err error
params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
if err != nil {
panic(err)
}
serialized, err := asn1.Marshal(params)
if err != nil {
panic(err)
}
return asn1.RawValue{FullBytes: serialized}
}
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm {
if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
for _, details := range signatureAlgorithmDetails {
if ai.Algorithm.Equal(details.oid) {
return details.algo
}
}
return UnknownSignatureAlgorithm
}
// RSA PSS is special because it encodes important parameters
// in the Parameters.
var params pssParameters
if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
return UnknownSignatureAlgorithm
}
var mgf1HashFunc pkix.AlgorithmIdentifier
if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
return UnknownSignatureAlgorithm
}
// PSS is greatly overburdened with options. This code forces
// them into three buckets by requiring that the MGF1 hash
// function always match the message hash function (as
// recommended in
// https://tools.ietf.org/html/rfc3447#section-8.1), that the
// salt length matches the hash length, and that the trailer
// field has the default value.
asn1NULL := []byte{0x05, 0x00}
if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) ||
!params.MGF.Algorithm.Equal(oidMGF1) ||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) ||
params.TrailerField != 1 {
return UnknownSignatureAlgorithm
}
switch {
case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
return SHA256WithRSAPSS
case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
return SHA384WithRSAPSS
case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
return SHA512WithRSAPSS
}
return UnknownSignatureAlgorithm
}
// RFC 3279, 2.3 Public Key Algorithms
//
// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
// rsadsi(113549) pkcs(1) 1 }
//
// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
//
// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
// x9-57(10040) x9cm(4) 1 }
//
// RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters
//
// id-ecPublicKey OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
var (
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
)
func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
switch {
case oid.Equal(oidPublicKeyRSA):
return RSA
case oid.Equal(oidPublicKeyDSA):
return DSA
case oid.Equal(oidPublicKeyECDSA):
return ECDSA
}
return UnknownPublicKeyAlgorithm
}
// RFC 5480, 2.1.1.1. Named Curve
//
// secp224r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
//
// secp256r1 OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
// prime(1) 7 }
//
// secp384r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 34 }
//
// secp521r1 OBJECT IDENTIFIER ::= {
// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
//
// NB: secp256r1 is equivalent to prime256v1
var (
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301} // I get the SM2 ID through parsing the pem file generated by gmssl
)
func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
switch {
case oid.Equal(oidNamedCurveP224):
return elliptic.P224()
case oid.Equal(oidNamedCurveP256):
return elliptic.P256()
case oid.Equal(oidNamedCurveP384):
return elliptic.P384()
case oid.Equal(oidNamedCurveP521):
return elliptic.P521()
case oid.Equal(oidNamedCurveP256SM2):
return P256Sm2()
}
return nil
}
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
switch curve {
case elliptic.P224():
return oidNamedCurveP224, true
case elliptic.P256():
return oidNamedCurveP256, true
case elliptic.P384():
return oidNamedCurveP384, true
case elliptic.P521():
return oidNamedCurveP521, true
case P256Sm2():
return oidNamedCurveP256SM2, true
}
return nil, false
}
// KeyUsage represents the set of actions that are valid for a given key. It's
// a bitmap of the KeyUsage* constants.
type KeyUsage int
const (
KeyUsageDigitalSignature KeyUsage = 1 << iota
KeyUsageContentCommitment
KeyUsageKeyEncipherment
KeyUsageDataEncipherment
KeyUsageKeyAgreement
KeyUsageCertSign
KeyUsageCRLSign
KeyUsageEncipherOnly
KeyUsageDecipherOnly
)
// RFC 5280, 4.2.1.12 Extended Key Usage
//
// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
//
// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
//
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
var (
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
)
// ExtKeyUsage represents an extended set of actions that are valid for a given key.
// Each of the ExtKeyUsage* constants define a unique action.
type ExtKeyUsage int
const (
ExtKeyUsageAny ExtKeyUsage = iota
ExtKeyUsageServerAuth
ExtKeyUsageClientAuth
ExtKeyUsageCodeSigning
ExtKeyUsageEmailProtection
ExtKeyUsageIPSECEndSystem
ExtKeyUsageIPSECTunnel
ExtKeyUsageIPSECUser
ExtKeyUsageTimeStamping
ExtKeyUsageOCSPSigning
ExtKeyUsageMicrosoftServerGatedCrypto
ExtKeyUsageNetscapeServerGatedCrypto
)
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
var extKeyUsageOIDs = []struct {
extKeyUsage ExtKeyUsage
oid asn1.ObjectIdentifier
}{
{ExtKeyUsageAny, oidExtKeyUsageAny},
{ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
{ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
{ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
{ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
{ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem},
{ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel},
{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
}
func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
for _, pair := range extKeyUsageOIDs {
if oid.Equal(pair.oid) {
return pair.extKeyUsage, true
}
}
return
}
func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) {
for _, pair := range extKeyUsageOIDs {
if eku == pair.extKeyUsage {
return pair.oid, true
}
}
return
}
// A Certificate represents an X.509 certificate.
type Certificate struct {
Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content.
RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
RawSubject []byte // DER encoded Subject
RawIssuer []byte // DER encoded Issuer
Signature []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey interface{}
Version int
SerialNumber *big.Int
Issuer pkix.Name
Subject pkix.Name
NotBefore, NotAfter time.Time // Validity bounds.
KeyUsage KeyUsage
// Extensions contains raw X.509 extensions. When parsing certificates,
// this can be used to extract non-critical extensions that are not
// parsed by this package. When marshaling certificates, the Extensions
// field is ignored, see ExtraExtensions.
Extensions []pkix.Extension
// ExtraExtensions contains extensions to be copied, raw, into any
// marshaled certificates. Values override any extensions that would
// otherwise be produced based on the other fields. The ExtraExtensions
// field is not populated when parsing certificates, see Extensions.
ExtraExtensions []pkix.Extension
// UnhandledCriticalExtensions contains a list of extension IDs that
// were not (fully) processed when parsing. Verify will fail if this
// slice is non-empty, unless verification is delegated to an OS
// library which understands all the critical extensions.
//
// Users can access these extensions using Extensions and can remove
// elements from this slice if they believe that they have been
// handled.
UnhandledCriticalExtensions []asn1.ObjectIdentifier
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
BasicConstraintsValid bool // if true then the next two fields are valid.
IsCA bool
MaxPathLen int
// MaxPathLenZero indicates that BasicConstraintsValid==true and
// MaxPathLen==0 should be interpreted as an actual maximum path length
// of zero. Otherwise, that combination is interpreted as MaxPathLen
// not being set.
MaxPathLenZero bool
SubjectKeyId []byte
AuthorityKeyId []byte
// RFC 5280, 4.2.2.1 (Authority Information Access)
OCSPServer []string
IssuingCertificateURL []string
// Subject Alternate Name values
DNSNames []string
EmailAddresses []string
IPAddresses []net.IP
// Name constraints
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
PermittedDNSDomains []string
// CRL Distribution Points
CRLDistributionPoints []string
PolicyIdentifiers []asn1.ObjectIdentifier
}
// ErrUnsupportedAlgorithm results from attempting to perform an operation that
// involves algorithms that are not currently implemented.
var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
// An InsecureAlgorithmError
type InsecureAlgorithmError SignatureAlgorithm
func (e InsecureAlgorithmError) Error() string {
return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e))
}
// ConstraintViolationError results when a requested usage is not permitted by
// a certificate. For example: checking a signature when the public key isn't a
// certificate signing key.
type ConstraintViolationError struct{}
func (ConstraintViolationError) Error() string {
return "x509: invalid signature: parent certificate cannot sign this kind of certificate"
}
func (c *Certificate) Equal(other *Certificate) bool {
return bytes.Equal(c.Raw, other.Raw)
}
// Entrust have a broken root certificate (CN=Entrust.net Certification
// Authority (2048)) which isn't marked as a CA certificate and is thus invalid
// according to PKIX.
// We recognise this certificate by its SubjectPublicKeyInfo and exempt it
// from the Basic Constraints requirement.
// See http://www.entrust.net/knowledge-base/technote.cfm?tn=7869
//
// TODO(agl): remove this hack once their reissued root is sufficiently
// widespread.
var entrustBrokenSPKI = []byte{
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0x00, 0x97, 0xa3, 0x2d, 0x3c, 0x9e, 0xde, 0x05,
0xda, 0x13, 0xc2, 0x11, 0x8d, 0x9d, 0x8e, 0xe3,
0x7f, 0xc7, 0x4b, 0x7e, 0x5a, 0x9f, 0xb3, 0xff,
0x62, 0xab, 0x73, 0xc8, 0x28, 0x6b, 0xba, 0x10,
0x64, 0x82, 0x87, 0x13, 0xcd, 0x57, 0x18, 0xff,
0x28, 0xce, 0xc0, 0xe6, 0x0e, 0x06, 0x91, 0x50,
0x29, 0x83, 0xd1, 0xf2, 0xc3, 0x2a, 0xdb, 0xd8,
0xdb, 0x4e, 0x04, 0xcc, 0x00, 0xeb, 0x8b, 0xb6,
0x96, 0xdc, 0xbc, 0xaa, 0xfa, 0x52, 0x77, 0x04,
0xc1, 0xdb, 0x19, 0xe4, 0xae, 0x9c, 0xfd, 0x3c,
0x8b, 0x03, 0xef, 0x4d, 0xbc, 0x1a, 0x03, 0x65,
0xf9, 0xc1, 0xb1, 0x3f, 0x72, 0x86, 0xf2, 0x38,
0xaa, 0x19, 0xae, 0x10, 0x88, 0x78, 0x28, 0xda,
0x75, 0xc3, 0x3d, 0x02, 0x82, 0x02, 0x9c, 0xb9,
0xc1, 0x65, 0x77, 0x76, 0x24, 0x4c, 0x98, 0xf7,
0x6d, 0x31, 0x38, 0xfb, 0xdb, 0xfe, 0xdb, 0x37,
0x02, 0x76, 0xa1, 0x18, 0x97, 0xa6, 0xcc, 0xde,
0x20, 0x09, 0x49, 0x36, 0x24, 0x69, 0x42, 0xf6,
0xe4, 0x37, 0x62, 0xf1, 0x59, 0x6d, 0xa9, 0x3c,
0xed, 0x34, 0x9c, 0xa3, 0x8e, 0xdb, 0xdc, 0x3a,
0xd7, 0xf7, 0x0a, 0x6f, 0xef, 0x2e, 0xd8, 0xd5,
0x93, 0x5a, 0x7a, 0xed, 0x08, 0x49, 0x68, 0xe2,
0x41, 0xe3, 0x5a, 0x90, 0xc1, 0x86, 0x55, 0xfc,
0x51, 0x43, 0x9d, 0xe0, 0xb2, 0xc4, 0x67, 0xb4,
0xcb, 0x32, 0x31, 0x25, 0xf0, 0x54, 0x9f, 0x4b,
0xd1, 0x6f, 0xdb, 0xd4, 0xdd, 0xfc, 0xaf, 0x5e,
0x6c, 0x78, 0x90, 0x95, 0xde, 0xca, 0x3a, 0x48,
0xb9, 0x79, 0x3c, 0x9b, 0x19, 0xd6, 0x75, 0x05,
0xa0, 0xf9, 0x88, 0xd7, 0xc1, 0xe8, 0xa5, 0x09,
0xe4, 0x1a, 0x15, 0xdc, 0x87, 0x23, 0xaa, 0xb2,
0x75, 0x8c, 0x63, 0x25, 0x87, 0xd8, 0xf8, 0x3d,
0xa6, 0xc2, 0xcc, 0x66, 0xff, 0xa5, 0x66, 0x68,
0x55, 0x02, 0x03, 0x01, 0x00, 0x01,
}
// CheckSignatureFrom verifies that the signature on c is a valid signature
// from parent.
func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
// RFC 5280, 4.2.1.9:
// "If the basic constraints extension is not present in a version 3
// certificate, or the extension is present but the cA boolean is not
// asserted, then the certified public key MUST NOT be used to verify
// certificate signatures."
// (except for Entrust, see comment above entrustBrokenSPKI)
if (parent.Version == 3 && !parent.BasicConstraintsValid ||
parent.BasicConstraintsValid && !parent.IsCA) &&
!bytes.Equal(c.RawSubjectPublicKeyInfo, entrustBrokenSPKI) {
return ConstraintViolationError{}
}
if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 {
return ConstraintViolationError{}
}
if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
return ErrUnsupportedAlgorithm
}
// TODO(agl): don't ignore the path length constraint.
return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
}
// CheckSignature verifies that signature is a valid signature over signed from
// c's public key.
func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
return checkSignature(algo, signed, signature, c.PublicKey)
}
// CheckSignature verifies that signature is a valid signature over signed from
// a crypto.PublicKey.
func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
var hashType Hash
switch algo {
case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1, SM2WithSHA1:
hashType = SHA1
case SHA256WithRSA, SHA256WithRSAPSS, DSAWithSHA256, ECDSAWithSHA256, SM2WithSHA256:
hashType = SHA256
case SHA384WithRSA, SHA384WithRSAPSS, ECDSAWithSHA384:
hashType = SHA384
case SHA512WithRSA, SHA512WithRSAPSS, ECDSAWithSHA512:
hashType = SHA512
case MD2WithRSA, MD5WithRSA:
return InsecureAlgorithmError(algo)
case SM2WithSM3: // SM3WithRSA reserve
hashType = SM3
default:
return ErrUnsupportedAlgorithm
}
if !hashType.Available() {
return ErrUnsupportedAlgorithm
}
h := hashType.New()
h.Write(signed)
digest := h.Sum(nil)
switch pub := publicKey.(type) {
case *rsa.PublicKey:
if algo.isRSAPSS() {
return rsa.VerifyPSS(pub, crypto.Hash(hashType), digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
} else {
return rsa.VerifyPKCS1v15(pub, crypto.Hash(hashType), digest, signature)
}
case *dsa.PublicKey:
dsaSig := new(dsaSignature)
if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
return err
} else if len(rest) != 0 {
return errors.New("x509: trailing data after DSA signature")
}
if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
return errors.New("x509: DSA signature contained zero or negative values")
}
if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
return errors.New("x509: DSA verification failure")
}
return
case *ecdsa.PublicKey:
ecdsaSig := new(ecdsaSignature)
if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
return err
} else if len(rest) != 0 {
return errors.New("x509: trailing data after ECDSA signature")
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
return errors.New("x509: ECDSA signature contained zero or negative values")
}
switch pub.Curve {
case P256Sm2():
if !Verify(&PublicKey{
Curve: pub.Curve,
X: pub.X,
Y: pub.Y,
}, digest, ecdsaSig.R, ecdsaSig.S) {
return errors.New("x509: SM2 verification failure")
}
default:
if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) {
return errors.New("x509: ECDSA verification failure")
}
}
return
}
return ErrUnsupportedAlgorithm
}
// CheckCRLSignature checks that the signature in crl is from c.
func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
type UnhandledCriticalExtension struct{}
func (h UnhandledCriticalExtension) Error() string {
return "x509: unhandled critical extension"
}
type basicConstraints struct {
IsCA bool `asn1:"optional"`
MaxPathLen int `asn1:"optional,default:-1"`
}
// RFC 5280 4.2.1.4
type policyInformation struct {
Policy asn1.ObjectIdentifier
// policyQualifiers omitted
}
// RFC 5280, 4.2.1.10
type nameConstraints struct {
Permitted []generalSubtree `asn1:"optional,tag:0"`
Excluded []generalSubtree `asn1:"optional,tag:1"`
}
type generalSubtree struct {
Name string `asn1:"tag:2,optional,ia5"`
}
// RFC 5280, 4.2.2.1
type authorityInfoAccess struct {
Method asn1.ObjectIdentifier
Location asn1.RawValue
}
// RFC 5280, 4.2.1.14
type distributionPoint struct {
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
Reason asn1.BitString `asn1:"optional,tag:1"`
CRLIssuer asn1.RawValue `asn1:"optional,tag:2"`
}
type distributionPointName struct {
FullName asn1.RawValue `asn1:"optional,tag:0"`
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}
// asn1Null is the ASN.1 encoding of a NULL value.
var asn1Null = []byte{5, 0}
func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
asn1Data := keyData.PublicKey.RightAlign()
switch algo {
case RSA:
// RSA public keys must have a NULL in the parameters
// (https://tools.ietf.org/html/rfc3279#section-2.3.1).
if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) {
return nil, errors.New("x509: RSA key missing NULL parameters")
}
p := new(rsaPublicKey)
rest, err := asn1.Unmarshal(asn1Data, p)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: trailing data after RSA public key")
}
if p.N.Sign() <= 0 {
return nil, errors.New("x509: RSA modulus is not a positive number")
}
if p.E <= 0 {
return nil, errors.New("x509: RSA public exponent is not a positive number")
}
pub := &rsa.PublicKey{
E: p.E,
N: p.N,
}
return pub, nil
case DSA:
var p *big.Int
rest, err := asn1.Unmarshal(asn1Data, &p)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: trailing data after DSA public key")
}
paramsData := keyData.Algorithm.Parameters.FullBytes
params := new(dsaAlgorithmParameters)
rest, err = asn1.Unmarshal(paramsData, params)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: trailing data after DSA parameters")
}
if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
return nil, errors.New("x509: zero or negative DSA parameter")
}
pub := &dsa.PublicKey{
Parameters: dsa.Parameters{
P: params.P,
Q: params.Q,
G: params.G,
},
Y: p,
}
return pub, nil
case ECDSA:
paramsData := keyData.Algorithm.Parameters.FullBytes
namedCurveOID := new(asn1.ObjectIdentifier)
rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: trailing data after ECDSA parameters")
}
namedCurve := namedCurveFromOID(*namedCurveOID)
if namedCurve == nil {
return nil, errors.New("x509: unsupported elliptic curve")
}
x, y := elliptic.Unmarshal(namedCurve, asn1Data)
if x == nil {
return nil, errors.New("x509: failed to unmarshal elliptic curve point")
}
pub := &ecdsa.PublicKey{
Curve: namedCurve,
X: x,
Y: y,
}
return pub, nil
default:
return nil, nil
}
}
func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) {
// RFC 5280, 4.2.1.6
// SubjectAltName ::= GeneralNames
//
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
//
// GeneralName ::= CHOICE {
// otherName [0] OtherName,
// rfc822Name [1] IA5String,
// dNSName [2] IA5String,
// x400Address [3] ORAddress,
// directoryName [4] Name,
// ediPartyName [5] EDIPartyName,
// uniformResourceIdentifier [6] IA5String,
// iPAddress [7] OCTET STRING,
// registeredID [8] OBJECT IDENTIFIER }
var seq asn1.RawValue
var rest []byte
if rest, err = asn1.Unmarshal(value, &seq); err != nil {
return
} else if len(rest) != 0 {
err = errors.New("x509: trailing data after X.509 extension")
return
}
if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
err = asn1.StructuralError{Msg: "bad SAN sequence"}
return
}
rest = seq.Bytes
for len(rest) > 0 {
var v asn1.RawValue
rest, err = asn1.Unmarshal(rest, &v)
if err != nil {
return
}
switch v.Tag {
case 1:
emailAddresses = append(emailAddresses, string(v.Bytes))
case 2:
dnsNames = append(dnsNames, string(v.Bytes))
case 7:
switch len(v.Bytes) {
case net.IPv4len, net.IPv6len:
ipAddresses = append(ipAddresses, v.Bytes)
default:
err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
return
}
}
}
return
}
func parseCertificate(in *certificate) (*Certificate, error) {
out := new(Certificate)
out.Raw = in.Raw
out.RawTBSCertificate = in.TBSCertificate.Raw
out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw
out.RawSubject = in.TBSCertificate.Subject.FullBytes
out.RawIssuer = in.TBSCertificate.Issuer.FullBytes
out.Signature = in.SignatureValue.RightAlign()
out.SignatureAlgorithm =
getSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm)
out.PublicKeyAlgorithm =
getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
var err error
out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)
if err != nil {
return nil, err
}
out.Version = in.TBSCertificate.Version + 1
out.SerialNumber = in.TBSCertificate.SerialNumber
var issuer, subject pkix.RDNSequence
if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 subject")
}
if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 subject")
}
out.Issuer.FillFromRDNSequence(&issuer)
out.Subject.FillFromRDNSequence(&subject)
out.NotBefore = in.TBSCertificate.Validity.NotBefore
out.NotAfter = in.TBSCertificate.Validity.NotAfter
for _, e := range in.TBSCertificate.Extensions {
out.Extensions = append(out.Extensions, e)
unhandled := false
if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
switch e.Id[3] {
case 15:
// RFC 5280, 4.2.1.3
var usageBits asn1.BitString
if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 KeyUsage")
}
var usage int
for i := 0; i < 9; i++ {
if usageBits.At(i) != 0 {
usage |= 1 << uint(i)
}
}
out.KeyUsage = KeyUsage(usage)
case 19:
// RFC 5280, 4.2.1.9
var constraints basicConstraints
if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 BasicConstraints")
}
out.BasicConstraintsValid = true
out.IsCA = constraints.IsCA
out.MaxPathLen = constraints.MaxPathLen
out.MaxPathLenZero = out.MaxPathLen == 0
case 17:
out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
if err != nil {
return nil, err
}
if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 {
// If we didn't parse anything then we do the critical check, below.
unhandled = true
}
case 30:
// RFC 5280, 4.2.1.10
// NameConstraints ::= SEQUENCE {
// permittedSubtrees [0] GeneralSubtrees OPTIONAL,
// excludedSubtrees [1] GeneralSubtrees OPTIONAL }
//
// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
//
// GeneralSubtree ::= SEQUENCE {
// base GeneralName,
// minimum [0] BaseDistance DEFAULT 0,
// maximum [1] BaseDistance OPTIONAL }
//
// BaseDistance ::= INTEGER (0..MAX)
var constraints nameConstraints
if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 NameConstraints")
}
if len(constraints.Excluded) > 0 && e.Critical {
return out, UnhandledCriticalExtension{}
}
for _, subtree := range constraints.Permitted {
if len(subtree.Name) == 0 {
if e.Critical {
return out, UnhandledCriticalExtension{}
}
continue
}
out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
}
case 31:
// RFC 5280, 4.2.1.13
// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
//
// DistributionPoint ::= SEQUENCE {
// distributionPoint [0] DistributionPointName OPTIONAL,
// reasons [1] ReasonFlags OPTIONAL,
// cRLIssuer [2] GeneralNames OPTIONAL }
//
// DistributionPointName ::= CHOICE {
// fullName [0] GeneralNames,
// nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
var cdp []distributionPoint
if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 CRL distribution point")
}
for _, dp := range cdp {
// Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty.
if len(dp.DistributionPoint.FullName.Bytes) == 0 {
continue
}
var n asn1.RawValue
if _, err := asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
return nil, err
}
// Trailing data after the fullName is
// allowed because other elements of
// the SEQUENCE can appear.
if n.Tag == 6 {
out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
}
}
case 35:
// RFC 5280, 4.2.1.1
var a authKeyId
if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 authority key-id")
}
out.AuthorityKeyId = a.Id
case 37:
// RFC 5280, 4.2.1.12. Extended Key Usage
// id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
//
// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
//
// KeyPurposeId ::= OBJECT IDENTIFIER
var keyUsage []asn1.ObjectIdentifier
if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
}
for _, u := range keyUsage {
if extKeyUsage, ok := extKeyUsageFromOID(u); ok {
out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage)
} else {
out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)
}
}
case 14:
// RFC 5280, 4.2.1.2
var keyid []byte
if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 key-id")
}
out.SubjectKeyId = keyid
case 32:
// RFC 5280 4.2.1.4: Certificate Policies
var policies []policyInformation
if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 certificate policies")
}
out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
for i, policy := range policies {
out.PolicyIdentifiers[i] = policy.Policy
}
default:
// Unknown extensions are recorded if critical.
unhandled = true
}
} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
// RFC 5280 4.2.2.1: Authority Information Access
var aia []authorityInfoAccess
if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 authority information")
}
for _, v := range aia {
// GeneralName: uniformResourceIdentifier [6] IA5String
if v.Location.Tag != 6 {
continue
}
if v.Method.Equal(oidAuthorityInfoAccessOcsp) {
out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes))
} else if v.Method.Equal(oidAuthorityInfoAccessIssuers) {
out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
}
}
} else {
// Unknown extensions are recorded if critical.
unhandled = true
}
if e.Critical && unhandled {
out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
}
}
return out, nil
}
// ParseCertificate parses a single certificate from the given ASN.1 DER data.
func ParseCertificate(asn1Data []byte) (*Certificate, error) {
var cert certificate
rest, err := asn1.Unmarshal(asn1Data, &cert)
if err != nil {
return nil, err
}
if len(rest) > 0 {
return nil, asn1.SyntaxError{Msg: "trailing data"}
}
return parseCertificate(&cert)
}
// ParseCertificates parses one or more certificates from the given ASN.1 DER
// data. The certificates must be concatenated with no intermediate padding.
func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
var v []*certificate
for len(asn1Data) > 0 {
cert := new(certificate)
var err error
asn1Data, err = asn1.Unmarshal(asn1Data, cert)
if err != nil {
return nil, err
}
v = append(v, cert)
}
ret := make([]*Certificate, len(v))
for i, ci := range v {
cert, err := parseCertificate(ci)
if err != nil {
return nil, err
}
ret[i] = cert
}
return ret, nil
}
func reverseBitsInAByte(in byte) byte {
b1 := in>>4 | in<<4
b2 := b1>>2&0x33 | b1<<2&0xcc
b3 := b2>>1&0x55 | b2<<1&0xaa
return b3
}
// asn1BitLength returns the bit-length of bitString by considering the
// most-significant bit in a byte to be the "first" bit. This convention
// matches ASN.1, but differs from almost everything else.
func asn1BitLength(bitString []byte) int {
bitLen := len(bitString) * 8
for i := range bitString {
b := bitString[len(bitString)-i-1]
for bit := uint(0); bit < 8; bit++ {
if (b>>bit)&1 == 1 {
return bitLen
}
bitLen--
}
}
return 0
}
var (
oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
oidExtensionKeyUsage = []int{2, 5, 29, 15}
oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
oidExtensionBasicConstraints = []int{2, 5, 29, 19}
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
oidExtensionNameConstraints = []int{2, 5, 29, 30}
oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31}
oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
)
var (
oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1}
oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}
)
// oidNotInExtensions returns whether an extension with the given oid exists in
// extensions.
func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
for _, e := range extensions {
if e.Id.Equal(oid) {
return true
}
}
return false
}
// marshalSANs marshals a list of addresses into a the contents of an X.509
// SubjectAlternativeName extension.
func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBytes []byte, err error) {
var rawValues []asn1.RawValue
for _, name := range dnsNames {
rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
}
for _, email := range emailAddresses {
rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
}
for _, rawIP := range ipAddresses {
// If possible, we always want to encode IPv4 addresses in 4 bytes.
ip := rawIP.To4()
if ip == nil {
ip = rawIP
}
rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
}
return asn1.Marshal(rawValues)
}
func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0
if template.KeyUsage != 0 &&
!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
ret[n].Id = oidExtensionKeyUsage
ret[n].Critical = true
var a [2]byte
a[0] = reverseBitsInAByte(byte(template.KeyUsage))
a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
l := 1
if a[1] != 0 {
l = 2
}
bitString := a[:l]
ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
if err != nil {
return
}
n++
}
if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
ret[n].Id = oidExtensionExtendedKeyUsage
var oids []asn1.ObjectIdentifier
for _, u := range template.ExtKeyUsage {
if oid, ok := oidFromExtKeyUsage(u); ok {
oids = append(oids, oid)
} else {
panic("internal error")
}
}
oids = append(oids, template.UnknownExtKeyUsage...)
ret[n].Value, err = asn1.Marshal(oids)
if err != nil {
return
}
n++
}
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
// Leaving MaxPathLen as zero indicates that no maximum path
// length is desired, unless MaxPathLenZero is set. A value of
// -1 causes encoding/asn1 to omit the value as desired.
maxPathLen := template.MaxPathLen
if maxPathLen == 0 && !template.MaxPathLenZero {
maxPathLen = -1
}
ret[n].Id = oidExtensionBasicConstraints
ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
ret[n].Critical = true
if err != nil {
return
}
n++
}
if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectKeyId
ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
if err != nil {
return
}
n++
}
if len(template.AuthorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) {
ret[n].Id = oidExtensionAuthorityKeyId
ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
if err != nil {
return
}
n++
}
if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) &&
!oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) {
ret[n].Id = oidExtensionAuthorityInfoAccess
var aiaValues []authorityInfoAccess
for _, name := range template.OCSPServer {
aiaValues = append(aiaValues, authorityInfoAccess{
Method: oidAuthorityInfoAccessOcsp,
Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
})
}
for _, name := range template.IssuingCertificateURL {
aiaValues = append(aiaValues, authorityInfoAccess{
Method: oidAuthorityInfoAccessIssuers,
Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
})
}
ret[n].Value, err = asn1.Marshal(aiaValues)
if err != nil {
return
}
n++
}
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectAltName
ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
if err != nil {
return
}
n++
}
if len(template.PolicyIdentifiers) > 0 &&
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
ret[n].Id = oidExtensionCertificatePolicies
policies := make([]policyInformation, len(template.PolicyIdentifiers))
for i, policy := range template.PolicyIdentifiers {
policies[i].Policy = policy
}
ret[n].Value, err = asn1.Marshal(policies)
if err != nil {
return
}
n++
}
if len(template.PermittedDNSDomains) > 0 &&
!oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) {
ret[n].Id = oidExtensionNameConstraints
ret[n].Critical = template.PermittedDNSDomainsCritical
var out nameConstraints
out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains))
for i, permitted := range template.PermittedDNSDomains {
out.Permitted[i] = generalSubtree{Name: permitted}
}
ret[n].Value, err = asn1.Marshal(out)
if err != nil {
return
}
n++
}
if len(template.CRLDistributionPoints) > 0 &&
!oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) {
ret[n].Id = oidExtensionCRLDistributionPoints
var crlDp []distributionPoint
for _, name := range template.CRLDistributionPoints {
rawFullName, _ := asn1.Marshal(asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)})
dp := distributionPoint{
DistributionPoint: distributionPointName{
FullName: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: rawFullName},
},
}
crlDp = append(crlDp, dp)
}
ret[n].Value, err = asn1.Marshal(crlDp)
if err != nil {
return
}
n++
}
// Adding another extension here? Remember to update the maximum number
// of elements in the make() at the top of the function.
return append(ret[:n], template.ExtraExtensions...), nil
}
func subjectBytes(cert *Certificate) ([]byte, error) {
if len(cert.RawSubject) > 0 {
return cert.RawSubject, nil
}
return asn1.Marshal(cert.Subject.ToRDNSequence())
}
// signingParamsForPublicKey returns the parameters to use for signing with
// priv. If requestedSigAlgo is not zero then it overrides the default
// signature algorithm.
func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
var pubType PublicKeyAlgorithm
switch pub := pub.(type) {
case *rsa.PublicKey:
pubType = RSA
hashFunc = SHA256
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
sigAlgo.Parameters = asn1.RawValue{
Tag: 5,
}
case *ecdsa.PublicKey:
pubType = ECDSA
switch pub.Curve {
case elliptic.P224(), elliptic.P256():
hashFunc = SHA256
sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
case elliptic.P384():
hashFunc = SHA384
sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
case elliptic.P521():
hashFunc = SHA512
sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
default:
err = errors.New("x509: unknown elliptic curve")
}
case *PublicKey:
pubType = ECDSA
switch pub.Curve {
case P256Sm2():
hashFunc = SM3
sigAlgo.Algorithm = oidSignatureSM2WithSM3
default:
err = errors.New("x509: unknown SM2 curve")
}
default:
err = errors.New("x509: only RSA and ECDSA keys supported")
}
if err != nil {
return
}
if requestedSigAlgo == 0 {
return
}
found := false
for _, details := range signatureAlgorithmDetails {
if details.algo == requestedSigAlgo {
if details.pubKeyAlgo != pubType {
err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
return
}
sigAlgo.Algorithm, hashFunc = details.oid, details.hash
if hashFunc == 0 {
err = errors.New("x509: cannot sign with hash function requested")
return
}
if requestedSigAlgo.isRSAPSS() {
sigAlgo.Parameters = rsaPSSParameters(hashFunc)
}
found = true
break
}
}
if !found {
err = errors.New("x509: unknown SignatureAlgorithm")
}
return
}
// CreateCertificate creates a new certificate based on a template. The
// following members of template are used: SerialNumber, Subject, NotBefore,
// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid,
// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
// PermittedDNSDomains, SignatureAlgorithm.
//
// The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed. The parameter pub is the public key of the
// signee and priv is the private key of the signer.
//
// The returned slice is the certificate in DER encoding.
//
// All keys types that are implemented via crypto.Signer are supported (This
// includes *rsa.PublicKey and *ecdsa.PublicKey.)
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
if template.SerialNumber == nil {
return nil, errors.New("x509: no SerialNumber given")
}
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
if err != nil {
return nil, err
}
publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
if err != nil {
return nil, err
}
asn1Issuer, err := subjectBytes(parent)
if err != nil {
return
}
asn1Subject, err := subjectBytes(template)
if err != nil {
return
}
if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
template.AuthorityKeyId = parent.SubjectKeyId
}
extensions, err := buildExtensions(template)
if err != nil {
return
}
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
c := tbsCertificate{
Version: 2,
SerialNumber: template.SerialNumber,
SignatureAlgorithm: signatureAlgorithm,
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
Subject: asn1.RawValue{FullBytes: asn1Subject},
PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
Extensions: extensions,
}
tbsCertContents, err := asn1.Marshal(c)
if err != nil {
return
}
c.Raw = tbsCertContents
h := hashFunc.New()
h.Write(tbsCertContents)
digest := h.Sum(nil)
var signerOpts crypto.SignerOpts
signerOpts = hashFunc
if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
signerOpts = &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash,
Hash: crypto.Hash(hashFunc),
}
}
var signature []byte
signature, err = key.Sign(rand, digest, signerOpts)
if err != nil {
return
}
return asn1.Marshal(certificate{
nil,
c,
signatureAlgorithm,
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
// CRL.
var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
// pemType is the type of a PEM encoded CRL.
var pemType = "X509 CRL"
// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
// encoded CRLs will appear where they should be DER encoded, so this function
// will transparently handle PEM encoding as long as there isn't any leading
// garbage.
func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) {
if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
block, _ := pem.Decode(crlBytes)
if block != nil && block.Type == pemType {
crlBytes = block.Bytes
}
}
return ParseDERCRL(crlBytes)
}
// ParseDERCRL parses a DER encoded CRL from the given bytes.
func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
certList := new(pkix.CertificateList)
if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after CRL")
}
return certList, nil
}
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
// contains the given list of revoked certificates.
func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
if err != nil {
return nil, err
}
// Force revocation times to UTC per RFC 5280.
revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts))
for i, rc := range revokedCerts {
rc.RevocationTime = rc.RevocationTime.UTC()
revokedCertsUTC[i] = rc
}
tbsCertList := pkix.TBSCertificateList{
Version: 1,
Signature: signatureAlgorithm,
Issuer: c.Subject.ToRDNSequence(),
ThisUpdate: now.UTC(),
NextUpdate: expiry.UTC(),
RevokedCertificates: revokedCertsUTC,
}
// Authority Key Id
if len(c.SubjectKeyId) > 0 {
var aki pkix.Extension
aki.Id = oidExtensionAuthorityKeyId
aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
if err != nil {
return
}
tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
}
tbsCertListContents, err := asn1.Marshal(tbsCertList)
if err != nil {
return
}
h := hashFunc.New()
h.Write(tbsCertListContents)
digest := h.Sum(nil)
var signature []byte
signature, err = key.Sign(rand, digest, hashFunc)
if err != nil {
return
}
return asn1.Marshal(pkix.CertificateList{
TBSCertList: tbsCertList,
SignatureAlgorithm: signatureAlgorithm,
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
// CertificateRequest represents a PKCS #10, certificate signature request.
type CertificateRequest struct {
Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
RawSubject []byte // DER encoded Subject.
Version int
Signature []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey interface{}
Subject pkix.Name
// Attributes is the dried husk of a bug and shouldn't be used.
Attributes []pkix.AttributeTypeAndValueSET
// Extensions contains raw X.509 extensions. When parsing CSRs, this
// can be used to extract extensions that are not parsed by this
// package.
Extensions []pkix.Extension
// ExtraExtensions contains extensions to be copied, raw, into any
// marshaled CSR. Values override any extensions that would otherwise
// be produced based on the other fields but are overridden by any
// extensions specified in Attributes.
//
// The ExtraExtensions field is not populated when parsing CSRs, see
// Extensions.
ExtraExtensions []pkix.Extension
// Subject Alternate Name values.
DNSNames []string
EmailAddresses []string
IPAddresses []net.IP
}
// These structures reflect the ASN.1 structure of X.509 certificate
// signature requests (see RFC 2986):
type tbsCertificateRequest struct {
Raw asn1.RawContent
Version int
Subject asn1.RawValue
PublicKey publicKeyInfo
RawAttributes []asn1.RawValue `asn1:"tag:0"`
}
type certificateRequest struct {
Raw asn1.RawContent
TBSCSR tbsCertificateRequest
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
// extensions in a CSR.
var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
// newRawAttributes converts AttributeTypeAndValueSETs from a template
// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
var rawAttributes []asn1.RawValue
b, err := asn1.Marshal(attributes)
if err != nil {
return nil, err
}
rest, err := asn1.Unmarshal(b, &rawAttributes)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, errors.New("x509: failed to unmarshal raw CSR Attributes")
}
return rawAttributes, nil
}
// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
var attributes []pkix.AttributeTypeAndValueSET
for _, rawAttr := range rawAttributes {
var attr pkix.AttributeTypeAndValueSET
rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
// Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
// (i.e.: challengePassword or unstructuredName).
if err == nil && len(rest) == 0 {
attributes = append(attributes, attr)
}
}
return attributes
}
// parseCSRExtensions parses the attributes from a CSR and extracts any
// requested extensions.
func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) {
// pkcs10Attribute reflects the Attribute structure from section 4.1 of
// https://tools.ietf.org/html/rfc2986.
type pkcs10Attribute struct {
Id asn1.ObjectIdentifier
Values []asn1.RawValue `asn1:"set"`
}
var ret []pkix.Extension
for _, rawAttr := range rawAttributes {
var attr pkcs10Attribute
if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 {
// Ignore attributes that don't parse.
continue
}
if !attr.Id.Equal(oidExtensionRequest) {
continue
}
var extensions []pkix.Extension
if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil {
return nil, err
}
ret = append(ret, extensions...)
}
return ret, nil
}
// CreateCertificateRequest creates a new certificate request based on a template.
// The following members of template are used: Subject, Attributes,
// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
// The private key is the private key of the signer.
//
// The returned slice is the certificate request in DER encoding.
//
// All keys types that are implemented via crypto.Signer are supported (This
// includes *rsa.PublicKey and *ecdsa.PublicKey.)
func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
var hashFunc Hash
var sigAlgo pkix.AlgorithmIdentifier
hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
if err != nil {
return nil, err
}
var publicKeyBytes []byte
var publicKeyAlgorithm pkix.AlgorithmIdentifier
publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
if err != nil {
return nil, err
}
var extensions []pkix.Extension
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
if err != nil {
return nil, err
}
extensions = append(extensions, pkix.Extension{
Id: oidExtensionSubjectAltName,
Value: sanBytes,
})
}
extensions = append(extensions, template.ExtraExtensions...)
var attributes []pkix.AttributeTypeAndValueSET
attributes = append(attributes, template.Attributes...)
if len(extensions) > 0 {
// specifiedExtensions contains all the extensions that we
// found specified via template.Attributes.
specifiedExtensions := make(map[string]bool)
for _, atvSet := range template.Attributes {
if !atvSet.Type.Equal(oidExtensionRequest) {
continue
}
for _, atvs := range atvSet.Value {
for _, atv := range atvs {
specifiedExtensions[atv.Type.String()] = true
}
}
}
atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
for _, e := range extensions {
if specifiedExtensions[e.Id.String()] {
// Attributes already contained a value for
// this extension and it takes priority.
continue
}
atvs = append(atvs, pkix.AttributeTypeAndValue{
// There is no place for the critical flag in a CSR.
Type: e.Id,
Value: e.Value,
})
}
// Append the extensions to an existing attribute if possible.
appended := false
for _, atvSet := range attributes {
if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
continue
}
atvSet.Value[0] = append(atvSet.Value[0], atvs...)
appended = true
break
}
// Otherwise, add a new attribute for the extensions.
if !appended {
attributes = append(attributes, pkix.AttributeTypeAndValueSET{
Type: oidExtensionRequest,
Value: [][]pkix.AttributeTypeAndValue{
atvs,
},
})
}
}
asn1Subject := template.RawSubject
if len(asn1Subject) == 0 {
asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
if err != nil {
return
}
}
rawAttributes, err := newRawAttributes(attributes)
if err != nil {
return
}
tbsCSR := tbsCertificateRequest{
Version: 0, // PKCS #10, RFC 2986
Subject: asn1.RawValue{FullBytes: asn1Subject},
PublicKey: publicKeyInfo{
Algorithm: publicKeyAlgorithm,
PublicKey: asn1.BitString{
Bytes: publicKeyBytes,
BitLength: len(publicKeyBytes) * 8,
},
},
RawAttributes: rawAttributes,
}
tbsCSRContents, err := asn1.Marshal(tbsCSR)
if err != nil {
return
}
tbsCSR.Raw = tbsCSRContents
h := hashFunc.New()
h.Write(tbsCSRContents)
digest := h.Sum(nil)
var signature []byte
signature, err = key.Sign(rand, digest, hashFunc)
if err != nil {
return
}
return asn1.Marshal(certificateRequest{
TBSCSR: tbsCSR,
SignatureAlgorithm: sigAlgo,
SignatureValue: asn1.BitString{
Bytes: signature,
BitLength: len(signature) * 8,
},
})
}
// ParseCertificateRequest parses a single certificate request from the
// given ASN.1 DER data.
func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
var csr certificateRequest
rest, err := asn1.Unmarshal(asn1Data, &csr)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, asn1.SyntaxError{Msg: "trailing data"}
}
return parseCertificateRequest(&csr)
}
func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
out := &CertificateRequest{
Raw: in.Raw,
RawTBSCertificateRequest: in.TBSCSR.Raw,
RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw,
RawSubject: in.TBSCSR.Subject.FullBytes,
Signature: in.SignatureValue.RightAlign(),
SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm),
PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
Version: in.TBSCSR.Version,
Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
}
var err error
out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey)
if err != nil {
return nil, err
}
var subject pkix.RDNSequence
if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after X.509 Subject")
}
out.Subject.FillFromRDNSequence(&subject)
if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil {
return nil, err
}
for _, extension := range out.Extensions {
if extension.Id.Equal(oidExtensionSubjectAltName) {
out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(extension.Value)
if err != nil {
return nil, err
}
}
}
return out, nil
}
// CheckSignature reports whether the signature on c is valid.
func (c *CertificateRequest) CheckSignature() error {
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
}
func ReadCertificateRequestFromMem(data []byte) (*CertificateRequest, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("failed to decode certificate request")
}
return ParseCertificateRequest(block.Bytes)
}
func ReadCertificateRequestFromPem(FileName string) (*CertificateRequest, error) {
data, err := ioutil.ReadFile(FileName)
if err != nil {
return nil, err
}
return ReadCertificateRequestFromMem(data)
}
func CreateCertificateRequestToMem(template *CertificateRequest, privKey *PrivateKey) ([]byte, error) {
der, err := CreateCertificateRequest(rand.Reader, template, privKey)
if err != nil {
return nil, err
}
block := &pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: der,
}
return pem.EncodeToMemory(block), nil
}
func CreateCertificateRequestToPem(FileName string, template *CertificateRequest,
privKey *PrivateKey) (bool, error) {
der, err := CreateCertificateRequest(rand.Reader, template, privKey)
if err != nil {
return false, err
}
block := &pem.Block{
Type: "CERTIFICATE REQUEST",
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 ReadCertificateFromMem(data []byte) (*Certificate, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("failed to decode certificate request")
}
return ParseCertificate(block.Bytes)
}
func ReadCertificateFromPem(FileName string) (*Certificate, error) {
data, err := ioutil.ReadFile(FileName)
if err != nil {
return nil, err
}
return ReadCertificateFromMem(data)
}
func CreateCertificateToMem(template, parent *Certificate, pubKey *PublicKey, privKey *PrivateKey) ([]byte, error) {
der, err := CreateCertificate(rand.Reader, template, parent, pubKey, privKey)
if err != nil {
return nil, err
}
block := &pem.Block{
Type: "CERTIFICATE",
Bytes: der,
}
return pem.EncodeToMemory(block), nil
}
func CreateCertificateToPem(FileName string, template, parent *Certificate, pubKey *PublicKey, privKey *PrivateKey) (bool, error) {
der, err := CreateCertificate(rand.Reader, template, parent, pubKey, privKey)
if err != nil {
return false, err
}
block := &pem.Block{
Type: "CERTIFICATE",
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
}
package sm3
// Sum256 returns the SM3 digest of the data.
func Sum256(data []byte) (digest [32]byte) {
hash := Sm3Sum(data)
copy(digest[:], hash)
return
}
// Sum calculate data into hash
func Sum(hash, data []byte) {
tmp := Sm3Sum(data)
copy(hash, tmp)
}
package sm3
import (
"encoding/binary"
"hash"
)
type SM3 struct {
digest [8]uint32 // digest represents the partial evaluation of V
length uint64 // length of the message
unhandleMsg []byte // uint8 //
}
func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z }
func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) }
func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z }
func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) }
func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) }
func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) }
func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return (x<<(i%32) | x>>(32-i%32)) }
func (sm3 *SM3) pad() []byte {
msg := sm3.unhandleMsg
msg = append(msg, 0x80) // Append '1'
blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512)
for len(msg)%blockSize != 56 {
msg = append(msg, 0x00)
}
// append message length
// not using loops so that compiler might benefit from it
msg = append(msg, uint8(sm3.length>>56&0xff))
msg = append(msg, uint8(sm3.length>>48&0xff))
msg = append(msg, uint8(sm3.length>>40&0xff))
msg = append(msg, uint8(sm3.length>>32&0xff))
msg = append(msg, uint8(sm3.length>>24&0xff))
msg = append(msg, uint8(sm3.length>>16&0xff))
msg = append(msg, uint8(sm3.length>>8&0xff))
msg = append(msg, uint8(sm3.length>>0&0xff))
if len(msg)%64 != 0 {
panic("------SM3 Pad: error msgLen =")
}
return msg
}
func (sm3 *SM3) update(msg []byte, nblocks int) {
var w [68]uint32
var w1 [64]uint32
a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
for len(msg) >= 64 {
for i := 0; i < 16; i++ {
w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
}
for i := 16; i < 68; i++ {
w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
}
for i := 0; i < 64; i++ {
w1[i] = w[i] ^ w[i+4]
}
A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
for i := 0; i < 16; i++ {
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
SS2 := SS1 ^ sm3.leftRotate(A, 12)
TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
D = C
C = sm3.leftRotate(B, 9)
B = A
A = TT1
H = G
G = sm3.leftRotate(F, 19)
F = E
E = sm3.p0(TT2)
}
for i := 16; i < 64; i++ {
SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
SS2 := SS1 ^ sm3.leftRotate(A, 12)
TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
D = C
C = sm3.leftRotate(B, 9)
B = A
A = TT1
H = G
G = sm3.leftRotate(F, 19)
F = E
E = sm3.p0(TT2)
}
a ^= A
b ^= B
c ^= C
d ^= D
e ^= E
f ^= F
g ^= G
h ^= H
msg = msg[64:]
}
sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h
}
func New() hash.Hash {
var sm3 SM3
sm3.Reset()
return &sm3
}
// BlockSize, required by the hash.Hash interface.
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all writes
// are a multiple of the block size.
func (sm3 *SM3) BlockSize() int { return 64 }
// Size, required by the hash.Hash interface.
// Size returns the number of bytes Sum will return.
func (sm3 *SM3) Size() int { return 32 }
// Reset clears the internal state by zeroing bytes in the state buffer.
// This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
func (sm3 *SM3) Reset() {
// Reset digest
sm3.digest[0] = 0x7380166f
sm3.digest[1] = 0x4914b2b9
sm3.digest[2] = 0x172442d7
sm3.digest[3] = 0xda8a0600
sm3.digest[4] = 0xa96f30bc
sm3.digest[5] = 0x163138aa
sm3.digest[6] = 0xe38dee4d
sm3.digest[7] = 0xb0fb0e4e
sm3.length = 0 // Reset numberic states
sm3.unhandleMsg = []byte{}
}
// Write, required by the hash.Hash interface.
// Write (via the embedded io.Writer interface) adds more data to the running hash.
// It never returns an error.
func (sm3 *SM3) Write(p []byte) (int, error) {
toWrite := len(p)
sm3.length += uint64(len(p) * 8)
msg := append(sm3.unhandleMsg, p...)
nblocks := len(msg) / sm3.BlockSize()
sm3.update(msg, nblocks)
// Update unhandleMsg
sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():]
return toWrite, nil
}
// Sum, required by the hash.Hash interface.
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
func (sm3 *SM3) Sum(in []byte) []byte {
sm3.Write(in)
msg := sm3.pad()
// Finialize
sm3.update(msg, len(msg)/sm3.BlockSize())
// save hash to in
needed := sm3.Size()
if cap(in)-len(in) < needed {
newIn := make([]byte, len(in), len(in)+needed)
copy(newIn, in)
in = newIn
}
out := in[len(in) : len(in)+needed]
for i := 0; i < 8; i++ {
binary.BigEndian.PutUint32(out[i*4:], sm3.digest[i])
}
return out
}
func Sm3Sum(data []byte) []byte {
var sm3 SM3
sm3.Reset()
sm3.Write(data)
return sm3.Sum(nil)
}
/*
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 sm3
import (
"fmt"
"io/ioutil"
"log"
"os"
"testing"
)
func byteToString(b []byte) string {
ret := ""
for i := 0; i < len(b); i++ {
ret += fmt.Sprintf("%02x", b[i])
}
fmt.Println("ret = ", ret)
return ret
}
func TestSm3(t *testing.T) {
msg := []byte("test")
err := ioutil.WriteFile("ifile", msg, os.FileMode(0644)) // 生成测试文件
if err != nil {
log.Fatal(err)
}
msg, err = ioutil.ReadFile("ifile")
if err != nil {
log.Fatal(err)
}
hw := New()
hw.Write(msg)
hash := hw.Sum(nil)
fmt.Println(hash)
fmt.Printf("hash = %d\n", len(hash))
fmt.Printf("%s\n", byteToString(hash))
hash1 := Sm3Sum(msg)
fmt.Println(hash1)
fmt.Printf("%s\n", byteToString(hash1))
}
func BenchmarkSm3(t *testing.B) {
t.ReportAllocs()
msg := []byte("test")
hw := New()
for i := 0; i < t.N; i++ {
hw.Sum(nil)
Sm3Sum(msg)
}
}
/*
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.
sm4 acceration
modified by Jack, 2017 Oct
*/
package sm4
import (
"crypto/cipher"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"errors"
"io/ioutil"
"os"
"strconv"
)
const BlockSize = 16
type SM4Key []byte
type KeySizeError int
// Cipher is an instance of SM4 encryption.
type Sm4Cipher struct {
subkeys []uint32
block1 []uint32
block2 []byte
}
// sm4密钥参量
var fk = [4]uint32{
0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc,
}
// sm4密钥参量
var ck = [32]uint32{
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
}
// sm4密钥参量
var sbox = [256]uint8{
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
}
var sbox0 = [256]uint32{
0xd55b5b8e, 0x924242d0, 0xeaa7a74d, 0xfdfbfb06, 0xcf3333fc, 0xe2878765, 0x3df4f4c9, 0xb5dede6b, 0x1658584e, 0xb4dada6e, 0x14505044, 0xc10b0bca, 0x28a0a088, 0xf8efef17, 0x2cb0b09c, 0x05141411,
0x2bacac87, 0x669d9dfb, 0x986a6af2, 0x77d9d9ae, 0x2aa8a882, 0xbcfafa46, 0x04101014, 0xc00f0fcf, 0xa8aaaa02, 0x45111154, 0x134c4c5f, 0x269898be, 0x4825256d, 0x841a1a9e, 0x0618181e, 0x9b6666fd,
0x9e7272ec, 0x4309094a, 0x51414110, 0xf7d3d324, 0x934646d5, 0xecbfbf53, 0x9a6262f8, 0x7be9e992, 0x33ccccff, 0x55515104, 0x0b2c2c27, 0x420d0d4f, 0xeeb7b759, 0xcc3f3ff3, 0xaeb2b21c, 0x638989ea,
0xe7939374, 0xb1cece7f, 0x1c70706c, 0xaba6a60d, 0xca2727ed, 0x08202028, 0xeba3a348, 0x975656c1, 0x82020280, 0xdc7f7fa3, 0x965252c4, 0xf9ebeb12, 0x74d5d5a1, 0x8d3e3eb3, 0x3ffcfcc3, 0xa49a9a3e,
0x461d1d5b, 0x071c1c1b, 0xa59e9e3b, 0xfff3f30c, 0xf0cfcf3f, 0x72cdcdbf, 0x175c5c4b, 0xb8eaea52, 0x810e0e8f, 0x5865653d, 0x3cf0f0cc, 0x1964647d, 0xe59b9b7e, 0x87161691, 0x4e3d3d73, 0xaaa2a208,
0x69a1a1c8, 0x6aadadc7, 0x83060685, 0xb0caca7a, 0x70c5c5b5, 0x659191f4, 0xd96b6bb2, 0x892e2ea7, 0xfbe3e318, 0xe8afaf47, 0x0f3c3c33, 0x4a2d2d67, 0x71c1c1b0, 0x5759590e, 0x9f7676e9, 0x35d4d4e1,
0x1e787866, 0x249090b4, 0x0e383836, 0x5f797926, 0x628d8def, 0x59616138, 0xd2474795, 0xa08a8a2a, 0x259494b1, 0x228888aa, 0x7df1f18c, 0x3bececd7, 0x01040405, 0x218484a5, 0x79e1e198, 0x851e1e9b,
0xd7535384, 0x00000000, 0x4719195e, 0x565d5d0b, 0x9d7e7ee3, 0xd04f4f9f, 0x279c9cbb, 0x5349491a, 0x4d31317c, 0x36d8d8ee, 0x0208080a, 0xe49f9f7b, 0xa2828220, 0xc71313d4, 0xcb2323e8, 0x9c7a7ae6,
0xe9abab42, 0xbdfefe43, 0x882a2aa2, 0xd14b4b9a, 0x41010140, 0xc41f1fdb, 0x38e0e0d8, 0xb7d6d661, 0xa18e8e2f, 0xf4dfdf2b, 0xf1cbcb3a, 0xcd3b3bf6, 0xfae7e71d, 0x608585e5, 0x15545441, 0xa3868625,
0xe3838360, 0xacbaba16, 0x5c757529, 0xa6929234, 0x996e6ef7, 0x34d0d0e4, 0x1a686872, 0x54555501, 0xafb6b619, 0x914e4edf, 0x32c8c8fa, 0x30c0c0f0, 0xf6d7d721, 0x8e3232bc, 0xb3c6c675, 0xe08f8f6f,
0x1d747469, 0xf5dbdb2e, 0xe18b8b6a, 0x2eb8b896, 0x800a0a8a, 0x679999fe, 0xc92b2be2, 0x618181e0, 0xc30303c0, 0x29a4a48d, 0x238c8caf, 0xa9aeae07, 0x0d343439, 0x524d4d1f, 0x4f393976, 0x6ebdbdd3,
0xd6575781, 0xd86f6fb7, 0x37dcdceb, 0x44151551, 0xdd7b7ba6, 0xfef7f709, 0x8c3a3ab6, 0x2fbcbc93, 0x030c0c0f, 0xfcffff03, 0x6ba9a9c2, 0x73c9c9ba, 0x6cb5b5d9, 0x6db1b1dc, 0x5a6d6d37, 0x50454515,
0x8f3636b9, 0x1b6c6c77, 0xadbebe13, 0x904a4ada, 0xb9eeee57, 0xde7777a9, 0xbef2f24c, 0x7efdfd83, 0x11444455, 0xda6767bd, 0x5d71712c, 0x40050545, 0x1f7c7c63, 0x10404050, 0x5b696932, 0xdb6363b8,
0x0a282822, 0xc20707c5, 0x31c4c4f5, 0x8a2222a8, 0xa7969631, 0xce3737f9, 0x7aeded97, 0xbff6f649, 0x2db4b499, 0x75d1d1a4, 0xd3434390, 0x1248485a, 0xbae2e258, 0xe6979771, 0xb6d2d264, 0xb2c2c270,
0x8b2626ad, 0x68a5a5cd, 0x955e5ecb, 0x4b292962, 0x0c30303c, 0x945a5ace, 0x76ddddab, 0x7ff9f986, 0x649595f1, 0xbbe6e65d, 0xf2c7c735, 0x0924242d, 0xc61717d1, 0x6fb9b9d6, 0xc51b1bde, 0x86121294,
0x18606078, 0xf3c3c330, 0x7cf5f589, 0xefb3b35c, 0x3ae8e8d2, 0xdf7373ac, 0x4c353579, 0x208080a0, 0x78e5e59d, 0xedbbbb56, 0x5e7d7d23, 0x3ef8f8c6, 0xd45f5f8b, 0xc82f2fe7, 0x39e4e4dd, 0x49212168,
}
var sbox1 = [256]uint32{
0x5b5b8ed5, 0x4242d092, 0xa7a74dea, 0xfbfb06fd, 0x3333fccf, 0x878765e2, 0xf4f4c93d, 0xdede6bb5, 0x58584e16, 0xdada6eb4, 0x50504414, 0x0b0bcac1, 0xa0a08828, 0xefef17f8, 0xb0b09c2c, 0x14141105,
0xacac872b, 0x9d9dfb66, 0x6a6af298, 0xd9d9ae77, 0xa8a8822a, 0xfafa46bc, 0x10101404, 0x0f0fcfc0, 0xaaaa02a8, 0x11115445, 0x4c4c5f13, 0x9898be26, 0x25256d48, 0x1a1a9e84, 0x18181e06, 0x6666fd9b,
0x7272ec9e, 0x09094a43, 0x41411051, 0xd3d324f7, 0x4646d593, 0xbfbf53ec, 0x6262f89a, 0xe9e9927b, 0xccccff33, 0x51510455, 0x2c2c270b, 0x0d0d4f42, 0xb7b759ee, 0x3f3ff3cc, 0xb2b21cae, 0x8989ea63,
0x939374e7, 0xcece7fb1, 0x70706c1c, 0xa6a60dab, 0x2727edca, 0x20202808, 0xa3a348eb, 0x5656c197, 0x02028082, 0x7f7fa3dc, 0x5252c496, 0xebeb12f9, 0xd5d5a174, 0x3e3eb38d, 0xfcfcc33f, 0x9a9a3ea4,
0x1d1d5b46, 0x1c1c1b07, 0x9e9e3ba5, 0xf3f30cff, 0xcfcf3ff0, 0xcdcdbf72, 0x5c5c4b17, 0xeaea52b8, 0x0e0e8f81, 0x65653d58, 0xf0f0cc3c, 0x64647d19, 0x9b9b7ee5, 0x16169187, 0x3d3d734e, 0xa2a208aa,
0xa1a1c869, 0xadadc76a, 0x06068583, 0xcaca7ab0, 0xc5c5b570, 0x9191f465, 0x6b6bb2d9, 0x2e2ea789, 0xe3e318fb, 0xafaf47e8, 0x3c3c330f, 0x2d2d674a, 0xc1c1b071, 0x59590e57, 0x7676e99f, 0xd4d4e135,
0x7878661e, 0x9090b424, 0x3838360e, 0x7979265f, 0x8d8def62, 0x61613859, 0x474795d2, 0x8a8a2aa0, 0x9494b125, 0x8888aa22, 0xf1f18c7d, 0xececd73b, 0x04040501, 0x8484a521, 0xe1e19879, 0x1e1e9b85,
0x535384d7, 0x00000000, 0x19195e47, 0x5d5d0b56, 0x7e7ee39d, 0x4f4f9fd0, 0x9c9cbb27, 0x49491a53, 0x31317c4d, 0xd8d8ee36, 0x08080a02, 0x9f9f7be4, 0x828220a2, 0x1313d4c7, 0x2323e8cb, 0x7a7ae69c,
0xabab42e9, 0xfefe43bd, 0x2a2aa288, 0x4b4b9ad1, 0x01014041, 0x1f1fdbc4, 0xe0e0d838, 0xd6d661b7, 0x8e8e2fa1, 0xdfdf2bf4, 0xcbcb3af1, 0x3b3bf6cd, 0xe7e71dfa, 0x8585e560, 0x54544115, 0x868625a3,
0x838360e3, 0xbaba16ac, 0x7575295c, 0x929234a6, 0x6e6ef799, 0xd0d0e434, 0x6868721a, 0x55550154, 0xb6b619af, 0x4e4edf91, 0xc8c8fa32, 0xc0c0f030, 0xd7d721f6, 0x3232bc8e, 0xc6c675b3, 0x8f8f6fe0,
0x7474691d, 0xdbdb2ef5, 0x8b8b6ae1, 0xb8b8962e, 0x0a0a8a80, 0x9999fe67, 0x2b2be2c9, 0x8181e061, 0x0303c0c3, 0xa4a48d29, 0x8c8caf23, 0xaeae07a9, 0x3434390d, 0x4d4d1f52, 0x3939764f, 0xbdbdd36e,
0x575781d6, 0x6f6fb7d8, 0xdcdceb37, 0x15155144, 0x7b7ba6dd, 0xf7f709fe, 0x3a3ab68c, 0xbcbc932f, 0x0c0c0f03, 0xffff03fc, 0xa9a9c26b, 0xc9c9ba73, 0xb5b5d96c, 0xb1b1dc6d, 0x6d6d375a, 0x45451550,
0x3636b98f, 0x6c6c771b, 0xbebe13ad, 0x4a4ada90, 0xeeee57b9, 0x7777a9de, 0xf2f24cbe, 0xfdfd837e, 0x44445511, 0x6767bdda, 0x71712c5d, 0x05054540, 0x7c7c631f, 0x40405010, 0x6969325b, 0x6363b8db,
0x2828220a, 0x0707c5c2, 0xc4c4f531, 0x2222a88a, 0x969631a7, 0x3737f9ce, 0xeded977a, 0xf6f649bf, 0xb4b4992d, 0xd1d1a475, 0x434390d3, 0x48485a12, 0xe2e258ba, 0x979771e6, 0xd2d264b6, 0xc2c270b2,
0x2626ad8b, 0xa5a5cd68, 0x5e5ecb95, 0x2929624b, 0x30303c0c, 0x5a5ace94, 0xddddab76, 0xf9f9867f, 0x9595f164, 0xe6e65dbb, 0xc7c735f2, 0x24242d09, 0x1717d1c6, 0xb9b9d66f, 0x1b1bdec5, 0x12129486,
0x60607818, 0xc3c330f3, 0xf5f5897c, 0xb3b35cef, 0xe8e8d23a, 0x7373acdf, 0x3535794c, 0x8080a020, 0xe5e59d78, 0xbbbb56ed, 0x7d7d235e, 0xf8f8c63e, 0x5f5f8bd4, 0x2f2fe7c8, 0xe4e4dd39, 0x21216849,
}
var sbox2 = [256]uint32{
0x5b8ed55b, 0x42d09242, 0xa74deaa7, 0xfb06fdfb, 0x33fccf33, 0x8765e287, 0xf4c93df4, 0xde6bb5de, 0x584e1658, 0xda6eb4da, 0x50441450, 0x0bcac10b, 0xa08828a0, 0xef17f8ef, 0xb09c2cb0, 0x14110514,
0xac872bac, 0x9dfb669d, 0x6af2986a, 0xd9ae77d9, 0xa8822aa8, 0xfa46bcfa, 0x10140410, 0x0fcfc00f, 0xaa02a8aa, 0x11544511, 0x4c5f134c, 0x98be2698, 0x256d4825, 0x1a9e841a, 0x181e0618, 0x66fd9b66,
0x72ec9e72, 0x094a4309, 0x41105141, 0xd324f7d3, 0x46d59346, 0xbf53ecbf, 0x62f89a62, 0xe9927be9, 0xccff33cc, 0x51045551, 0x2c270b2c, 0x0d4f420d, 0xb759eeb7, 0x3ff3cc3f, 0xb21caeb2, 0x89ea6389,
0x9374e793, 0xce7fb1ce, 0x706c1c70, 0xa60daba6, 0x27edca27, 0x20280820, 0xa348eba3, 0x56c19756, 0x02808202, 0x7fa3dc7f, 0x52c49652, 0xeb12f9eb, 0xd5a174d5, 0x3eb38d3e, 0xfcc33ffc, 0x9a3ea49a,
0x1d5b461d, 0x1c1b071c, 0x9e3ba59e, 0xf30cfff3, 0xcf3ff0cf, 0xcdbf72cd, 0x5c4b175c, 0xea52b8ea, 0x0e8f810e, 0x653d5865, 0xf0cc3cf0, 0x647d1964, 0x9b7ee59b, 0x16918716, 0x3d734e3d, 0xa208aaa2,
0xa1c869a1, 0xadc76aad, 0x06858306, 0xca7ab0ca, 0xc5b570c5, 0x91f46591, 0x6bb2d96b, 0x2ea7892e, 0xe318fbe3, 0xaf47e8af, 0x3c330f3c, 0x2d674a2d, 0xc1b071c1, 0x590e5759, 0x76e99f76, 0xd4e135d4,
0x78661e78, 0x90b42490, 0x38360e38, 0x79265f79, 0x8def628d, 0x61385961, 0x4795d247, 0x8a2aa08a, 0x94b12594, 0x88aa2288, 0xf18c7df1, 0xecd73bec, 0x04050104, 0x84a52184, 0xe19879e1, 0x1e9b851e,
0x5384d753, 0x00000000, 0x195e4719, 0x5d0b565d, 0x7ee39d7e, 0x4f9fd04f, 0x9cbb279c, 0x491a5349, 0x317c4d31, 0xd8ee36d8, 0x080a0208, 0x9f7be49f, 0x8220a282, 0x13d4c713, 0x23e8cb23, 0x7ae69c7a,
0xab42e9ab, 0xfe43bdfe, 0x2aa2882a, 0x4b9ad14b, 0x01404101, 0x1fdbc41f, 0xe0d838e0, 0xd661b7d6, 0x8e2fa18e, 0xdf2bf4df, 0xcb3af1cb, 0x3bf6cd3b, 0xe71dfae7, 0x85e56085, 0x54411554, 0x8625a386,
0x8360e383, 0xba16acba, 0x75295c75, 0x9234a692, 0x6ef7996e, 0xd0e434d0, 0x68721a68, 0x55015455, 0xb619afb6, 0x4edf914e, 0xc8fa32c8, 0xc0f030c0, 0xd721f6d7, 0x32bc8e32, 0xc675b3c6, 0x8f6fe08f,
0x74691d74, 0xdb2ef5db, 0x8b6ae18b, 0xb8962eb8, 0x0a8a800a, 0x99fe6799, 0x2be2c92b, 0x81e06181, 0x03c0c303, 0xa48d29a4, 0x8caf238c, 0xae07a9ae, 0x34390d34, 0x4d1f524d, 0x39764f39, 0xbdd36ebd,
0x5781d657, 0x6fb7d86f, 0xdceb37dc, 0x15514415, 0x7ba6dd7b, 0xf709fef7, 0x3ab68c3a, 0xbc932fbc, 0x0c0f030c, 0xff03fcff, 0xa9c26ba9, 0xc9ba73c9, 0xb5d96cb5, 0xb1dc6db1, 0x6d375a6d, 0x45155045,
0x36b98f36, 0x6c771b6c, 0xbe13adbe, 0x4ada904a, 0xee57b9ee, 0x77a9de77, 0xf24cbef2, 0xfd837efd, 0x44551144, 0x67bdda67, 0x712c5d71, 0x05454005, 0x7c631f7c, 0x40501040, 0x69325b69, 0x63b8db63,
0x28220a28, 0x07c5c207, 0xc4f531c4, 0x22a88a22, 0x9631a796, 0x37f9ce37, 0xed977aed, 0xf649bff6, 0xb4992db4, 0xd1a475d1, 0x4390d343, 0x485a1248, 0xe258bae2, 0x9771e697, 0xd264b6d2, 0xc270b2c2,
0x26ad8b26, 0xa5cd68a5, 0x5ecb955e, 0x29624b29, 0x303c0c30, 0x5ace945a, 0xddab76dd, 0xf9867ff9, 0x95f16495, 0xe65dbbe6, 0xc735f2c7, 0x242d0924, 0x17d1c617, 0xb9d66fb9, 0x1bdec51b, 0x12948612,
0x60781860, 0xc330f3c3, 0xf5897cf5, 0xb35cefb3, 0xe8d23ae8, 0x73acdf73, 0x35794c35, 0x80a02080, 0xe59d78e5, 0xbb56edbb, 0x7d235e7d, 0xf8c63ef8, 0x5f8bd45f, 0x2fe7c82f, 0xe4dd39e4, 0x21684921,
}
var sbox3 = [256]uint32{
0x8ed55b5b, 0xd0924242, 0x4deaa7a7, 0x06fdfbfb, 0xfccf3333, 0x65e28787, 0xc93df4f4, 0x6bb5dede, 0x4e165858, 0x6eb4dada, 0x44145050, 0xcac10b0b, 0x8828a0a0, 0x17f8efef, 0x9c2cb0b0, 0x11051414,
0x872bacac, 0xfb669d9d, 0xf2986a6a, 0xae77d9d9, 0x822aa8a8, 0x46bcfafa, 0x14041010, 0xcfc00f0f, 0x02a8aaaa, 0x54451111, 0x5f134c4c, 0xbe269898, 0x6d482525, 0x9e841a1a, 0x1e061818, 0xfd9b6666,
0xec9e7272, 0x4a430909, 0x10514141, 0x24f7d3d3, 0xd5934646, 0x53ecbfbf, 0xf89a6262, 0x927be9e9, 0xff33cccc, 0x04555151, 0x270b2c2c, 0x4f420d0d, 0x59eeb7b7, 0xf3cc3f3f, 0x1caeb2b2, 0xea638989,
0x74e79393, 0x7fb1cece, 0x6c1c7070, 0x0daba6a6, 0xedca2727, 0x28082020, 0x48eba3a3, 0xc1975656, 0x80820202, 0xa3dc7f7f, 0xc4965252, 0x12f9ebeb, 0xa174d5d5, 0xb38d3e3e, 0xc33ffcfc, 0x3ea49a9a,
0x5b461d1d, 0x1b071c1c, 0x3ba59e9e, 0x0cfff3f3, 0x3ff0cfcf, 0xbf72cdcd, 0x4b175c5c, 0x52b8eaea, 0x8f810e0e, 0x3d586565, 0xcc3cf0f0, 0x7d196464, 0x7ee59b9b, 0x91871616, 0x734e3d3d, 0x08aaa2a2,
0xc869a1a1, 0xc76aadad, 0x85830606, 0x7ab0caca, 0xb570c5c5, 0xf4659191, 0xb2d96b6b, 0xa7892e2e, 0x18fbe3e3, 0x47e8afaf, 0x330f3c3c, 0x674a2d2d, 0xb071c1c1, 0x0e575959, 0xe99f7676, 0xe135d4d4,
0x661e7878, 0xb4249090, 0x360e3838, 0x265f7979, 0xef628d8d, 0x38596161, 0x95d24747, 0x2aa08a8a, 0xb1259494, 0xaa228888, 0x8c7df1f1, 0xd73becec, 0x05010404, 0xa5218484, 0x9879e1e1, 0x9b851e1e,
0x84d75353, 0x00000000, 0x5e471919, 0x0b565d5d, 0xe39d7e7e, 0x9fd04f4f, 0xbb279c9c, 0x1a534949, 0x7c4d3131, 0xee36d8d8, 0x0a020808, 0x7be49f9f, 0x20a28282, 0xd4c71313, 0xe8cb2323, 0xe69c7a7a,
0x42e9abab, 0x43bdfefe, 0xa2882a2a, 0x9ad14b4b, 0x40410101, 0xdbc41f1f, 0xd838e0e0, 0x61b7d6d6, 0x2fa18e8e, 0x2bf4dfdf, 0x3af1cbcb, 0xf6cd3b3b, 0x1dfae7e7, 0xe5608585, 0x41155454, 0x25a38686,
0x60e38383, 0x16acbaba, 0x295c7575, 0x34a69292, 0xf7996e6e, 0xe434d0d0, 0x721a6868, 0x01545555, 0x19afb6b6, 0xdf914e4e, 0xfa32c8c8, 0xf030c0c0, 0x21f6d7d7, 0xbc8e3232, 0x75b3c6c6, 0x6fe08f8f,
0x691d7474, 0x2ef5dbdb, 0x6ae18b8b, 0x962eb8b8, 0x8a800a0a, 0xfe679999, 0xe2c92b2b, 0xe0618181, 0xc0c30303, 0x8d29a4a4, 0xaf238c8c, 0x07a9aeae, 0x390d3434, 0x1f524d4d, 0x764f3939, 0xd36ebdbd,
0x81d65757, 0xb7d86f6f, 0xeb37dcdc, 0x51441515, 0xa6dd7b7b, 0x09fef7f7, 0xb68c3a3a, 0x932fbcbc, 0x0f030c0c, 0x03fcffff, 0xc26ba9a9, 0xba73c9c9, 0xd96cb5b5, 0xdc6db1b1, 0x375a6d6d, 0x15504545,
0xb98f3636, 0x771b6c6c, 0x13adbebe, 0xda904a4a, 0x57b9eeee, 0xa9de7777, 0x4cbef2f2, 0x837efdfd, 0x55114444, 0xbdda6767, 0x2c5d7171, 0x45400505, 0x631f7c7c, 0x50104040, 0x325b6969, 0xb8db6363,
0x220a2828, 0xc5c20707, 0xf531c4c4, 0xa88a2222, 0x31a79696, 0xf9ce3737, 0x977aeded, 0x49bff6f6, 0x992db4b4, 0xa475d1d1, 0x90d34343, 0x5a124848, 0x58bae2e2, 0x71e69797, 0x64b6d2d2, 0x70b2c2c2,
0xad8b2626, 0xcd68a5a5, 0xcb955e5e, 0x624b2929, 0x3c0c3030, 0xce945a5a, 0xab76dddd, 0x867ff9f9, 0xf1649595, 0x5dbbe6e6, 0x35f2c7c7, 0x2d092424, 0xd1c61717, 0xd66fb9b9, 0xdec51b1b, 0x94861212,
0x78186060, 0x30f3c3c3, 0x897cf5f5, 0x5cefb3b3, 0xd23ae8e8, 0xacdf7373, 0x794c3535, 0xa0208080, 0x9d78e5e5, 0x56edbbbb, 0x235e7d7d, 0xc63ef8f8, 0x8bd45f5f, 0xe7c82f2f, 0xdd39e4e4, 0x68492121,
}
func rl(x uint32, i uint8) uint32 { return (x << (i % 32)) | (x >> (32 - (i % 32))) }
func l0(b uint32) uint32 { return b ^ rl(b, 13) ^ rl(b, 23) }
func feistel0(x0, x1, x2, x3, rk uint32) uint32 { return x0 ^ l0(p(x1^x2^x3^rk)) }
//非线性变换τ(.)
func p(a uint32) uint32 {
return (uint32(sbox[a>>24]) << 24) ^ (uint32(sbox[(a>>16)&0xff]) << 16) ^ (uint32(sbox[(a>>8)&0xff]) << 8) ^ uint32(sbox[(a)&0xff])
}
func permuteInitialBlock(b []uint32, block []byte) {
for i := 0; i < 4; i++ {
b[i] = (uint32(block[i*4]) << 24) | (uint32(block[i*4+1]) << 16) |
(uint32(block[i*4+2]) << 8) | (uint32(block[i*4+3]))
}
}
func permuteFinalBlock(b []byte, block []uint32) {
for i := 0; i < 4; i++ {
b[i*4] = uint8(block[i] >> 24)
b[i*4+1] = uint8(block[i] >> 16)
b[i*4+2] = uint8(block[i] >> 8)
b[i*4+3] = uint8(block[i])
}
}
//修改后的加密核心函数
func cryptBlock(subkeys []uint32, b []uint32, r []byte, dst, src []byte, decrypt bool) {
var x uint32
permuteInitialBlock(b, src)
if decrypt {
for i := 0; i < 8; i++ {
x = b[1] ^ b[2] ^ b[3] ^ subkeys[31-4*i]
b[0] = b[0] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
x = b[0] ^ b[2] ^ b[3] ^ subkeys[31-4*i-1]
b[1] = b[1] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
x = b[0] ^ b[1] ^ b[3] ^ subkeys[31-4*i-2]
b[2] = b[2] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
x = b[1] ^ b[2] ^ b[0] ^ subkeys[31-4*i-3]
b[3] = b[3] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
}
} else {
for i := 0; i < 8; i++ {
x = b[1] ^ b[2] ^ b[3] ^ subkeys[4*i]
b[0] = b[0] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
x = b[0] ^ b[2] ^ b[3] ^ subkeys[4*i+1]
b[1] = b[1] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
x = b[0] ^ b[1] ^ b[3] ^ subkeys[4*i+2]
b[2] = b[2] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
x = b[1] ^ b[2] ^ b[0] ^ subkeys[4*i+3]
b[3] = b[3] ^ sbox0[x&0xff] ^ sbox1[(x>>8)&0xff] ^ sbox2[(x>>16)&0xff] ^ sbox3[(x>>24)&0xff]
}
}
b[0], b[1], b[2], b[3] = b[3], b[2], b[1], b[0]
permuteFinalBlock(r, b)
copy(dst, r)
}
func generateSubKeys(key []byte) []uint32 {
subkeys := make([]uint32, 32)
b := make([]uint32, 4)
permuteInitialBlock(b, key)
b[0] ^= fk[0]
b[1] ^= fk[1]
b[2] ^= fk[2]
b[3] ^= fk[3]
for i := 0; i < 32; i++ {
subkeys[i] = feistel0(b[0], b[1], b[2], b[3], ck[i])
b[0], b[1], b[2], b[3] = b[1], b[2], b[3], subkeys[i]
}
return subkeys
}
func EncryptBlock(key SM4Key, dst, src []byte) {
subkeys := generateSubKeys(key)
cryptBlock(subkeys, make([]uint32, 4), make([]byte, 16), dst, src, false)
}
func DecryptBlock(key SM4Key, dst, src []byte) {
subkeys := generateSubKeys(key)
cryptBlock(subkeys, make([]uint32, 4), make([]byte, 16), dst, src, true)
}
func ReadKeyFromMem(data []byte, pwd []byte) (SM4Key, error) {
block, _ := pem.Decode(data)
if x509.IsEncryptedPEMBlock(block) {
if block.Type != "SM4 ENCRYPTED KEY" {
return nil, errors.New("SM4: unknown type")
}
if pwd == nil {
return nil, errors.New("SM4: need passwd")
}
data, err := x509.DecryptPEMBlock(block, pwd)
if err != nil {
return nil, err
}
return data, nil
}
if block.Type != "SM4 KEY" {
return nil, errors.New("SM4: unknown type")
}
return block.Bytes, nil
}
func ReadKeyFromPem(FileName string, pwd []byte) (SM4Key, error) {
data, err := ioutil.ReadFile(FileName)
if err != nil {
return nil, err
}
return ReadKeyFromMem(data, pwd)
}
func WriteKeytoMem(key SM4Key, pwd []byte) ([]byte, error) {
if pwd != nil {
block, err := x509.EncryptPEMBlock(rand.Reader,
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(block), nil
} else {
block := &pem.Block{
Type: "SM4 KEY",
Bytes: key,
}
return pem.EncodeToMemory(block), nil
}
}
func WriteKeyToPem(FileName string, key SM4Key, pwd []byte) (bool, error) {
var block *pem.Block
if pwd != nil {
var err error
block, err = x509.EncryptPEMBlock(rand.Reader,
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
if err != nil {
return false, err
}
} else {
block = &pem.Block{
Type: "SM4 KEY",
Bytes: key,
}
}
file, err := os.Create(FileName)
if err != nil {
return false, err
}
defer file.Close()
err = pem.Encode(file, block)
if err != nil {
return false, nil
}
return true, nil
}
func (k KeySizeError) Error() string {
return "SM4: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a new cipher.Block.
func NewCipher(key []byte) (cipher.Block, error) {
if len(key) != BlockSize {
return nil, KeySizeError(len(key))
}
c := new(Sm4Cipher)
c.subkeys = generateSubKeys(key)
c.block1 = make([]uint32, 4)
c.block2 = make([]byte, 16)
return c, nil
}
func (c *Sm4Cipher) BlockSize() int {
return BlockSize
}
func (c *Sm4Cipher) Encrypt(dst, src []byte) {
cryptBlock(c.subkeys, c.block1, c.block2, dst, src, false)
}
func (c *Sm4Cipher) Decrypt(dst, src []byte) {
cryptBlock(c.subkeys, c.block1, c.block2, dst, src, true)
}
/*
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 sm4
import (
"fmt"
"log"
"reflect"
"testing"
)
func TestSM4(t *testing.T) {
key := []byte("1234567890abcdef")
fmt.Printf("key = %v\n", key)
data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
WriteKeyToPem("key.pem", key, nil)
key, err := ReadKeyFromPem("key.pem", nil)
fmt.Printf("key = %v\n", key)
if err != nil {
log.Fatal(err)
}
fmt.Printf("data = %x\n", data)
c, err := NewCipher(key)
if err != nil {
log.Fatal(err)
}
d0 := make([]byte, 16)
c.Encrypt(d0, data)
fmt.Printf("d0 = %x\n", d0)
d1 := make([]byte, 16)
c.Decrypt(d1, d0)
fmt.Printf("d1 = %x\n", d1)
if sa := testCompare(data, d1); sa != true {
fmt.Printf("Error data!")
}
}
func BenchmarkSM4(t *testing.B) {
t.ReportAllocs()
key := []byte("1234567890abcdef")
data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
WriteKeyToPem("key.pem", key, nil)
key, err := ReadKeyFromPem("key.pem", nil)
if err != nil {
log.Fatal(err)
}
c, err := NewCipher(key)
if err != nil {
log.Fatal(err)
}
for i := 0; i < t.N; i++ {
d0 := make([]byte, 16)
c.Encrypt(d0, data)
d1 := make([]byte, 16)
c.Decrypt(d1, d0)
}
}
func TestErrKeyLen(t *testing.T) {
fmt.Printf("\n--------------test key len------------------")
key := []byte("1234567890abcdefg")
_, err := NewCipher(key)
if err != nil {
fmt.Println("\nError key len !")
}
key = []byte("1234")
_, err = NewCipher(key)
if err != nil {
fmt.Println("Error key len !")
}
fmt.Println("------------------end----------------------")
}
func testCompare(key1, key2 []byte) bool {
if len(key1) != len(key2) {
return false
}
for i, v := range key1 {
if i == 1 {
fmt.Println("type of v", reflect.TypeOf(v))
}
a := key2[i]
if a != v {
return false
}
}
return true
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment