diff --git a/attestation/common/cryptotools/cryptotools.go b/attestation/common/cryptotools/cryptotools.go index ef37099328a501dab11e9b2ae560f65ad594dd96..5c42b864363dbc11fa6029461eb856a15578e345 100644 --- a/attestation/common/cryptotools/cryptotools.go +++ b/attestation/common/cryptotools/cryptotools.go @@ -38,6 +38,9 @@ import ( "math/big" "sync/atomic" "time" + "cryptotools/gmssTool/SM2" // 导入SM2包 + "cryptotools/gmssTool/SM3" // 导入SM3包 + "cryptotools/gmssTool/SM4" ) const ( @@ -58,13 +61,24 @@ const ( AlgCBC = 0x0042 // AlgCFB means CFB mode AlgCFB = 0x0043 + // AlgSM4 means SM4 algorithm + AlgSM4 = 0x0007 + // AlgSM2 means SM2 algorithm + AlgSM2 = 0x0008 + // AlgSM3 means SM3 algorithm + AlgSM3 = 0x0009 // KEYSIZE means the size of key KEYSIZE = 16 - // Encrypt_Alg means AES128 encryption algorithm with CBC mode Encrypt_Alg = "AES128-CBC" // AesKeySize means the size of AES algorithm key AesKeySize = 16 + // SM4KeySize means the size of SM4 algorithm key + SM4KeySize = 16 + // SM4IVSize means the size of SM4 initialization vector + SM4IVSize = 16 + // Encrypt_Alg_SM4 means SM4 encryption algorithm with CBC mode + Encrypt_Alg_SM4 = "SM4-CBC" // RsaKeySize means the size of RSA algorithm key RsaKeySize = 2048 headPrivKey = "PRIVATE KEY" @@ -235,6 +249,8 @@ func SymmetricEncrypt(alg, mod uint16, key, iv, plaintext []byte) ([]byte, error return aesOFBEncDec(key, iv, plaintext) case AlgCTR: return aesCTREncDec(key, iv, plaintext) + case AlgSM4: + return SymmetricEncryptSM4(key, iv, plaintext) } } return []byte{}, ErrWrongParams @@ -253,6 +269,8 @@ func SymmetricDecrypt(alg, mod uint16, key, iv, ciphertext []byte) ([]byte, erro return aesOFBEncDec(key, iv, ciphertext) case AlgCTR: return aesCTREncDec(key, iv, ciphertext) + case AlgSM4: + return SymmetricDecryptSM4(key, iv, ciphertext) } } return []byte{}, ErrWrongParams @@ -1075,3 +1093,44 @@ func validateCert(cert, parent *x509.Certificate) error { } return nil } +// SymmetricEncryptSM4 uses key/iv to encrypt the plaintext with SM4 algorithm in CBC mode. +func SymmetricEncryptSM4(key, iv, plaintext []byte) ([]byte, error) { + if len(key) != SM4KeySize { + return nil, ErrWrongParams + } + if len(iv) != SM4IVSize { + return nil, ErrWrongParams + } + ciphertext, _, err := sm4.SM4Encrypt(plaintext, key) + return ciphertext, err +} + +// SymmetricDecryptSM4 uses key/iv to decrypt the ciphertext with SM4 algorithm in CBC mode. +func SymmetricDecryptSM4(key, iv, ciphertext []byte) ([]byte, error) { + if len(key) != SM4KeySize { + return nil, ErrWrongParams + } + if len(iv) != SM4IVSize { + return nil, ErrWrongParams + } + plaintext, err := sm4.SM4Decrypt(ciphertext, key, iv) + return plaintext, err +} +// SM3Hash 计算数据的 SM3 哈希值 +func SM3Hash(data []byte) ([]byte, error) { + return sm3.SM3Hash(data) +} +// GenerateSM2KeyPair 生成 SM2 密钥对(返回 PEM 格式字符串) +func GenerateSM2KeyPair() (pubKey, privKey string, err error) { + return sm2.GenerateSM2KeyPair() +} + +// SM2Sign 使用 SM2 私钥签名数据 +func SM2Sign(privKeyPEM string, data []byte) ([]byte, error) { + return sm2.SM2Sign(privKeyPEM, data) +} + +// SM2Verify 使用 SM2 公钥验签 +func SM2Verify(pubKeyPEM string, data, sig []byte) (bool, error) { + return sm2.SM2Verify(pubKeyPEM, data, sig) +} \ No newline at end of file diff --git a/attestation/common/cryptotools/gmsslTool/SM2/sm2.go b/attestation/common/cryptotools/gmsslTool/SM2/sm2.go new file mode 100644 index 0000000000000000000000000000000000000000..e5bb154dd0111ea4e894a059a32e3a7c6522e159 --- /dev/null +++ b/attestation/common/cryptotools/gmsslTool/SM2/sm2.go @@ -0,0 +1,167 @@ +package sm2 + +/* +#cgo LDFLAGS: -lssl -lcrypto +#include +#include +#include +#include + +// 生成 SM2 密钥对(PEM 格式) +int sm2_generate_keypair(char **pub_key, char **priv_key) +{ + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (!ctx) return 0; + + if (EVP_PKEY_keygen_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + return 0; + } + + // 设置 SM2 曲线参数 + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_sm2) <= 0) { + EVP_PKEY_CTX_free(ctx); + return 0; + } + + EVP_PKEY *pkey = NULL; + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + EVP_PKEY_CTX_free(ctx); + return 0; + } + + // 导出公钥和私钥 + BIO *bio_pub = BIO_new(BIO_s_mem()); + BIO *bio_priv = BIO_new(BIO_s_mem()); + PEM_write_bio_PUBKEY(bio_pub, pkey); + PEM_write_bio_PrivateKey(bio_priv, pkey, NULL, NULL, 0, NULL, NULL); + + *pub_key = malloc(BIO_pending(bio_pub) + 1); + *priv_key = malloc(BIO_pending(bio_priv) + 1); + BIO_read(bio_pub, *pub_key, BIO_pending(bio_pub)); + BIO_read(bio_priv, *priv_key, BIO_pending(bio_priv)); + (*pub_key)[BIO_pending(bio_pub)] = '\0'; + (*priv_key)[BIO_pending(bio_priv)] = '\0'; + + BIO_free_all(bio_pub); + BIO_free_all(bio_priv); + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + return 1; +} + +// SM2 签名 +int sm2_sign(const char *priv_key_pem, const unsigned char *data, size_t data_len, + unsigned char *sig, size_t *sig_len) { + BIO *bio = BIO_new_mem_buf(priv_key_pem, -1); + EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (!pkey) { + BIO_free(bio); + return 0; + } + + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (!ctx) { + EVP_PKEY_free(pkey); + BIO_free(bio); + return 0; + } + + if (EVP_DigestSignInit(ctx, NULL, EVP_sm3(), NULL, pkey) <= 0 || + EVP_DigestSignUpdate(ctx, data, data_len) <= 0 || + EVP_DigestSignFinal(ctx, sig, sig_len) <= 0) { + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + BIO_free(bio); + return 0; + } + + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + BIO_free(bio); + return 1; +} + +// SM2 验签 +int sm2_verify(const char *pub_key_pem, const unsigned char *data, size_t data_len, + const unsigned char *sig, size_t sig_len) { + BIO *bio = BIO_new_mem_buf(pub_key_pem, -1); + EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (!pkey) { + BIO_free(bio); + return 0; + } + + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (!ctx) { + EVP_PKEY_free(pkey); + BIO_free(bio); + return 0; + } + + int ret = 0; + if (EVP_DigestVerifyInit(ctx, NULL, EVP_sm3(), NULL, pkey) > 0 && + EVP_DigestVerifyUpdate(ctx, data, data_len) > 0 && + EVP_DigestVerifyFinal(ctx, sig, sig_len) > 0) { + ret = 1; + } + + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + BIO_free(bio); + return ret; +} +*/ +import "C" +import ( + "errors" + "unsafe" +) + +// GenerateSM2KeyPair 生成 SM2 密钥对(返回 PEM 格式字符串) +func GenerateSM2KeyPair() (pubKey, privKey string, err error) { + var cPub, cPriv *C.char + if C.sm2_generate_keypair(&cPub, &cPriv) != 1 { + return "", "", errors.New("failed to generate SM2 key pair") + } + defer C.free(unsafe.Pointer(cPub)) + defer C.free(unsafe.Pointer(cPriv)) + return C.GoString(cPub), C.GoString(cPriv), nil +} + +// SM2Sign 使用 SM2 私钥签名数据 +func SM2Sign(privKeyPEM string, data []byte) ([]byte, error) { + sig := make([]byte, 64) // SM2 签名长度通常为 64 字节 + var sigLen C.size_t + + cPrivKeyPEM := C.CString(privKeyPEM) + if C.sm2_sign( + cPrivKeyPEM, + (*C.uchar)(unsafe.Pointer(&data[0])), + C.size_t(len(data)), + (*C.uchar)(unsafe.Pointer(&sig[0])), + &sigLen, + ) != 1 { + return nil, errors.New("SM2 signing failed") + } + defer C.free(unsafe.Pointer(cPrivKeyPEM)) + return sig[:sigLen], nil +} + + +// SM2Verify 使用 SM2 公钥验签 +func SM2Verify(pubKeyPEM string, data, sig []byte) (bool, error) { + ret := C.sm2_verify( + C.CString(pubKeyPEM), + (*C.uchar)(unsafe.Pointer(&data[0])), + C.size_t(len(data)), + (*C.uchar)(unsafe.Pointer(&sig[0])), + C.size_t(len(sig)), + ) + defer C.free(unsafe.Pointer(C.CString(pubKeyPEM))) // 释放C.CString分配的内存 + if ret == 1 { + return true, nil + } + return false, errors.New("SM2 verification failed") +} diff --git a/attestation/common/cryptotools/gmsslTool/SM3/sm3.go b/attestation/common/cryptotools/gmsslTool/SM3/sm3.go new file mode 100644 index 0000000000000000000000000000000000000000..75dcddfc894c319757e4abd90c4156f54a062e00 --- /dev/null +++ b/attestation/common/cryptotools/gmsslTool/SM3/sm3.go @@ -0,0 +1,39 @@ +package sm3 + +/* +#cgo LDFLAGS: -lssl -lcrypto +#include +#include + +// SM3 哈希计算 +void sm3_hash(const unsigned char *data, size_t data_len, unsigned char *hash) { + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + const EVP_MD *md = EVP_sm3(); + unsigned int hash_len; + + EVP_DigestInit_ex(ctx, md, NULL); + EVP_DigestUpdate(ctx, data, data_len); + EVP_DigestFinal_ex(ctx, hash, &hash_len); + EVP_MD_CTX_free(ctx); +} +*/ +import "C" +import ( + "errors" + "unsafe" +) + +// SM3Hash 计算数据的 SM3 哈希值(固定 32 字节) +func SM3Hash(data []byte) ([]byte, error) { + if len(data) == 0 { + return nil, errors.New("input data cannot be empty") + } + + hash := make([]byte, 32) // SM3 输出长度为 32 字节 + C.sm3_hash( + (*C.uchar)(unsafe.Pointer(&data[0])), + C.size_t(len(data)), + (*C.uchar)(unsafe.Pointer(&hash[0])), + ) + return hash, nil +} \ No newline at end of file diff --git a/attestation/common/cryptotools/gmsslTool/SM4/sm4.go b/attestation/common/cryptotools/gmsslTool/SM4/sm4.go new file mode 100644 index 0000000000000000000000000000000000000000..598d52313fd0fef73c0a9af2872651b09f3a0ae1 --- /dev/null +++ b/attestation/common/cryptotools/gmsslTool/SM4/sm4.go @@ -0,0 +1,133 @@ +package sm4 + +/* +#cgo LDFLAGS: -lssl -lcrypto +#include +#include +#include + +// 加密函数 +void sm4_encrypt(const unsigned char *plaintext, int plaintext_len, + const unsigned char *key, const unsigned char *iv, + unsigned char *ciphertext, int *ciphertext_len) { + EVP_CIPHER_CTX *ctx; + int len; + + // 创建并初始化上下文 + if(!(ctx = EVP_CIPHER_CTX_new())) { + return; + } + + // 初始化加密操作,启用填充 + if(1 != EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, key, iv)) { + EVP_CIPHER_CTX_free(ctx); + return; + } + + // 提供要加密的数据并进行加密 + if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) { + EVP_CIPHER_CTX_free(ctx); + return; + } + *ciphertext_len = len; + + // 完成加密操作 + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { + EVP_CIPHER_CTX_free(ctx); + return; + } + *ciphertext_len += len; + + // 清理上下文 + EVP_CIPHER_CTX_free(ctx); +} + +// 解密函数 +void sm4_decrypt(const unsigned char *ciphertext, int ciphertext_len, + const unsigned char *key, const unsigned char *iv, + unsigned char *plaintext, int *plaintext_len) { + EVP_CIPHER_CTX *ctx; + int len; + + // 创建并初始化上下文 + if(!(ctx = EVP_CIPHER_CTX_new())) { + return; + } + + // 初始化解密操作,启用填充 + if(1 != EVP_DecryptInit_ex(ctx, EVP_sm4_cbc(), NULL, key, iv)) { + EVP_CIPHER_CTX_free(ctx); + return; + } + + // 提供要解密的数据并进行解密 + if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { + EVP_CIPHER_CTX_free(ctx); + return; + } + *plaintext_len = len; + + // 完成解密操作 + if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { + EVP_CIPHER_CTX_free(ctx); + return; + } + *plaintext_len += len; + + // 清理上下文 + EVP_CIPHER_CTX_free(ctx); +} +*/ +import "C" +import ( + "crypto/rand" + "errors" + "unsafe" +) +const SM4KeySize = 16 +const SM4IVSize = 16 +// SM4Encrypt 使用 SM4 算法进行加密 +func SM4Encrypt(plaintext []byte, key []byte) ([]byte, []byte, error) { + if len(key) != SM4KeySize { + return nil, nil, errors.New("SM4 key must be 16 bytes") + } + iv := make([]byte, 16) + _, err := rand.Read(iv) + if err != nil { + return nil, nil, err + } + const IVSize = 16 + ciphertext := make([]byte, len(plaintext)+IVSize) + var ciphertextLen C.int + C.sm4_encrypt( + (*C.uchar)(unsafe.Pointer(&plaintext[0])), + C.int(len(plaintext)), + (*C.uchar)(unsafe.Pointer(&key[0])), + (*C.uchar)(unsafe.Pointer(&iv[0])), + (*C.uchar)(unsafe.Pointer(&ciphertext[0])), + &ciphertextLen, + ) + return ciphertext[:ciphertextLen], iv, nil +} + +// SM4Decrypt 使用 SM4 算法进行解密 +func SM4Decrypt(ciphertext []byte, key []byte, iv []byte) ([]byte, error) { + + if len(key) != SM4KeySize { + return nil, errors.New("SM4 key must be 16 bytes") + } + if len(iv) != SM4IVSize { + return nil, errors.New("SM4 IV must be 16 bytes") + } + plaintext := make([]byte, len(ciphertext)) + var plaintextLen C.int + C.sm4_decrypt( + (*C.uchar)(unsafe.Pointer(&ciphertext[0])), + C.int(len(ciphertext)), + (*C.uchar)(unsafe.Pointer(&key[0])), + (*C.uchar)(unsafe.Pointer(&iv[0])), + (*C.uchar)(unsafe.Pointer(&plaintext[0])), + &plaintextLen, + ) + return plaintext[:plaintextLen], nil +}