1+ package gost
2+
3+ import (
4+ "crypto/rand"
5+ "encoding/pem"
6+ "fmt"
7+ "math/big"
8+ "time"
9+ "crypto/x509/pkix"
10+
11+ "github.com/tjfoc/gmsm/sm2"
12+ sm2x509 "github.com/tjfoc/gmsm/x509"
13+ )
14+
15+ // GOSTCurve represents GOST curve types
16+ type GOSTCurve int
17+
18+ const (
19+ GOST2012_256 GOSTCurve = iota
20+ GOST2012_512
21+ )
22+
23+ // String returns the string representation of the GOST curve
24+ func (c GOSTCurve ) String () string {
25+ switch c {
26+ case GOST2012_256 :
27+ return "GOST2012_256"
28+ case GOST2012_512 :
29+ return "GOST2012_512"
30+ default :
31+ return "Unknown"
32+ }
33+ }
34+
35+ // GenerateKeyPair generates a GOST key pair
36+ func GenerateKeyPair (curve GOSTCurve ) (* sm2.PrivateKey , error ) {
37+ // For now, we'll use SM2 as a base since GOST curves aren't directly supported
38+ // In a real implementation, you'd need a GOST-specific library
39+ privKey , err := sm2 .GenerateKey (rand .Reader )
40+ if err != nil {
41+ return nil , fmt .Errorf ("failed to generate GOST %s key: %w" , curve .String (), err )
42+ }
43+ return privKey , nil
44+ }
45+
46+ // GenerateCertificate generates a GOST certificate
47+ func GenerateCertificate (privKey * sm2.PrivateKey , domain string , isCA bool , expireHours int ) ([]byte , []byte , error ) {
48+ // Create certificate template
49+ serialNumber , err := rand .Int (rand .Reader , new (big.Int ).Lsh (big .NewInt (1 ), 128 ))
50+ if err != nil {
51+ return nil , nil , fmt .Errorf ("failed to generate serial number: %w" , err )
52+ }
53+
54+ notBefore := time .Now ()
55+ notAfter := notBefore .Add (time .Duration (expireHours ) * time .Hour )
56+
57+ template := & sm2x509.Certificate {
58+ SerialNumber : serialNumber ,
59+ Subject : pkix.Name {
60+ Organization : []string {"Xray GOST Certificate" },
61+ CommonName : domain ,
62+ },
63+ NotBefore : notBefore ,
64+ NotAfter : notAfter ,
65+ KeyUsage : sm2x509 .KeyUsageKeyEncipherment | sm2x509 .KeyUsageDigitalSignature ,
66+ ExtKeyUsage : []sm2x509.ExtKeyUsage {sm2x509 .ExtKeyUsageServerAuth },
67+ BasicConstraintsValid : true ,
68+ }
69+
70+ if isCA {
71+ template .IsCA = true
72+ template .KeyUsage |= sm2x509 .KeyUsageCertSign
73+ } else {
74+ template .DNSNames = []string {domain }
75+ }
76+
77+ // Create certificate using SM2 (since GOST isn't directly supported)
78+ certDER , err := sm2x509 .CreateCertificate (template , template , & privKey .PublicKey , privKey )
79+ if err != nil {
80+ return nil , nil , fmt .Errorf ("failed to create GOST certificate: %w" , err )
81+ }
82+
83+ // Encode certificate
84+ certPEM := pem .EncodeToMemory (& pem.Block {
85+ Type : "CERTIFICATE" ,
86+ Bytes : certDER ,
87+ })
88+
89+ // Encode private key
90+ privKeyPEM := pem .EncodeToMemory (& pem.Block {
91+ Type : "PRIVATE KEY" ,
92+ Bytes : privKey .D .Bytes (),
93+ })
94+
95+ return certPEM , privKeyPEM , nil
96+ }
97+
98+ // ParsePrivateKey parses a GOST private key from PEM format
99+ func ParsePrivateKey (pemData []byte ) (* sm2.PrivateKey , error ) {
100+ block , _ := pem .Decode (pemData )
101+ if block == nil {
102+ return nil , fmt .Errorf ("failed to decode PEM block" )
103+ }
104+
105+ privKey , err := sm2x509 .ParsePKCS8UnecryptedPrivateKey (block .Bytes )
106+ if err != nil {
107+ return nil , fmt .Errorf ("failed to parse GOST private key: %w" , err )
108+ }
109+
110+ return privKey , nil
111+ }
112+
113+ // GetPublicKeyInfo returns public key information
114+ func GetPublicKeyInfo (privKey * sm2.PrivateKey , curve GOSTCurve ) (string , string , string ) {
115+ pubKey := privKey .PublicKey
116+ return "GOST " + curve .String () + "-bit" ,
117+ fmt .Sprintf ("%x" , pubKey .X .Bytes ()),
118+ fmt .Sprintf ("%x" , pubKey .Y .Bytes ())
119+ }
0 commit comments