添加文件: ymt_v3/valid.md

This commit is contained in:
renzhiyuan 2026-07-23 16:39:45 +08:00
parent 98603ce4ff
commit 6eb5f47500
1 changed files with 272 additions and 0 deletions

272
ymt_v3/valid.md Normal file
View File

@ -0,0 +1,272 @@
// File: ymt_v3/crypto.go
```go
package ymt_v3
import (
"bytes"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"io"
"reflect"
"sort"
"strings"
"time"
"github.com/tjfoc/gmsm/sm4"
)
const (
EncryptModeAES = "aes"
EncryptModeSM4 = "sm4"
)
func GenerateTimestamp() string {
return time.Now().Format("2006-01-02 15:04:05")
}
func BuildSignString(appID, timestamp, ciphertext string) string {
return appID + timestamp + ciphertext
}
func RSASign(signStr string, privateKeyPEM string) (string, error) {
block, _ := pem.Decode([]byte(privateKeyPEM))
if block == nil {
return "", fmt.Errorf("failed to decode PEM private key")
}
var privateKey *rsa.PrivateKey
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", fmt.Errorf("failed to parse private key: %v", err)
}
privateKey = key.(*rsa.PrivateKey)
} else {
var ok bool
privateKey, ok = key.(*rsa.PrivateKey)
if !ok {
return "", fmt.Errorf("not a RSA private key")
}
}
hash := sha256.Sum256([]byte(signStr))
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hash[:])
if err != nil {
return "", fmt.Errorf("sign failed: %v", err)
}
return base64.StdEncoding.EncodeToString(signature), nil
}
func RSAVerify(signStr, signature string, publicKeyPEM string) error {
block, _ := pem.Decode([]byte(publicKeyPEM))
if block == nil {
return fmt.Errorf("failed to decode PEM public key")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return fmt.Errorf("failed to parse public key: %v", err)
}
publicKey, ok := pub.(*rsa.PublicKey)
if !ok {
return fmt.Errorf("not a RSA public key")
}
sigBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
return fmt.Errorf("failed to decode signature: %v", err)
}
hash := sha256.Sum256([]byte(signStr))
return rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hash[:], sigBytes)
}
func AESECBEncrypt(plaintext []byte, key []byte) (string, error) {
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("create AES cipher failed: %v", err)
}
padded := pkcs7Padding(plaintext, aes.BlockSize)
ciphertext := make([]byte, len(padded))
for i := 0; i < len(padded); i += aes.BlockSize {
block.Encrypt(ciphertext[i:i+aes.BlockSize], padded[i:i+aes.BlockSize])
}
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
func AESECBDecrypt(encryptedData string, key []byte) ([]byte, error) {
ciphertext, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return nil, fmt.Errorf("decode base64 failed: %v", err)
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("create AES cipher failed: %v", err)
}
if len(ciphertext)%aes.BlockSize != 0 {
return nil, fmt.Errorf("ciphertext length is not multiple of block size")
}
plaintext := make([]byte, len(ciphertext))
for i := 0; i < len(ciphertext); i += aes.BlockSize {
block.Decrypt(plaintext[i:i+aes.BlockSize], ciphertext[i:i+aes.BlockSize])
}
plaintext, err = pkcs7UnPadding(plaintext)
if err != nil {
return nil, fmt.Errorf("remove padding failed: %v", err)
}
return plaintext, nil
}
func SM4CBCEncrypt(plaintext []byte, key []byte) (string, error) {
if len(key) != 16 {
return "", fmt.Errorf("SM4 key length must be 16 bytes")
}
block, err := sm4.NewCipher(key)
if err != nil {
return "", fmt.Errorf("create SM4 cipher failed: %v", err)
}
padded := pkcs7Padding(plaintext, block.BlockSize())
iv := make([]byte, block.BlockSize())
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", fmt.Errorf("generate IV failed: %v", err)
}
mode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(padded))
mode.CryptBlocks(ciphertext, padded)
result := append(iv, ciphertext...)
return base64.StdEncoding.EncodeToString(result), nil
}
func SM4CBCDecrypt(encryptedData string, key []byte) ([]byte, error) {
if len(key) != 16 {
return nil, fmt.Errorf("SM4 key length must be 16 bytes")
}
data, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return nil, fmt.Errorf("decode base64 failed: %v", err)
}
block, err := sm4.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("create SM4 cipher failed: %v", err)
}
blockSize := block.BlockSize()
if len(data) < blockSize {
return nil, fmt.Errorf("data length too short")
}
iv := data[:blockSize]
ciphertext := data[blockSize:]
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)
plaintext, err = pkcs7UnPadding(plaintext)
if err != nil {
return nil, fmt.Errorf("remove padding failed: %v", err)
}
return plaintext, nil
}
func pkcs7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padtext...)
}
func pkcs7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, fmt.Errorf("data is empty")
}
unpadding := int(data[length-1])
if unpadding > length || unpadding == 0 {
return nil, fmt.Errorf("invalid padding")
}
return data[:length-unpadding], nil
}
func StructToSortedJSON(v interface{}) (string, error) {
val := reflect.ValueOf(v)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return "", fmt.Errorf("expected struct, got %s", val.Kind())
}
typ := val.Type()
result := make(map[string]interface{})
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := typ.Field(i)
jsonTag := fieldType.Tag.Get("json")
if jsonTag == "" || jsonTag == "-" {
continue
}
name := jsonTag
if idx := strings.Index(jsonTag, ","); idx != -1 {
name = jsonTag[:idx]
}
if field.IsZero() {
continue
}
result[name] = field.Interface()
}
keys := make([]string, 0, len(result))
for k := range result {
keys = append(keys, k)
}
sort.Strings(keys)
var buf bytes.Buffer
buf.WriteString("{")
for i, k := range keys {
if i > 0 {
buf.WriteString(",")
}
buf.WriteString(`"`)
buf.WriteString(k)
buf.WriteString(`":`)
vBytes, err := json.Marshal(result[k])
if err != nil {
return "", err
}
buf.Write(vBytes)
}
buf.WriteString("}")
return buf.String(), nil
}
```