添加文件: ymt_v3/valid.md
This commit is contained in:
parent
98603ce4ff
commit
6eb5f47500
|
|
@ -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
|
||||
}
|
||||
```
|
||||
Loading…
Reference in New Issue