You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
6.5 KiB
275 lines
6.5 KiB
|
2 months ago
|
package base
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/dsa"
|
||
|
|
"crypto/rand"
|
||
|
|
"crypto/sha1"
|
||
|
|
"crypto/x509/pkix"
|
||
|
|
"encoding/asn1"
|
||
|
|
"encoding/base64"
|
||
|
|
"errors"
|
||
|
|
"fmt"
|
||
|
|
"math/big"
|
||
|
|
)
|
||
|
|
|
||
|
|
// 签名结构体
|
||
|
|
type dsaSignature struct {
|
||
|
|
R, S *big.Int
|
||
|
|
}
|
||
|
|
|
||
|
|
// 公钥结构体(ASN.1 编码)
|
||
|
|
type dsaPublicKey struct {
|
||
|
|
P, Q, G, Y *big.Int
|
||
|
|
}
|
||
|
|
|
||
|
|
// 私钥结构体(ASN.1 编码)
|
||
|
|
type dsaPrivateKey struct {
|
||
|
|
Public dsaPublicKey
|
||
|
|
X *big.Int
|
||
|
|
}
|
||
|
|
|
||
|
|
// GenerateKeyPairBase64 生成 DSA 密钥对(返回 Base64 编码)
|
||
|
|
func GenerateKeyPairBase64() (string, string, error) {
|
||
|
|
var params dsa.Parameters
|
||
|
|
if err := dsa.GenerateParameters(¶ms, rand.Reader, dsa.L1024N160); err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
priv := new(dsa.PrivateKey)
|
||
|
|
priv.Parameters = params
|
||
|
|
if err := dsa.GenerateKey(priv, rand.Reader); err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
pubEnc := dsaPublicKey{
|
||
|
|
P: priv.P,
|
||
|
|
Q: priv.Q,
|
||
|
|
G: priv.G,
|
||
|
|
Y: priv.Y,
|
||
|
|
}
|
||
|
|
privEnc := dsaPrivateKey{
|
||
|
|
Public: pubEnc,
|
||
|
|
X: priv.X,
|
||
|
|
}
|
||
|
|
|
||
|
|
pubBytes, _ := asn1.Marshal(pubEnc)
|
||
|
|
privBytes, _ := asn1.Marshal(privEnc)
|
||
|
|
|
||
|
|
pubB64 := base64.StdEncoding.EncodeToString(pubBytes)
|
||
|
|
privB64 := base64.StdEncoding.EncodeToString(privBytes)
|
||
|
|
return pubB64, privB64, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// 解码 Base64 公钥
|
||
|
|
// func decodePublicKey(pubB64 string) (*dsa.PublicKey, error) {
|
||
|
|
// data, err := base64.StdEncoding.DecodeString(pubB64)
|
||
|
|
// if err != nil {
|
||
|
|
// return nil, err
|
||
|
|
// }
|
||
|
|
// var pk dsaPublicKey
|
||
|
|
// if _, err := asn1.Unmarshal(data, &pk); err != nil {
|
||
|
|
// return nil, err
|
||
|
|
// }
|
||
|
|
|
||
|
|
// pub := &dsa.PublicKey{}
|
||
|
|
// pub.Y = pk.Y
|
||
|
|
// pub.Parameters.P = pk.P
|
||
|
|
// pub.Parameters.Q = pk.Q
|
||
|
|
// pub.Parameters.G = pk.G
|
||
|
|
// return pub, nil
|
||
|
|
// }
|
||
|
|
|
||
|
|
// 解码 Base64 私钥
|
||
|
|
// func decodePrivateKey(privB64 string) (*dsa.PrivateKey, error) {
|
||
|
|
// data, err := base64.StdEncoding.DecodeString(privB64)
|
||
|
|
// if err != nil {
|
||
|
|
// return nil, err
|
||
|
|
// }
|
||
|
|
// var sk dsaPrivateKey
|
||
|
|
// if _, err := asn1.Unmarshal(data, &sk); err != nil {
|
||
|
|
// return nil, err
|
||
|
|
// }
|
||
|
|
// priv := &dsa.PrivateKey{}
|
||
|
|
// priv.X = sk.X
|
||
|
|
// priv.PublicKey.Y = sk.Public.Y
|
||
|
|
// priv.PublicKey.Parameters.P = sk.Public.P
|
||
|
|
// priv.PublicKey.Parameters.Q = sk.Public.Q
|
||
|
|
// priv.PublicKey.Parameters.G = sk.Public.G
|
||
|
|
// return priv, nil
|
||
|
|
// // key, err := x509.ParsePKCS8PrivateKey(data)
|
||
|
|
// // if err != nil {
|
||
|
|
// // panic("ParsePKCS8PrivateKey error: " + err.Error())
|
||
|
|
// // }
|
||
|
|
|
||
|
|
// // // 3. 断言为DSA私钥类型
|
||
|
|
// // dsaPrivKey, ok := key.(*dsa.PrivateKey)
|
||
|
|
// // if !ok {
|
||
|
|
// // panic("Not a DSA private key")
|
||
|
|
// // }
|
||
|
|
// // return dsaPrivKey, nil
|
||
|
|
// }
|
||
|
|
|
||
|
|
// SignDsa 使用 Base64 私钥对消息签名
|
||
|
|
func SignDsa(message, privB64 string) (string, error) {
|
||
|
|
priv, err := decodePKCS8DSAPrivateKey(privB64)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
hash := sha1.Sum([]byte(message))
|
||
|
|
r, s, err := dsa.Sign(rand.Reader, priv, hash[:])
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
sigBytes, _ := asn1.Marshal(dsaSignature{r, s})
|
||
|
|
return base64.StdEncoding.EncodeToString(sigBytes), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// VerifyDsa 使用 Base64 公钥验证签名
|
||
|
|
func VerifyDsa(message, sigB64, pubB64 string) (bool, error) {
|
||
|
|
pub, err := decodeDSAPublicKey(pubB64)
|
||
|
|
if err != nil {
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
sigBytes, err := base64.StdEncoding.DecodeString(sigB64)
|
||
|
|
if err != nil {
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
var sig dsaSignature
|
||
|
|
if _, err := asn1.Unmarshal(sigBytes, &sig); err != nil {
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
hash := sha1.Sum([]byte(message))
|
||
|
|
return dsa.Verify(pub, hash[:], sig.R, sig.S), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ExampleMain 测试入口
|
||
|
|
func ExampleMain() {
|
||
|
|
message := "288889a170964134871008Dsr5c1729585712879payout"
|
||
|
|
|
||
|
|
pub, priv, err := GenerateKeyPairBase64()
|
||
|
|
if err != nil {
|
||
|
|
panic(err)
|
||
|
|
}
|
||
|
|
fmt.Println("Public Key (Base64):", pub)
|
||
|
|
fmt.Println("Private Key (Base64):", priv)
|
||
|
|
|
||
|
|
sig, err := SignDsa(message, priv)
|
||
|
|
if err != nil {
|
||
|
|
panic(err)
|
||
|
|
}
|
||
|
|
fmt.Println("Signature (Base64):", sig)
|
||
|
|
|
||
|
|
valid, err := VerifyDsa(message, sig, pub)
|
||
|
|
if err != nil {
|
||
|
|
panic(err)
|
||
|
|
}
|
||
|
|
fmt.Println("Signature is valid:", valid)
|
||
|
|
}
|
||
|
|
|
||
|
|
// PKCS#8 最外层结构
|
||
|
|
type pkcs8PrivateKey struct {
|
||
|
|
Version int
|
||
|
|
Algo pkix.AlgorithmIdentifier
|
||
|
|
PrivateKey []byte // OCTET STRING
|
||
|
|
}
|
||
|
|
|
||
|
|
// DSA 算法参数 Dss-Parms ::= SEQUENCE { p, q, g }
|
||
|
|
type dssParms struct {
|
||
|
|
P, Q, G *big.Int
|
||
|
|
}
|
||
|
|
|
||
|
|
func decodePKCS8DSAPrivateKey(b64 string) (*dsa.PrivateKey, error) {
|
||
|
|
// 1) Base64 解码 DER
|
||
|
|
der, err := base64.StdEncoding.DecodeString(b64)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2) 解析外层 PKCS#8
|
||
|
|
var p8 pkcs8PrivateKey
|
||
|
|
if _, err := asn1.Unmarshal(der, &p8); err != nil {
|
||
|
|
return nil, fmt.Errorf("unmarshal PKCS#8: %w", err)
|
||
|
|
}
|
||
|
|
// 确保是 DSA OID
|
||
|
|
if !p8.Algo.Algorithm.Equal(asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}) {
|
||
|
|
return nil, errors.New("unexpected algorithm OID, not DSA")
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3) 从 Algo.Parameters 解出 P, Q, G
|
||
|
|
var params dssParms
|
||
|
|
if _, err := asn1.Unmarshal(p8.Algo.Parameters.FullBytes, ¶ms); err != nil {
|
||
|
|
return nil, fmt.Errorf("unmarshal DSA parameters: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 4) 从 PrivateKey OCTET STRING 解出 X(私钥整数)
|
||
|
|
var x *big.Int
|
||
|
|
if _, err := asn1.Unmarshal(p8.PrivateKey, &x); err != nil {
|
||
|
|
return nil, fmt.Errorf("unmarshal DSA private integer: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 5) 计算 Y = G^X mod P
|
||
|
|
y := new(big.Int).Exp(params.G, x, params.P)
|
||
|
|
|
||
|
|
// 6) 构造 dsa.PrivateKey
|
||
|
|
priv := &dsa.PrivateKey{
|
||
|
|
PublicKey: dsa.PublicKey{
|
||
|
|
Parameters: dsa.Parameters{
|
||
|
|
P: params.P,
|
||
|
|
Q: params.Q,
|
||
|
|
G: params.G,
|
||
|
|
},
|
||
|
|
Y: y,
|
||
|
|
},
|
||
|
|
X: x,
|
||
|
|
}
|
||
|
|
return priv, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// SPKI 结构
|
||
|
|
type subjectPublicKeyInfo struct {
|
||
|
|
Algo pkix.AlgorithmIdentifier
|
||
|
|
PublicKey asn1.BitString
|
||
|
|
}
|
||
|
|
|
||
|
|
func decodeDSAPublicKey(b64 string) (*dsa.PublicKey, error) {
|
||
|
|
// 1. 解码 base64
|
||
|
|
der, err := base64.StdEncoding.DecodeString(b64)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("base64 decode: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. 解码 SPKI 外层
|
||
|
|
var spki subjectPublicKeyInfo
|
||
|
|
if _, err := asn1.Unmarshal(der, &spki); err != nil {
|
||
|
|
return nil, fmt.Errorf("unmarshal SPKI: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. 验证算法 OID 是 DSA
|
||
|
|
if !spki.Algo.Algorithm.Equal(asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}) {
|
||
|
|
return nil, fmt.Errorf("unexpected algorithm OID (not DSA)")
|
||
|
|
}
|
||
|
|
|
||
|
|
// 4. 解析 DSA 参数
|
||
|
|
var params dssParms
|
||
|
|
if _, err := asn1.Unmarshal(spki.Algo.Parameters.FullBytes, ¶ms); err != nil {
|
||
|
|
return nil, fmt.Errorf("unmarshal DSA parameters: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 5. 解析 BIT STRING 中的 Y
|
||
|
|
var y *big.Int
|
||
|
|
if _, err := asn1.Unmarshal(spki.PublicKey.RightAlign(), &y); err != nil {
|
||
|
|
return nil, fmt.Errorf("unmarshal public key Y: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 6. 构造 dsa.PublicKey
|
||
|
|
pub := &dsa.PublicKey{
|
||
|
|
Parameters: dsa.Parameters{
|
||
|
|
P: params.P,
|
||
|
|
Q: params.Q,
|
||
|
|
G: params.G,
|
||
|
|
},
|
||
|
|
Y: y,
|
||
|
|
}
|
||
|
|
return pub, nil
|
||
|
|
}
|