C语言使用GmSSL库实现sm3、sm4算法

发布于:2025-08-02 ⋅ 阅读:(15) ⋅ 点赞:(0)

GmSSL库

GmSSL库github链接

注意编译的时候加上 -lgmssl 选项

一、sm3算法

— sm3杂凑算法

#include <stdio.h>
#include <string.h>
#include <gmssl/sm3.h>
#define SM3_DIGEST_LENGTH 32

int main(int argc, char *argv[])
{
    // 检查参数
    if (argc != 2) {
        printf("Usage: %s <message>\n", argv[0]);
        return 1;
    }

    const char *message = argv[1];
    size_t message_len = strlen(message);
    
    // SM3哈希结果缓冲区
    unsigned char sm3_hash[SM3_DIGEST_LENGTH];
    
    // SM3上下文结构
    SM3_CTX sm3_ctx;
    
    // 初始化SM3上下文
    sm3_init(&sm3_ctx);
    
    // 更新哈希计算,可以多次调用处理大数据
    sm3_update(&sm3_ctx, (unsigned char *)message, message_len);
    
    // 完成哈希计算,获取最终结果
    sm3_finish(&sm3_ctx, sm3_hash);
    
    // 打印原始消息
    printf("Message: %s\n", message);
    
    // 打印SM3哈希结果
    printf("SM3 Hash: ");
    for (int i = 0; i < SM3_DIGEST_LENGTH; i++) {
        printf("%02x", sm3_hash[i]);
    }
    printf("\n");
    
    return 0;
}

— sm3 hmac算法

#include <stdio.h>
#include <string.h>
#include <gmssl/hmac.h>
#include <gmssl/sm3.h>

void print_hex(const char *label, const unsigned char *data, size_t len) {
    printf("%s: ", label);
    for (size_t i = 0; i < len; i++) {
        printf("%02x", data[i]);
    }
    printf("\n");
}

int main() {
    // 预定义的十六进制密钥 (32字节全零)
    const unsigned char key[16] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    };

    // 预定义的十六进制消息 (12字节全零)
    const unsigned char message[16] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    };

    // 计算HMAC-SM3
    unsigned char hmac[1024] = {0};
    size_t hmac_len = 1024;
    HMAC_CTX ctx;

    // 初始化HMAC上下文
    if (hmac_init(&ctx, DIGEST_sm3(), key, sizeof(key)) != 1) {
        fprintf(stderr, "HMAC init failed\n");
        return 1;
    }

    // 更新消息数据
    if (hmac_update(&ctx, message, sizeof(message)) != 1) {
        fprintf(stderr, "HMAC update failed\n");
        return 1;
    }

    // 获取HMAC结果
    if (hmac_finish(&ctx, hmac, &hmac_len) != 1) {
        fprintf(stderr, "HMAC finish failed\n");
        return 1;
    }

    // 验证输出长度
    if (hmac_len != SM3_DIGEST_SIZE) {
        fprintf(stderr, "Error: Unexpected HMAC length %zu (expected %d)\n",
                hmac_len, SM3_DIGEST_SIZE);
        return 1;
    }

    // 打印结果
    print_hex("Key (hex)", key, sizeof(key));
    print_hex("Message (hex)", message, sizeof(message));
    print_hex("HMAC-SM3 (hex)", hmac, hmac_len);

    return 0;
}

二、sm4算法

— ECB模式 包括包括0填充和PKCS#7 填充方式

#include <stdio.h>
#include <string.h>
#include <gmssl/sm4.h>
#include <gmssl/hex.h>

// 打印十六进制数据
void print_hex(const char* label, const uint8_t* data, size_t datalen) {
    printf("%s: ", label);
    for (size_t i = 0; i < datalen; i++) {
        printf("%02X", data[i]);
    }
    printf("\n");
}

// PKCS#7填充
int pkcs7_pad(uint8_t* buf, size_t buflen, size_t datalen, int block_size) {
    if (datalen >= buflen || block_size <= 0 || block_size > 255) {
        return -1;
    }
    
    int pad_len = block_size - (datalen % block_size);
    for (size_t i = datalen; i < datalen + pad_len; i++) {
        buf[i] = (uint8_t)pad_len;
    }
    return datalen + pad_len;
}

// PKCS#7去填充
int pkcs7_unpad(uint8_t* buf, size_t buflen) {
    if (buflen == 0) return -1;
    
    uint8_t pad_len = buf[buflen - 1];
    if (pad_len > buflen) return -1;
    
    for (size_t i = buflen - pad_len; i < buflen; i++) {
        if (buf[i] != pad_len) return -1;
    }
    return buflen - pad_len;
}

// 使用0填充的SM4 ECB加密
int sm4_ecb_encrypt_zero_pad(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
    SM4_KEY sm4_key;
    sm4_set_encrypt_key(&sm4_key, key);
    
    // 0填充到16字节倍数
    size_t padded_len = ((inlen + 15) / 16) * 16;
    uint8_t padded_data[padded_len];
    memcpy(padded_data, in, inlen);
    memset(padded_data + inlen, 0, padded_len - inlen);
    
    for (size_t i = 0; i < padded_len; i += 16) {
        sm4_encrypt(&sm4_key, padded_data + i, out + i);
    }
    
    return padded_len;
}

// 使用0填充的SM4 ECB解密
int sm4_ecb_decrypt_zero_pad(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
    if (inlen % 16 != 0) {
        return -1;
    }
    
    SM4_KEY sm4_key;
    sm4_set_decrypt_key(&sm4_key, key);
    
    for (size_t i = 0; i < inlen; i += 16) {
        sm4_encrypt(&sm4_key, in + i, out + i); // 注意:在ECB模式下,解密也是使用sm4_encrypt函数,只是密钥不同
    }
    
    // 去除0填充需要知道原始数据长度,这里返回全部数据
    return inlen;
}

// 使用PKCS#7填充的SM4 ECB加密
int sm4_ecb_encrypt_pkcs7(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
    SM4_KEY sm4_key;
    sm4_set_encrypt_key(&sm4_key, key);
    
    // PKCS#7填充
    size_t padded_len = ((inlen + 15) / 16) * 16;
    uint8_t padded_data[padded_len];
    memcpy(padded_data, in, inlen);
    pkcs7_pad(padded_data, padded_len, inlen, 16);
    
    for (size_t i = 0; i < padded_len; i += 16) {
        sm4_encrypt(&sm4_key, padded_data + i, out + i);
    }
    
    return padded_len;
}

// 使用PKCS#7填充的SM4 ECB解密
int sm4_ecb_decrypt_pkcs7(const uint8_t* key, const uint8_t* in, size_t inlen, uint8_t* out) {
    if (inlen % 16 != 0) {
        return -1;
    }
    
    SM4_KEY sm4_key;
    sm4_set_decrypt_key(&sm4_key, key);
    
    for (size_t i = 0; i < inlen; i += 16) {
        sm4_encrypt(&sm4_key, in + i, out + i); // 注意:在ECB模式下,解密也是使用sm4_encrypt函数,只是密钥不同
    }
    
    // 去除PKCS#7填充
    return pkcs7_unpad(out, inlen);
}

int main() {
    // SM4密钥 (16字节)
    uint8_t key[16] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
        0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
    };
    
    // 测试数据
    uint8_t plaintext[] = "Hello, SM4 ECB encryption! This is a test.";
    size_t plaintext_len = strlen((char*)plaintext);
    
    printf("=== SM4 ECB Encryption/Decryption Demo ===\n");
    print_hex("Key", key, sizeof(key));
    print_hex("Plaintext", plaintext, plaintext_len);
    printf("Plaintext length: %zu\n", plaintext_len);
    
    // 1. 使用0填充加密解密
    printf("\n[Zero Padding]\n");
    
    uint8_t ciphertext_zero[256] = {0};
    uint8_t decrypted_zero[256] = {0};
    
    // 加密
    int ciphertext_zero_len = sm4_ecb_encrypt_zero_pad(key, plaintext, plaintext_len, ciphertext_zero);
    print_hex("Ciphertext (Zero pad)", ciphertext_zero, ciphertext_zero_len);
    
    // 解密
    int decrypted_zero_len = sm4_ecb_decrypt_zero_pad(key, ciphertext_zero, ciphertext_zero_len, decrypted_zero);
    printf("Decrypted length: %d\n", decrypted_zero_len);
    print_hex("Decrypted data (Zero pad)", decrypted_zero, decrypted_zero_len);
    printf("Decrypted text: %.*s\n", decrypted_zero_len, decrypted_zero);
    
    // 2. 使用PKCS#7填充加密解密
    printf("\n[PKCS#7 Padding]\n");
    
    uint8_t ciphertext_pkcs7[256] = {0};
    uint8_t decrypted_pkcs7[256] = {0};
    
    // 加密
    int ciphertext_pkcs7_len = sm4_ecb_encrypt_pkcs7(key, plaintext, plaintext_len, ciphertext_pkcs7);
    print_hex("Ciphertext (PKCS#7)", ciphertext_pkcs7, ciphertext_pkcs7_len);
    
    // 解密
    int decrypted_pkcs7_len = sm4_ecb_decrypt_pkcs7(key, ciphertext_pkcs7, ciphertext_pkcs7_len, decrypted_pkcs7);
    if (decrypted_pkcs7_len < 0) {
        printf("Decryption failed (invalid padding)\n");
    } else {
        printf("Decrypted length: %d\n", decrypted_pkcs7_len);
        print_hex("Decrypted data (PKCS#7)", decrypted_pkcs7, decrypted_pkcs7_len);
        printf("Decrypted text: %.*s\n", decrypted_pkcs7_len, decrypted_pkcs7);
    }
    
    return 0;
}

—CBC模式 包括包括0填充和PKCS#7 填充方式

#include <stdio.h>
#include <string.h>
#include <gmssl/sm4.h>
#include <gmssl/hex.h>
#include <gmssl/rand.h>

// 打印十六进制数据
void print_hex(const char* label, const uint8_t* data, size_t datalen) {
    printf("%s: ", label);
    for (size_t i = 0; i < datalen; i++) {
        printf("%02X", data[i]);
    }
    printf("\n");
}

// PKCS#7填充
int pkcs7_pad(uint8_t* buf, size_t buflen, size_t datalen, int block_size) {
    if (datalen >= buflen || block_size <= 0 || block_size > 255) {
        return -1;
    }
    
    int pad_len = block_size - (datalen % block_size);
    for (size_t i = datalen; i < datalen + pad_len; i++) {
        buf[i] = (uint8_t)pad_len;
    }
    return datalen + pad_len;
}

// PKCS#7去填充
int pkcs7_unpad(uint8_t* buf, size_t buflen) {
    if (buflen == 0) return -1;
    
    uint8_t pad_len = buf[buflen - 1];
    if (pad_len > buflen) return -1;
    
    for (size_t i = buflen - pad_len; i < buflen; i++) {
        if (buf[i] != pad_len) return -1;
    }
    return buflen - pad_len;
}

// 使用0填充的SM4 CBC加密
int sm4_cbc_encrypt_zero_pad(const uint8_t* key, const uint8_t* iv, 
                            const uint8_t* in, size_t inlen, uint8_t* out) {
    SM4_KEY sm4_key;
    uint8_t ivec[SM4_BLOCK_SIZE];
    
    sm4_set_encrypt_key(&sm4_key, key);
    memcpy(ivec, iv, SM4_BLOCK_SIZE);
    
    // 0填充到16字节倍数
    size_t padded_len = ((inlen + 15) / 16) * 16;
    uint8_t padded_data[padded_len];
    memcpy(padded_data, in, inlen);
    memset(padded_data + inlen, 0, padded_len - inlen);
    
    for (size_t i = 0; i < padded_len; i += SM4_BLOCK_SIZE) {
        // 异或IV
        for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
            padded_data[i + j] ^= ivec[j];
        }
        
        sm4_encrypt(&sm4_key, padded_data + i, out + i);
        
        // 更新IV为当前密文块
        memcpy(ivec, out + i, SM4_BLOCK_SIZE);
    }
    
    return padded_len;
}

// 使用0填充的SM4 CBC解密
int sm4_cbc_decrypt_zero_pad(const uint8_t* key, const uint8_t* iv, 
                            const uint8_t* in, size_t inlen, uint8_t* out) {
    if (inlen % SM4_BLOCK_SIZE != 0) {
        return -1;
    }
    
    SM4_KEY sm4_key;
    uint8_t ivec[SM4_BLOCK_SIZE];
    uint8_t temp[SM4_BLOCK_SIZE];
    
    sm4_set_decrypt_key(&sm4_key, key);
    memcpy(ivec, iv, SM4_BLOCK_SIZE);
    
    for (size_t i = 0; i < inlen; i += SM4_BLOCK_SIZE) {
        // 解密当前块
        sm4_encrypt(&sm4_key, in + i, temp);
        
        // 异或IV
        for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
            out[i + j] = temp[j] ^ ivec[j];
        }
        
        // 更新IV为当前密文块
        memcpy(ivec, in + i, SM4_BLOCK_SIZE);
    }
    
    // 返回解密数据长度(等于输入长度)
    return inlen;
}

// 使用PKCS#7填充的SM4 CBC加密
int sm4_cbc_encrypt_pkcs7(const uint8_t* key, const uint8_t* iv, 
                         const uint8_t* in, size_t inlen, uint8_t* out) {
    SM4_KEY sm4_key;
    uint8_t ivec[SM4_BLOCK_SIZE];
    
    sm4_set_encrypt_key(&sm4_key, key);
    memcpy(ivec, iv, SM4_BLOCK_SIZE);
    
    // PKCS#7填充
    size_t padded_len = ((inlen + 15) / 16) * 16;
    uint8_t padded_data[padded_len];
    memcpy(padded_data, in, inlen);
    pkcs7_pad(padded_data, padded_len, inlen, SM4_BLOCK_SIZE);
    
    for (size_t i = 0; i < padded_len; i += SM4_BLOCK_SIZE) {
        // 异或IV
        for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
            padded_data[i + j] ^= ivec[j];
        }
        
        sm4_encrypt(&sm4_key, padded_data + i, out + i);
        
        // 更新IV为当前密文块
        memcpy(ivec, out + i, SM4_BLOCK_SIZE);
    }
    
    return padded_len;
}

// 使用PKCS#7填充的SM4 CBC解密
int sm4_cbc_decrypt_pkcs7(const uint8_t* key, const uint8_t* iv, 
                         const uint8_t* in, size_t inlen, uint8_t* out) {
    if (inlen % SM4_BLOCK_SIZE != 0) {
        return -1;
    }
    
    SM4_KEY sm4_key;
    uint8_t ivec[SM4_BLOCK_SIZE];
    uint8_t temp[SM4_BLOCK_SIZE];
    
    sm4_set_decrypt_key(&sm4_key, key);
    memcpy(ivec, iv, SM4_BLOCK_SIZE);
    
    for (size_t i = 0; i < inlen; i += SM4_BLOCK_SIZE) {
        // 解密当前块
        sm4_encrypt(&sm4_key, in + i, temp);
        
        // 异或IV
        for (int j = 0; j < SM4_BLOCK_SIZE; j++) {
            out[i + j] = temp[j] ^ ivec[j];
        }
        
        // 更新IV为当前密文块
        memcpy(ivec, in + i, SM4_BLOCK_SIZE);
    }
    
    // 去除PKCS#7填充
    return pkcs7_unpad(out, inlen);
}

int main() {
    // SM4密钥 (16字节)
    uint8_t key[SM4_BLOCK_SIZE] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
        0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
    };
    
    // 初始化向量IV (16字节)
    uint8_t iv[SM4_BLOCK_SIZE];
    rand_bytes(iv, SM4_BLOCK_SIZE); // 使用随机IV
    
    // 测试数据
    uint8_t plaintext[] = "Hello, SM4 CBC encryption! This is a test.";
    size_t plaintext_len = strlen((char*)plaintext);
    
    printf("=== SM4 CBC Encryption/Decryption Demo ===\n");
    print_hex("Key", key, sizeof(key));
    print_hex("IV", iv, sizeof(iv));
    print_hex("Plaintext", plaintext, plaintext_len);
    printf("Plaintext length: %zu\n", plaintext_len);
    
    // 1. 使用0填充加密解密
    printf("\n[Zero Padding]\n");
    
    uint8_t ciphertext_zero[256] = {0};
    uint8_t decrypted_zero[256] = {0};
    
    // 加密
    int ciphertext_zero_len = sm4_cbc_encrypt_zero_pad(key, iv, plaintext, plaintext_len, ciphertext_zero);
    print_hex("Ciphertext (Zero pad)", ciphertext_zero, ciphertext_zero_len);
    
    // 解密
    int decrypted_zero_len = sm4_cbc_decrypt_zero_pad(key, iv, ciphertext_zero, ciphertext_zero_len, decrypted_zero);
    printf("Decrypted length: %d\n", decrypted_zero_len);
    print_hex("Decrypted data (Zero pad)", decrypted_zero, decrypted_zero_len);
    printf("Decrypted text: %.*s\n", decrypted_zero_len, decrypted_zero);
    
    // 2. 使用PKCS#7填充加密解密
    printf("\n[PKCS#7 Padding]\n");
    
    uint8_t ciphertext_pkcs7[256] = {0};
    uint8_t decrypted_pkcs7[256] = {0};
    
    // 加密
    int ciphertext_pkcs7_len = sm4_cbc_encrypt_pkcs7(key, iv, plaintext, plaintext_len, ciphertext_pkcs7);
    print_hex("Ciphertext (PKCS#7)", ciphertext_pkcs7, ciphertext_pkcs7_len);
    
    // 解密
    int decrypted_pkcs7_len = sm4_cbc_decrypt_pkcs7(key, iv, ciphertext_pkcs7, ciphertext_pkcs7_len, decrypted_pkcs7);
    if (decrypted_pkcs7_len < 0) {
        printf("Decryption failed (invalid padding)\n");
    } else {
        printf("Decrypted length: %d\n", decrypted_pkcs7_len);
        print_hex("Decrypted data (PKCS#7)", decrypted_pkcs7, decrypted_pkcs7_len);
        printf("Decrypted text: %.*s\n", decrypted_pkcs7_len, decrypted_pkcs7);
    }
    
    return 0;
}