《密码系统设计》实验
实验项目
实验序号 | 实验名称 | 实验学时数 | 实验目的 | 实验内容 | 实验类型 | 学生学习预期成果 |
---|---|---|---|---|---|---|
实验一 | 嵌入式开发基础 | 6 | 掌握Linux系统使用与开发方法 | Linux命令,OpenSSL(GmSSL)命令与开发 | 验证性 | 1.掌握常见的Linux命令与C语言开发方法;2.掌握OpenSSL(GmSSL)的基本用法与开发;3.掌握常见商用密码算法的使用 |
参考相关内容,在 Ubuntu或openEuler中(推荐 openEuler)中使⽤OpenSSL库编程实现调⽤SM2(加密解密,签名验签),SM3(摘要计算,HMAC 计算),SM4(加密解密)算法,使⽤Markdown记录详细记录实践过程,每完成⼀项git commit ⼀次。(5’)
SM2
代码
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
EVP_PKEY *load_private_key(const char *filename) {
FILE *fp = fopen(filename, "r");
if (!fp) {
perror("Unable to open file");
return NULL;
}
EVP_PKEY *private_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
if (!private_key) {
ERR_print_errors_fp(stderr);
}
fclose(fp);
return private_key;
}
EVP_PKEY* load_public_key(const char* filename) {
EVP_PKEY *key = NULL;
BIO *bio = BIO_new(BIO_s_file());
if (!bio) {
fprintf(stderr, "Unable to create file BIO\n");
return NULL;
}
BIO_read_filename(bio, filename);
key = PEM_read_bio_PUBKEY(bio, NULL, 0, NULL);
BIO_free(bio);
if (!key) {
fprintf(stderr, "Unable to load public key\n");
}
return key;
}
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
int sm2_encrypt(const unsigned char *input_file,EVP_PKEY *pub_key,unsigned char **ciphertext, size_t *ciphertext_len) {
EVP_PKEY_CTX *pctx = NULL;
int ret = 0;
// Check for a valid public key
if (!pub_key) {
fprintf(stderr, "Invalid public key.\n");
return 0;
}
pctx = EVP_PKEY_CTX_new(pub_key, NULL);
if (!pctx) {
fprintf(stderr, "Unable to create EVP_PKEY_CTX.\n");
ERR_print_errors_fp(stderr);
return 0;
}
unsigned char* buf = NULL;
size_t buf_len = 0;
if(read_file(input_file, &buf, &buf_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
if (EVP_PKEY_encrypt_init(pctx) <= 0) {
fprintf(stderr, "Encryption initialization failed.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
if (EVP_PKEY_encrypt(pctx, NULL, ciphertext_len, buf, buf_len) <= 0) {
fprintf(stderr, "Failed to determine ciphertext length.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
*ciphertext = OPENSSL_malloc(*ciphertext_len);
if (!*ciphertext) {
fprintf(stderr, "Unable to allocate memory for ciphertext.\n");
goto cleanup;
}
if (EVP_PKEY_encrypt(pctx, *ciphertext, ciphertext_len, buf, buf_len) <= 0) {
fprintf(stderr, "Encryption failed.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
ret = 1;
free(buf);
buf = NULL;
cleanup:
if (!ret && *ciphertext) {
OPENSSL_free(*ciphertext);
*ciphertext = NULL;
*ciphertext_len = 0;
}
if (pctx) {
EVP_PKEY_CTX_free(pctx);
}
return ret;
}
int sm2_decrypt(const unsigned char *input_file,EVP_PKEY *priv_pkey,unsigned char **plaintext, size_t *plaintext_len) {
EVP_PKEY_CTX *pctx = NULL;
int ret = 0;
if (!priv_pkey) {
fprintf(stderr, "Invalid pri key. \n");
return 0;
}
unsigned char* buf = NULL;
size_t buf_len = 0;
if(read_file(input_file, &buf, &buf_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
pctx = EVP_PKEY_CTX_new(priv_pkey, NULL);
if (!pctx) {
fprintf(stderr, "Unable to create EVP_PKEY_CTX.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
if (EVP_PKEY_decrypt_init(pctx) <= 0) {
fprintf(stderr, "Decryption initialization failed.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
if (EVP_PKEY_decrypt(pctx, NULL, plaintext_len, buf, buf_len) <= 0) {
fprintf(stderr, "Failed to determine plaintext length.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
*plaintext = OPENSSL_malloc(*plaintext_len);
if (!*plaintext) {
fprintf(stderr, "Unable to allocate memory for plaintext.\n");
goto cleanup;
}
if (EVP_PKEY_decrypt(pctx, *plaintext, plaintext_len, buf, buf_len) <= 0) {
fprintf(stderr, "Decryption failed.\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
printf("plaintext:%s", *plaintext);
ret = 1;
cleanup:
if (!ret && *plaintext) {
OPENSSL_free(*plaintext);
*plaintext = NULL;
*plaintext_len = 0;
}
if (pctx) {
EVP_PKEY_CTX_free(pctx);
}
return ret;
}
int generate_sm2_key(const char *priv_key_file, const char *pub_key_file) {
EC_KEY *ec_key = NULL;
EVP_PKEY *pkey = NULL;
FILE *priv_fp = NULL;
FILE *pub_fp = NULL;
int ret = 1;
ec_key = EC_KEY_new_by_curve_name(NID_sm2);
if (!ec_key) {
ERR_print_errors_fp(stderr);
return ret;
}
if (!EC_KEY_generate_key(ec_key)) {
fprintf(stderr, "Failed to generate SM2 key\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
pkey = EVP_PKEY_new();
if (!pkey || !EVP_PKEY_assign_EC_KEY(pkey, ec_key)) {
fprintf(stderr, "Failed to assign EC_KEY to EVP_PKEY\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
ec_key = NULL;
priv_fp = fopen(priv_key_file, "wb");
if (!priv_fp || !PEM_write_PrivateKey(priv_fp, pkey, NULL, NULL, 0, NULL, NULL)) {
fprintf(stderr, "Failed to write private key\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
pub_fp = fopen(pub_key_file, "wb");
if (!pub_fp || !PEM_write_PUBKEY(pub_fp, pkey)) {
fprintf(stderr, "Failed to write public key\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
printf("SM2 key pair generated and saved successfully.\n");
ret = 0;
cleanup:
if (pkey) EVP_PKEY_free(pkey);
if (ec_key) EC_KEY_free(ec_key);
if (priv_fp) fclose(priv_fp);
if (pub_fp) fclose(pub_fp);
return ret;
}
int sm2_sign(const unsigned char *input_file, EVP_PKEY *priv_key, unsigned char **signature, size_t *sig_len) {
unsigned char *sig = NULL;
unsigned char *message = NULL;
size_t len = 0;
if(read_file(input_file,&message, &len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
int ret = 0;
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
fprintf(stderr, "Failed to create signing context\n");
goto end;
}
if (EVP_DigestSignInit(ctx, NULL, EVP_sm3(), NULL, priv_key) <= 0) {
fprintf(stderr, "Failed to init signing\n");
goto end;
}
if (EVP_DigestSignUpdate(ctx, message, len) <= 0) {
fprintf(stderr, "Failed to update signing\n");
goto end;
}
size_t tmp_sig_len = 0;
if (EVP_DigestSignFinal(ctx, NULL, &tmp_sig_len) <= 0) {
fprintf(stderr, "Failed to get signature length\n");
goto end;
}
sig = OPENSSL_malloc(tmp_sig_len);
if (EVP_DigestSignFinal(ctx, sig, &tmp_sig_len) <= 0) {
fprintf(stderr, "Failed to sign\n");
goto end;
}
*signature = (char *)sig;
*sig_len = tmp_sig_len;
ret = 1;
end:
if (!ret) {
ERR_print_errors_fp(stderr);
OPENSSL_free(sig);
}
EVP_MD_CTX_free(ctx);
return ret;
}
int sm2_verify(const unsigned char *input_file, EVP_PKEY *pub_key, const unsigned char *signature) {
int ret = 0;
unsigned char *message = NULL, *sign = NULL;
size_t len = 0, sig_len = 0;
if(read_file(input_file,&message, &len) || read_file(signature, &sign, &sig_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
fprintf(stderr, "Failed to create verification context\n");
goto end;
}
if (EVP_DigestVerifyInit(ctx, NULL, EVP_sm3(), NULL, pub_key) <= 0) {
fprintf(stderr, "Failed to init verification\n");
goto end;
}
if (EVP_DigestVerifyUpdate(ctx, message, len) <= 0) {
fprintf(stderr, "Failed to update verification\n");
goto end;
}
if (EVP_DigestVerifyFinal(ctx, (const unsigned char *)sign, sig_len) <= 0) {
fprintf(stderr, "Failed to verify\n");
goto end;
}
ret = 1;
end:
if (!ret) {
ERR_print_errors_fp(stderr);
}
EVP_MD_CTX_free(ctx);
return ret;
}
void usage(){
printf("usage: -key\n");
printf(" -e -kfile -file\n");
printf(" -d -kfile -file\n");
printf(" -s -kfile -file\n");
printf(" -v -kfile -file -sig\n");
}
int check(char * argv[]){
if(strcmp(argv[4], "-file") != 0){
usage();
return 1;
}
if (argv[5] == NULL || argv[5][0] == '\0') {
fprintf(stderr, "No file provided\n");
return 1;
}
return 0;
}
int main(int argc, char * argv[]){
if(argc == 1){
usage();
return 0;
}
if(strcmp(argv[1], "-key") == 0){
const char *priv_key_file = "sm2_private.pem";
const char *pub_key_file = "sm2_public.pem";
generate_sm2_key(priv_key_file,pub_key_file);
}else if(argc <= 5){
usage();
}else if(strcmp(argv[1], "-e") == 0 && strcmp(argv[2], "-kfile") == 0){
EVP_PKEY *pub_key = load_public_key(argv[3]);
unsigned char * ciphertext = NULL;
size_t ciphertextlen = 0;
if(!pub_key){
fprintf(stderr, "Failed to load keys\n");
return 1;
}
if(check(argv)){
EVP_PKEY_free(pub_key);
return 1;
}
if (sm2_encrypt((const unsigned char *)argv[5], pub_key, &ciphertext, &ciphertextlen) == 1) {
printf("SM2 Encryption OK\n");
const char *output_file = "encrypt.txt";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM2 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(ciphertext, 1, ciphertextlen, fp_out);
printf("SM2 Save ok\n");
fclose(fp_out);
} else {
fprintf(stderr, "Encryption failed\n");
if (ciphertext) {
OPENSSL_free(ciphertext);
}
}
}else if(strcmp(argv[1], "-d") == 0 && strcmp(argv[2], "-kfile") == 0){
EVP_PKEY *priv_key = load_private_key(argv[3]);
unsigned char * plaintext = NULL;
size_t plaintextlen = 0;
if(!priv_key){
fprintf(stderr, "Failed to load keys\n");
return 1;
}
if(check(argv)){
EVP_PKEY_free(priv_key);
return 1;
}
if (sm2_decrypt((const unsigned char *)argv[5], priv_key, &plaintext, &plaintextlen) == 1) {
printf("SM2 Decryption OK\n");
const char *output_file = "decrypt.txt";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM2 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(plaintext, 1, plaintextlen, fp_out);
printf("SM2 Save ok\n");
fclose(fp_out);
} else {
fprintf(stderr, "Decryption failed\n");
if (plaintext) {
OPENSSL_free(plaintext);
}
}
}else if(strcmp(argv[1], "-s") == 0 && strcmp(argv[2], "-kfile") == 0){
EVP_PKEY *priv_key = load_private_key(argv[3]);
unsigned char * signtext = NULL;
size_t signlen = 0;
if(!priv_key){
fprintf(stderr, "Failed to load keys\n");
return 1;
}
if(check(argv)){
EVP_PKEY_free(priv_key);
return 1;
}
if(sm2_sign((const unsigned char *)argv[5], priv_key, &signtext, &signlen) == 1){
printf("SM2 signature OK\n");
const char *output_file = "signature.sig";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM2 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(signtext, 1, signlen, fp_out);
printf("SM2 Save ok\n");
fclose(fp_out);
}else{
fprintf(stderr, "Signature failed\n");
if (signtext) {
OPENSSL_free(signtext);
}
}
}
else if(strcmp(argv[1], "-v") == 0 && strcmp(argv[2], "-kfile") == 0){
EVP_PKEY *pub_key = load_public_key(argv[3]);
if(!pub_key){
fprintf(stderr, "Failed to load keys\n");
return 1;
}
if(check(argv)){
EVP_PKEY_free(pub_key);
return 1;
}
if(argc <= 6 || strcmp(argv[6], "-sig") != 0){
usage();
return 0;
}
if (argv[7] == NULL || argv[7][0] == '\0') {
fprintf(stderr, "No signature provided\n");
return 1;
}
if(sm2_verify((const unsigned char *)argv[5], pub_key, (const unsigned char *)argv[7])){
printf("Signature verified successfully.\n");
}else{
printf("Signature verification failed.\n");
}
EVP_PKEY_free(pub_key);
}else{
usage();
}
return 0;
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm2-1 -key
SM2 key pair generated and saved successfully.
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm2-1 -e -kfile sm2_public.pem -file plain.txt
SM2 Encryption OK
SM2 Save ok
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm2-1 -d -kfile sm2_private.pem -file encrypt.txt
plaintext:20221327俞鸿若劼
SM2 Decryption OK
SM2 Save ok
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm2-1 -s -kfile sm2_private.pem -file plain.txt
SM2 signature OK
SM2 Save ok
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm2-1 -v -kfile sm2_public.pem -file plain.txt -sig signature.sig
Signature verified successfully.
SM3
Hash
#include <openssl/evp.h>
#include <string.h>
void dumpbuf(const unsigned char *buf, int len) {
for (int i = 0; i < len; i++) {
printf("%02x", buf[i]);
}
printf("\n");
}
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
int sm3_hash(const unsigned char *input_file, unsigned char *hash, unsigned int *hash_len)
{
unsigned char *message = NULL;
size_t len = 0;
if(read_file(input_file,&message, &len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
EVP_MD_CTX *md_ctx = NULL;
const EVP_MD *md = NULL;
int ret = -1;
md_ctx = EVP_MD_CTX_new();
if (md_ctx == NULL) {
return ret;
}
md = EVP_sm3();
if (md == NULL) {
EVP_MD_CTX_free(md_ctx);
return ret;
}
if (EVP_DigestInit_ex(md_ctx, md, NULL) != 1) {
goto cleanup;
}
if (EVP_DigestUpdate(md_ctx, message, len) != 1) {
goto cleanup;
}
if (EVP_DigestFinal_ex(md_ctx, hash, hash_len) != 1) {
goto cleanup;
}
ret = 0;
cleanup:
EVP_MD_CTX_free(md_ctx);
return ret;
}
int main(int argc, char * argv[]){
unsigned char hash_value[32];
unsigned int hash_len;
if(argc < 3){
printf("usage: -in filename\n");
return 0;
}
if(strcmp(argv[1], "-in") != 0){
printf("usage: -in filename\n");
return 0;
}
int ret = sm3_hash((const unsigned char *)argv[2], hash_value, &hash_len);
if (ret != 0) {
fprintf(stderr, "SM3 Hash failed\n");
return 1;
}
printf("SM3 Hash OK\n");
const char *output_file = "hash.bin";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM3 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
dumpbuf(hash_value, hash_len);
fwrite(hash_value, 1, hash_len, fp_out);
printf("SM3 Save ok\n");
fclose(fp_out);
return 0;
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm3 -in plain.txt
SM3 Hash OK
00000000: 79ae c2e8 7f3d 3110 bd84 5866 ce1d 1633 y....=1...Xf...3
00000010: c5af b953 932f 4694 54fd 5a2e 6ca6 03ee ...S./F.T.Z.l...
SM3 Save ok
hmac
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#define BLOCK_LENGTH 64
#define L 32
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
void XOR(unsigned char *out, const unsigned char *in1, const unsigned char *in2, size_t len) {
for (size_t i = 0; i < len; i++) {
out[i] = in1[i] ^ in2[i];
}
}
unsigned char* SM3_HMAC(const unsigned char *key, size_t key_len, const unsigned char *data, size_t data_len, unsigned char *mac, size_t *mac_len) {
unsigned char key_pad[BLOCK_LENGTH] = {0};
unsigned char o_key_pad[BLOCK_LENGTH];
unsigned char inner_hash[L];
unsigned char final_hash[L];
if (key_len > BLOCK_LENGTH) {
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
fprintf(stderr, "Unable to create MD context\n");
return NULL;
}
EVP_DigestInit_ex(ctx, EVP_sm3(), NULL);
EVP_DigestUpdate(ctx, key, key_len);
unsigned char hashed_key[L];
EVP_DigestFinal_ex(ctx, hashed_key, NULL);
memcpy(key_pad, hashed_key, L);
EVP_MD_CTX_free(ctx);
} else {
memcpy(key_pad, key, key_len);
}
memset(o_key_pad, 0x5c, BLOCK_LENGTH);
memset(key_pad, 0x36, BLOCK_LENGTH);
XOR(o_key_pad, o_key_pad, key_pad, BLOCK_LENGTH);
EVP_MD_CTX *inner_ctx = EVP_MD_CTX_new();
if (!inner_ctx) {
fprintf(stderr, "Unable to create MD context\n");
return NULL;
}
EVP_DigestInit_ex(inner_ctx, EVP_sm3(), NULL);
EVP_DigestUpdate(inner_ctx, key_pad, BLOCK_LENGTH);
EVP_DigestUpdate(inner_ctx, data, data_len);
EVP_DigestFinal_ex(inner_ctx, inner_hash, NULL);
EVP_MD_CTX_free(inner_ctx);
EVP_MD_CTX *outer_ctx = EVP_MD_CTX_new();
if (!outer_ctx) {
fprintf(stderr, "Unable to create MD context\n");
return NULL;
}
EVP_DigestInit_ex(outer_ctx, EVP_sm3(), NULL);
EVP_DigestUpdate(outer_ctx, o_key_pad, BLOCK_LENGTH);
EVP_DigestUpdate(outer_ctx, inner_hash, L);
EVP_DigestFinal_ex(outer_ctx, final_hash, NULL);
EVP_MD_CTX_free(outer_ctx);
memcpy(mac, final_hash, L);
*mac_len = L;
return mac;
}
int main(int argc, char * argv[]) {
if(argc < 5){
printf("usage: -kfile -file");
return 0;
}
if(strcmp(argv[1], "-kfile") == 0 && strcmp(argv[3], "-file") == 0){
unsigned char *key, *data;
unsigned char mac[L];
size_t mac_len, key_len, data_len;
if(read_file((const unsigned char*)argv[2], &key, &key_len) || read_file((const unsigned char *)argv[4], &data, &data_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
SM3_HMAC(key, key_len, data, data_len, mac, &mac_len);
printf("HMAC-SM3: ");
for (size_t i = 0; i < mac_len; i++) {
printf("%02x", mac[i]);
}
printf("\n");
const char *output_file = "SM3-HMAC.bin";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM3 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(mac, 1, L, fp_out);
printf("SM3-HMAC Save ok\n");
fclose(fp_out);
}
return 0;
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ ./sm3-hmac -k'0123456789abcdef0123456789abcdef' -file plain.txt
HMAC-SM3: 6e034d26659e5a75539253a0881dc9887e1a53dd85d5d667fd1a76f23108fbb2
SM3-HMAC Save ok
SM4
代码
#include "openssl/evp.h"
#include <string.h>
#include <stdio.h>
#define FAILURE -1
#define SUCCESS 0
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
void print_hex(const char *title, const unsigned char *data, int len) {
printf("%s:", title);
for (int i = 0; i < len; i++) {
if (i % 16 == 0)
printf("\n%04X: ", i);
printf("%02X ", data[i]);
}
printf("\n");
}
int do_encrypt(const unsigned char * input_key, const unsigned char * input_iv, const unsigned char * input_message,const EVP_CIPHER *type, const char *ctype)
{
unsigned char outbuf[1024];
int outlen, tmplen;
unsigned char *key, *iv, *message;
size_t key_len, iv_len, message_len;
if(read_file(input_key, &key, &key_len) || read_file(input_iv, &iv, &iv_len)) {
fprintf(stderr, "Unable to read file.\n");
return 0;
}
if(key_len != 16 || iv_len != 16) {
fprintf(stderr, "Error Key or Iv.\n");
return 0;
}
if(read_file(input_message, &message, &message_len)) {
fprintf(stderr, "Unable to read file.\n");
return 0;
}
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
printf("Failed to create EVP_CIPHER_CTX\n");
return FAILURE;
}
if (EVP_EncryptInit_ex(ctx, type, NULL, key, iv) != 1) {
printf("EVP_EncryptInit_ex failed for %s\n", ctype);
EVP_CIPHER_CTX_free(ctx);
return FAILURE;
}
if (EVP_EncryptUpdate(ctx, outbuf, &outlen, (unsigned char*)message, message_len) != 1) {
printf("EVP_EncryptUpdate failed for %s\n", ctype);
EVP_CIPHER_CTX_free(ctx);
return FAILURE;
}
if (EVP_EncryptFinal_ex(ctx, outbuf + outlen, &tmplen) != 1) {
printf("EVP_EncryptFinal_ex failed for %s\n", ctype);
EVP_CIPHER_CTX_free(ctx);
return FAILURE;
}
outlen += tmplen;
EVP_CIPHER_CTX_free(ctx);
char filename[64];
sprintf(filename, "./cipher_%s.dat", ctype);
FILE *out = fopen(filename, "wb+");
if (!out) {
printf("Cannot open file: %s\n", filename);
return FAILURE;
}
fwrite(outbuf, 1, outlen, out);
fflush(out);
fclose(out);
printf("%s encryption successful. Ciphertext length: %d bytes\n", ctype, outlen);
print_hex("Ciphertext", outbuf, outlen);
return SUCCESS;
}
int do_decrypt(const unsigned char * input_key, const unsigned char * input_iv, const unsigned char * input_message,const EVP_CIPHER *type, const char *ctype)
{
unsigned char inbuf[1024] = { 0 };
unsigned char outbuf[1024] = { 0 };
int outlen, inlen, tmplen;
unsigned char *key, *iv, *message;
size_t key_len, iv_len, message_len;
if(read_file(input_key, &key, &key_len) || read_file(input_iv, &iv, &iv_len)) {
fprintf(stderr, "Unable to read file.\n");
return 0;
}
if(key_len != 16 || iv_len != 16) {
fprintf(stderr, "Error Key or Iv.\n");
return 0;
}
if(read_file(input_message, &message, &message_len)) {
fprintf(stderr, "Unable to read file.\n");
return 0;
}
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
printf("Failed to create EVP_CIPHER_CTX\n");
return FAILURE;
}
if (EVP_DecryptInit_ex(ctx, type, NULL, key, iv) != 1) {
printf("EVP_DecryptInit_ex failed for %s\n", ctype);
EVP_CIPHER_CTX_free(ctx);
return FAILURE;
}
if (EVP_DecryptUpdate(ctx, outbuf, &outlen, message, message_len) != 1) {
printf("EVP_DecryptUpdate failed for %s\n", ctype);
EVP_CIPHER_CTX_free(ctx);
return FAILURE;
}
if (EVP_DecryptFinal_ex(ctx, outbuf + outlen, &tmplen) != 1) {
printf("EVP_DecryptFinal_ex failed for %s\n", ctype);
EVP_CIPHER_CTX_free(ctx);
return FAILURE;
}
outlen += tmplen;
EVP_CIPHER_CTX_free(ctx);
printf("%s decryption result: \n%.*s\n", ctype, outlen, outbuf);
print_hex("Decrypted plaintext (hex)", outbuf, outlen);
return SUCCESS;
}
int main(int argc, char *argv[])
{
OpenSSL_add_all_algorithms();
const EVP_CIPHER *sm4_cbc = EVP_sm4_cbc();
if (!sm4_cbc) {
printf("Cannot get SM4-CBC cipher\n");
return FAILURE;
}
if(argc < 8){
printf("usage: -e/-d -kfile -iv -file");
return 0;
}
if(strcmp(argv[1], "-e") == 0){
if(strcmp(argv[2], "-kfile") == 0 && strcmp(argv[4], "-iv") == 0 && strcmp(argv[6], "-file") == 0)
if (do_encrypt((unsigned char*)argv[3], (unsigned char*)argv[5],(unsigned char*)argv[7],sm4_cbc, "sm4-cbc") != SUCCESS) {
printf("SM4-CBC encryption failed\n");
EVP_cleanup();
return FAILURE;
}
}else if(strcmp(argv[1], "-d") == 0){
if(strcmp(argv[2], "-kfile") == 0 && strcmp(argv[4], "-iv") == 0 && strcmp(argv[6], "-file") == 0){
if (do_decrypt((unsigned char*)argv[3], (unsigned char*)argv[5],(unsigned char*)argv[7],sm4_cbc, "sm4-cbc") != SUCCESS) {
printf("SM4-CBC decryption failed\n");
EVP_cleanup();
return FAILURE;
}
}
}else{
printf("usage: -e/-d -kfile -iv -file");
return 0;
}
EVP_cleanup();
return 0;
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm4$ ./sm4 -e -kfile key.bin -iv iv.bin -file plain.txt
sm4-cbc encryption successful. Ciphertext length: 16 bytes
Ciphertext:
0000: F7 9A 8F C5 65 49 CE 3D 2D 63 63 C4 CC BE C5 A5
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm4$ ./sm4 -d -kfile key.bin -iv iv.bin -file cipher_sm4-cbc.dat
sm4-cbc decryption result:
20221327
Decrypted plaintext (hex):
0000: 32 30 32 32 31 34 32 34 0A
参考相关内容,在 Ubuntu或openEuler中(推荐 openEuler)中使⽤GmSSL库编程实现调⽤SM2(加密解密,签名验签),SM3(摘要计算,HMAC 计算),SM4(加密解密)算法,使⽤Markdown记录详细记录实践过程,每完成⼀项git commit ⼀次。(5’)
SM2
代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
#include <gmssl/error.h>
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
void print_hex(const char *label, const uint8_t *data, size_t len) {
printf("%s: ", label);
for(size_t i = 0; i < len; i++) {
printf("%02X", data[i]);
}
printf("\n");
}
int gmssl_sm2_encrypt(const unsigned char * input_file, SM2_KEY* key){
unsigned char *plaintext = NULL;
size_t plaintext_len = 0;
if(read_file(input_file,&plaintext, &plaintext_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
};
uint8_t ciphertext[SM2_MAX_CIPHERTEXT_SIZE];
size_t ciphertext_len = sizeof(ciphertext);
int ret = sm2_encrypt(key, (const uint8_t *)plaintext, plaintext_len, ciphertext, &ciphertext_len);
if (ret != 1) {
fprintf(stderr, "SM2 加密失败\n");
return EXIT_FAILURE;
}
printf("加密成功。\n");
print_hex("密文", ciphertext, ciphertext_len);
const char *output_file = "encrypt.txt";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(ciphertext, 1, ciphertext_len, fp_out);
printf("Save ok\n");
fclose(fp_out);
}
int gmssl_sm2_decrypt(const unsigned char * input_file, SM2_KEY* key){
unsigned char *ciphertext = NULL;
size_t ciphertext_len = 0;
if(read_file(input_file,&ciphertext, &ciphertext_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
};
uint8_t decrypted[SM2_MAX_PLAINTEXT_SIZE];
size_t decrypted_len = sizeof(decrypted);
printf("解密密文...\n");
int ret = sm2_decrypt(key, (const uint8_t *)ciphertext, ciphertext_len, decrypted, &decrypted_len);
if (ret != 1) {
fprintf(stderr, "SM2 解密失败\n");
return EXIT_FAILURE;
}
printf("解密成功。\n");
decrypted[decrypted_len] = '\0';
printf("解密后的明文: %s\n", decrypted);
const char *output_file = "decrypt.txt";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(decrypted, 1, decrypted_len, fp_out);
printf("Save ok\n");
fclose(fp_out);
}
int gmssl_sm2_sign(const unsigned char * input_file, SM2_KEY* key){
char *message = NULL;
size_t message_len = 0;
if(read_file(input_file,&message, &message_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
};
SM2_SIGN_CTX sign_ctx;
sm2_sign_init(&sign_ctx, key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH);
int ret = sm2_sign_update(&sign_ctx, (const uint8_t *)message, message_len);
if (ret != 1) {
fprintf(stderr, "SM2 签名更新失败\n");
return EXIT_FAILURE;
}
uint8_t signature[SM2_MAX_SIGNATURE_SIZE];
size_t signature_len = sizeof(signature);
ret = sm2_sign_finish(&sign_ctx, signature, &signature_len);
if (ret != 1) {
fprintf(stderr, "SM2 签名失败\n");
return EXIT_FAILURE;
}
printf("签名成功。\n");
print_hex("签名", signature, signature_len);
const char *output_file = "signature.sig";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(signature, 1, signature_len, fp_out);
printf("Save ok\n");
fclose(fp_out);
}
int gmssl_sm2_verify(const unsigned char * input_file, const unsigned char * input_sign, SM2_KEY* key){
unsigned char *message = NULL;
size_t message_len = 0;
if(read_file(input_file,&message, &message_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
uint8_t *signature = NULL;
size_t signature_len = 0;
if(read_file(input_sign,&signature, &signature_len)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
printf("%s\n", message);
print_hex("签名",signature,signature_len);
SM2_SIGN_CTX verify_ctx;
sm2_verify_init(&verify_ctx, key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH);
int ret = sm2_verify_update(&verify_ctx, (const uint8_t *)message, message_len);
if (ret != 1) {
fprintf(stderr, "SM2 签名验证更新失败\n");
return EXIT_FAILURE;
}
ret = sm2_verify_finish(&verify_ctx, signature, signature_len);
if (ret == 1) {
printf("签名验证成功。\n");
} else {
printf("签名验证失败。\n");
return EXIT_FAILURE;
}
}
int generate_sm2_key(){
int ret;
SM2_KEY key;
printf("生成 SM2 密钥对...\n");
ret = sm2_key_generate(&key);
if (ret != 1) {
fprintf(stderr, "SM2 密钥生成失败\n");
return 1;
}
printf("SM2 密钥生成成功。\n");
FILE *priv_fp = fopen("private_key.bin", "wb");
if (priv_fp == NULL) {
fprintf(stderr, "打开私钥文件失败\n");
return EXIT_FAILURE;
}
FILE *pub_fp = fopen("public_key.bin", "wb");
if (pub_fp == NULL) {
fprintf(stderr, "打开公钥文件失败\n");
return EXIT_FAILURE;
}
uint8_t prikey[32];
sm2_z256_to_bytes(key.private_key, prikey);
uint8_t octets[65];
octets[0] = SM2_point_uncompressed;
(void)sm2_z256_point_to_bytes(&key.public_key, octets + 1);
fwrite(prikey, 1, sizeof(prikey), priv_fp);
fclose(priv_fp);
fwrite(octets, 1, sizeof(octets), pub_fp);
fclose(pub_fp);
sm2_key_print(stdout, 0, 4, "SM2", &key);
return 0;
}
int load_pri_key(const unsigned char* pri, SM2_KEY* mykey){
if (mykey == NULL) {
fprintf(stderr, "提供的SM2_KEY结构指针无效\n");
return 1;
}
FILE *priv_fp = fopen(pri, "rb");
if (priv_fp == NULL) {
fprintf(stderr, "打开私钥文件失败\n");
return 1;
}
uint8_t prikey[32];
size_t len;
len = fread(prikey, 1, sizeof(prikey), priv_fp);
if (len != sizeof(prikey)) {
fprintf(stderr, "读取私钥数据失败\n");
fclose(priv_fp);
return 1;
}
fclose(priv_fp);
sm2_z256_from_bytes(mykey->private_key, prikey);
return 0;
}
int load_pub_key(const unsigned char* pub, SM2_KEY* mykey){
if (mykey == NULL) {
fprintf(stderr, "提供的SM2_KEY结构指针无效\n");
return 1;
}
FILE *pub_fp = fopen(pub, "rb");
if (pub_fp == NULL) {
fprintf(stderr, "打开公钥文件失败\n");
return 1;
}
uint8_t octets[65];
size_t len;
len = fread(octets, 1, sizeof(octets), pub_fp);
if (len != sizeof(octets)) {
fprintf(stderr, "读取公钥数据失败\n");
fclose(pub_fp);
return 1;
}
fclose(pub_fp);
if (sm2_z256_point_from_bytes(&mykey->public_key, octets + 1) != 1) {
fprintf(stderr, "密钥数据加载失败\n");
return 1;
}
return 0;
}
int load_key(const char* pri_file, const char* pub_file, SM2_KEY* mykey) {
load_pub_key(pub_file, mykey);
load_pri_key(pri_file, mykey);
return 0;
}
void usage(){
printf("usage: -key\n");
printf(" -e -kfile -file\n");
printf(" -d -kfile -file\n");
printf(" -s -pri -pub -file\n");
printf(" -v -kfile -file -signature\n");
}
int check(char * argv[]){
if(strcmp(argv[4], "-file") != 0){
usage();
return 1;
}
if (argv[5] == NULL || argv[5][0] == '\0') {
fprintf(stderr, "No file provided\n");
return 1;
}
return 0;
}
int main(int argc, char* argv[]) {
SM2_KEY mykey;
if(argc == 1){
usage();
return 0;
}
if(strcmp(argv[1], "-key") == 0){
generate_sm2_key();
}else if(argc <= 5){
usage();
}else if(strcmp(argv[1], "-e") == 0 && strcmp(argv[2], "-kfile") == 0){
if(load_pub_key((const unsigned char*)argv[3], &mykey)){
fprintf(stderr, "密钥数据加载失败\n");
return 1;
}
if(check(argv)){
usage();
return 1;
}
gmssl_sm2_encrypt((const unsigned char*)argv[5], &mykey);
}else if(strcmp(argv[1], "-d") == 0 && strcmp(argv[2], "-kfile") == 0){
if(load_pri_key((const unsigned char*)argv[3], &mykey)){
fprintf(stderr, "密钥数据加载失败\n");
return 1;
}
if(check(argv)){
usage();
return 1;
}
gmssl_sm2_decrypt((const unsigned char*)argv[5], &mykey);
}else if(strcmp(argv[1], "-s") == 0 && strcmp(argv[2], "-pri") == 0 && strcmp(argv[4], "-pub") == 0){
if(load_pri_key((const unsigned char*)argv[3], &mykey) || load_pub_key((const unsigned char*)argv[5], &mykey)){
fprintf(stderr, "密钥数据加载失败\n");
return 1;
}
if(strcmp(argv[6], "-file") != 0 || argv[7] == NULL){
usage();
return 1;
}
gmssl_sm2_sign((const unsigned char*)argv[7], &mykey);
}
else if(strcmp(argv[1], "-v") == 0 && strcmp(argv[2], "-kfile") == 0){
//load_pri_key("private_key.bin", &mykey);
if(load_pub_key((const unsigned char*)argv[3], &mykey)){
fprintf(stderr, "密钥数据加载失败\n");
return 1;
}
if(check(argv) || strcmp(argv[6], "-signature") != 0 || argv[7] == NULL){
usage();
return 1;
}
gmssl_sm2_verify((const unsigned char*)argv[5], (const unsigned char*) argv[7],&mykey);
}else {
usage();
}
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm2$ '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_encrypt' '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_pk.pem' '/home/liuzujing/experiment-1-from-4-to-6/sm2/just.txt' '/home/liuzujing/experiment-1-from-4-to-6/sm2/enc.bin'
Encryption successful, output written to /home/liuzujing/experiment-1-from-4-to-6/sm2/enc.bin
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm2$ '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_decrypt' '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_pk.pem' '/home/liuzujing/experiment-1-from-4-to-6/sm2/enc.bin' '/home/liuzujing/experiment-1-from-4-to-6/sm2/message.txt'
Decryption successful, output written to /home/liuzujing/experiment-1-from-4-to-6/sm2/message.txt
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm2$ '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_sign' '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_sk.pem' '/home/liuzujing/experiment-1-from-4-to-6/sm2/just.txt' '/home/liuzujing/experiment-1-from-4-to-6/sm2/a.sig'
Signature generated and saved to /home/liuzujing/experiment-1-from-4-to-6/sm2/a.sig
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm2$ '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_verify' '/home/liuzujing/experiment-1-from-4-to-6/sm2/gm_sm2_pk.pem' '/home/liuzujing/experiment-1-from-4-to-6/sm2/just.txt' '/home/liuzujing/experiment-1-from-4-to-6/sm2/a.sig'
Verify success
SM3
hash
#include <stdio.h>
#include <string.h>
#include <gmssl/sm3.h>
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
int main(int argc, char* argv[]) {
if(argc < 3){
printf("usage: -in filename\n");
return 0;
}
if(strcmp(argv[1], "-in") != 0){
printf("usage: -in filename\n");
return 0;
}
unsigned char hash[SM3_DIGEST_SIZE];
SM3_CTX ctx;
sm3_init(&ctx);
sm3_update(&ctx, (const unsigned char*)argv[2], strlen(argv[2]));
sm3_finish(&ctx, hash);
printf("SM3 hash: ");
for (int i = 0; i < SM3_DIGEST_SIZE; i++) {
printf("%02x", hash[i]);
}
printf("\n");
const char *output_file = "hash.bin";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM3 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(hash, 1, SM3_DIGEST_SIZE, fp_out);
printf("SM3 Save ok\n");
fclose(fp_out);
return 0;
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ xxd '/home/liuzujing/experiment-1-from-4-to-6/sm3/hash.bin'
00000000: 79ae c2e8 7f3d 3110 bd84 5866 ce1d 1633 y....=1...Xf...3
00000010: c5af b953 932f 4694 54fd 5a2e 6ca6 03ee ...S./F.T.Z.l...
hmac
// sm3.c
#include <string.h>
#include <stdint.h>
#include <stdio.h>
typedef struct {
uint32_t total[2]; // 消息总长度(以位为单位)
uint32_t state[8]; // 哈希状态
unsigned char buffer[64]; // 数据缓冲区
// 用于 HMAC
unsigned char ipad[64];
unsigned char opad[64];
} sm3_context;
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ((uint32_t)(b)[(i) ] << 24) \
| ((uint32_t)(b)[(i) + 1] << 16) \
| ((uint32_t)(b)[(i) + 2] << 8) \
| ((uint32_t)(b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
/*
* SM3 context setup
*/
void sm3_starts(sm3_context *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x7380166F;
ctx->state[1] = 0x4914B2B9;
ctx->state[2] = 0x172442D7;
ctx->state[3] = 0xDA8A0600;
ctx->state[4] = 0xA96F30BC;
ctx->state[5] = 0x163138AA;
ctx->state[6] = 0xE38DEE4D;
ctx->state[7] = 0xB0FB0E4E;
}
static void sm3_process(sm3_context *ctx, const unsigned char data[64])
{
uint32_t SS1, SS2, TT1, TT2, W[68], W1[64];
uint32_t A, B, C, D, E, F, G, H;
uint32_t T[64];
uint32_t Temp1, Temp2, Temp3, Temp4, Temp5;
int j;
#ifdef _DEBUG
int i;
#endif
for (j = 0; j < 16; j++)
T[j] = 0x79CC4519;
for (j = 16; j < 64; j++)
T[j] = 0x7A879D8A;
for (j = 0; j < 16; j++)
GET_UINT32_BE(W[j], data, j * 4);
#ifdef _DEBUG
printf("Message with padding:\n");
for (i = 0; i < 8; i++)
printf("%08x ", W[i]);
printf("\n");
for (i = 8; i < 16; i++)
printf("%08x ", W[i]);
printf("\n");
#endif
#define FF0(x,y,z) ( (x) ^ (y) ^ (z))
#define FF1(x,y,z) (((x) & (y)) | ( (x) & (z)) | ( (y) & (z)))
#define GG0(x,y,z) ( (x) ^ (y) ^ (z))
#define GG1(x,y,z) (((x) & (y)) | ( (~(x)) & (z)) )
#define SHL(x,n) (((x) & 0xFFFFFFFF) << (n))
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - (n))))
#define P0(x) ((x) ^ ROTL((x),9) ^ ROTL((x),17))
#define P1(x) ((x) ^ ROTL((x),15) ^ ROTL((x),23))
for (j = 16; j < 68; j++)
{
Temp1 = W[j - 16] ^ W[j - 9];
Temp2 = ROTL(W[j - 3], 15);
Temp3 = Temp1 ^ Temp2;
Temp4 = P1(Temp3);
Temp5 = ROTL(W[j - 13], 7) ^ W[j - 6];
W[j] = Temp4 ^ Temp5;
}
#ifdef _DEBUG
printf("Expanding message W0-67:\n");
for (i = 0; i < 68; i++)
{
printf("%08x ", W[i]);
if (((i + 1) % 8) == 0) printf("\n");
}
printf("\n");
#endif
for (j = 0; j < 64; j++)
{
W1[j] = W[j] ^ W[j + 4];
}
#ifdef _DEBUG
printf("Expanding message W'0-63:\n");
for (i = 0; i < 64; i++)
{
printf("%08x ", W1[i]);
if (((i + 1) % 8) == 0) printf("\n");
}
printf("\n");
#endif
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
F = ctx->state[5];
G = ctx->state[6];
H = ctx->state[7];
#ifdef _DEBUG
printf("j A B C D E F G H\n");
printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", A, B, C, D, E, F, G, H);
#endif
for (j = 0; j < 16; j++)
{
SS1 = ROTL((ROTL(A, 12) + E + ROTL(T[j], j)), 7);
SS2 = SS1 ^ ROTL(A, 12);
TT1 = FF0(A, B, C) + D + SS2 + W1[j];
TT2 = GG0(E, F, G) + H + SS1 + W[j];
D = C;
C = ROTL(B, 9);
B = A;
A = TT1;
H = G;
G = ROTL(F, 19);
F = E;
E = P0(TT2);
#ifdef _DEBUG
printf("%02d %08x %08x %08x %08x %08x %08x %08x %08x\n", j, A, B, C, D, E, F, G, H);
#endif
}
for (j = 16; j < 64; j++)
{
SS1 = ROTL((ROTL(A, 12) + E + ROTL(T[j], j)), 7);
SS2 = SS1 ^ ROTL(A, 12);
TT1 = FF1(A, B, C) + D + SS2 + W1[j];
TT2 = GG1(E, F, G) + H + SS1 + W[j];
D = C;
C = ROTL(B, 9);
B = A;
A = TT1;
H = G;
G = ROTL(F, 19);
F = E;
E = P0(TT2);
#ifdef _DEBUG
printf("%02d %08x %08x %08x %08x %08x %08x %08x %08x\n", j, A, B, C, D, E, F, G, H);
#endif
}
ctx->state[0] ^= A;
ctx->state[1] ^= B;
ctx->state[2] ^= C;
ctx->state[3] ^= D;
ctx->state[4] ^= E;
ctx->state[5] ^= F;
ctx->state[6] ^= G;
ctx->state[7] ^= H;
#ifdef _DEBUG
printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", ctx->state[0], ctx->state[1], ctx->state[2],
ctx->state[3], ctx->state[4], ctx->state[5], ctx->state[6], ctx->state[7]);
#endif
}
/*
* SM3 process buffer
*/
void sm3_update(sm3_context *ctx, const unsigned char *input, int ilen)
{
int fill;
uint32_t left;
if (ilen <= 0)
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t)ilen)
ctx->total[1]++;
if (left && ilen >= fill)
{
memcpy(ctx->buffer + left, input, fill);
sm3_process(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64)
{
sm3_process(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0)
{
memcpy(ctx->buffer + left, input, ilen);
}
}
static const unsigned char sm3_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SM3 final digest
*/
void sm3_finish(sm3_context *ctx, unsigned char output[32])
{
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
PUT_UINT32_BE(high, msglen, 0);
PUT_UINT32_BE(low, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
sm3_update(ctx, sm3_padding, padn);
sm3_update(ctx, msglen, 8);
PUT_UINT32_BE(ctx->state[0], output, 0);
PUT_UINT32_BE(ctx->state[1], output, 4);
PUT_UINT32_BE(ctx->state[2], output, 8);
PUT_UINT32_BE(ctx->state[3], output, 12);
PUT_UINT32_BE(ctx->state[4], output, 16);
PUT_UINT32_BE(ctx->state[5], output, 20);
PUT_UINT32_BE(ctx->state[6], output, 24);
PUT_UINT32_BE(ctx->state[7], output, 28);
}
/*
* output = SM3( input buffer )
*/
void sm3(const unsigned char *input, int ilen, unsigned char output[32])
{
sm3_context ctx;
sm3_starts(&ctx);
sm3_update(&ctx, input, ilen);
sm3_finish(&ctx, output);
memset(&ctx, 0, sizeof(sm3_context));
}
/*
* output = SM3( file contents )
*/
int sm3_file(const char *path, unsigned char output[32])
{
FILE *f;
size_t n;
sm3_context ctx;
unsigned char buf[1024];
if ((f = fopen(path, "rb")) == NULL)
return 1;
sm3_starts(&ctx);
while ((n = fread(buf, 1, sizeof(buf), f)) > 0)
sm3_update(&ctx, buf, n);
sm3_finish(&ctx, output);
memset(&ctx, 0, sizeof(sm3_context));
if (ferror(f) != 0)
{
fclose(f);
return 2;
}
fclose(f);
return 0;
}
/*
* SM3 HMAC context setup
*/
void sm3_hmac_starts(sm3_context *ctx, const unsigned char *key, int keylen)
{
int i;
unsigned char sum[32];
if (keylen > 64)
{
sm3(key, keylen, sum);
keylen = 32;
//key = sum;
key = (const unsigned char*)sum;
}
memset(ctx->ipad, 0x36, 64);
memset(ctx->opad, 0x5C, 64);
for (i = 0; i < keylen; i++)
{
ctx->ipad[i] ^= key[i];
ctx->opad[i] ^= key[i];
}
sm3_starts(ctx);
sm3_update(ctx, ctx->ipad, 64);
memset(sum, 0, sizeof(sum));
}
/*
* SM3 HMAC process buffer
*/
void sm3_hmac_update(sm3_context *ctx, const unsigned char *input, int ilen)
{
sm3_update(ctx, input, ilen);
}
/*
* SM3 HMAC final digest
*/
void sm3_hmac_finish(sm3_context *ctx, unsigned char output[32])
{
int hlen = 32;
unsigned char tmpbuf[32];
sm3_finish(ctx, tmpbuf);
sm3_starts(ctx);
sm3_update(ctx, ctx->opad, 64);
sm3_update(ctx, tmpbuf, hlen);
sm3_finish(ctx, output);
memset(tmpbuf, 0, sizeof(tmpbuf));
}
/*
* output = HMAC-SM3( hmac key, input buffer )
*/
void sm3_hmac(const unsigned char *key, int keylen,
const unsigned char *input, int ilen,
unsigned char output[32])
{
sm3_context ctx;
sm3_hmac_starts(&ctx, key, keylen);
sm3_hmac_update(&ctx, input, ilen);
sm3_hmac_finish(&ctx, output);
memset(&ctx, 0, sizeof(sm3_context));
}
// 打印缓冲区为十六进制格式
void dumpbuf(const unsigned char *buf, int len) {
for (int i = 0; i < len; i++) {
printf("%02x", buf[i]);
if (((i + 1) % 4) == 0) printf(" ");
}
printf("\n");
}
int read_file(const unsigned char *input_file, unsigned char ** text, size_t* len){
FILE* fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
// 获取文件大小并分配内存
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
int main(int argc, char *argv[])
{
if(argc < 5){
printf("usage: -kfile -file\n");
return 0;
}
if(strcmp(argv[1], "-kfile") == 0 && strcmp(argv[3], "-file") == 0){
const unsigned char *input = NULL;
const unsigned char *key = NULL;
size_t keylen = 0, ilen = 0;
if(read_file((const unsigned char*)argv[2], &key, &keylen) || read_file((const unsigned char *)argv[4], &input, &ilen)){
fprintf(stderr, "Unable to read file.\n");
return 0;
}
unsigned char output[32];
printf("Message: %s\n", input);
sm3_hmac(key, keylen, input, ilen, output);
printf("HMAC: ");
dumpbuf(output, 32);
const char *output_file = "SM3-HMAC.bin";
FILE* fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("SM3 Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(output, 1, 32, fp_out);
printf("SM3-HMAC Save ok\n");
fclose(fp_out);
}
return 0;
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm3$ '/home/liuzujing/experiment-1-from-4-to-6/sm3/sm3_hmac' '0123456789abcdef0123456789abcdef'
'/home/liuzujing/experiment-1-from-4-to-6/sm3/just.txt' '/home/liuzujing/experiment-1-from-4-to-6/sm3/hash.bin'
6e034d26659e5a75539253a0881dc9887e1a53dd85d5d667fd1a76f23108fbb2
SM4
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "gmssl/sm4.h"
#include "gmssl/rand.h"
void usage() {
printf("usage: -key\n");
printf(" -iv\n");
printf(" -e/-d -key -iv -file\n");
return;
}
int read_file(const unsigned char *input_file, unsigned char **text, size_t *len) {
FILE *fp_in = fopen(input_file, "rb");
if (!fp_in) {
perror("Error opening input file");
return 1;
}
// 获取文件大小并分配内存
fseek(fp_in, 0, SEEK_END);
*len = ftell(fp_in);
fseek(fp_in, 0, SEEK_SET);
*text = malloc(*len);
if (!*text) {
perror("Memory allocation failed");
return 0;
}
fread(*text, 1, *len, fp_in);
fclose(fp_in);
return 0;
}
int main(int argc, char *argv[]) {
if (argc == 1) {
usage();
return;
}
if (strcmp(argv[1], "-key") == 0) {
uint8_t key[SM4_KEY_SIZE];
if (rand_bytes(key, SM4_KEY_SIZE) != 1) {
fprintf(stderr, "随机密钥生成失败。\n");
return EXIT_FAILURE;
}
printf("随机生成的密钥: ");
for (size_t i = 0; i < SM4_KEY_SIZE; i++) {
printf("%02X ", key[i]);
}
printf("\n");
const char *output_file = "key.bin";
FILE *fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(key, 1, SM4_KEY_SIZE, fp_out);
printf("key Save ok\n");
fclose(fp_out);
} else if (strcmp(argv[1], "-iv") == 0) {
uint8_t iv[SM4_BLOCK_SIZE];
if (rand_bytes(iv, SM4_BLOCK_SIZE) != 1) {
fprintf(stderr, "随机IV生成失败。\n");
return EXIT_FAILURE;
}
// 打印生成的IV
printf("随机生成的IV: ");
for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) {
printf("%02X ", iv[i]);
}
printf("\n");
const char *output_file = "iv.bin";
FILE *fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(iv, 1, SM4_BLOCK_SIZE, fp_out);
printf("iv Save ok\n");
fclose(fp_out);
} else if (strcmp(argv[1], "-e") == 0) {
if (argc < 8) {
usage();
return 0;
}
if (strcmp(argv[2], "-key") != 0 || strcmp(argv[4], "-iv") != 0 || strcmp(argv[6], "-file") != 0) {
usage();
return 0;
}
unsigned char *plaintext = NULL, *key = NULL, *iv = NULL;
size_t plaintext_len = 0, key_len = 0, iv_len = 0;
if (read_file((const unsigned char *) argv[3], &key, &key_len) ||
read_file((const unsigned char *) argv[5], &iv, &iv_len) ||
read_file((const unsigned char *) argv[7], &plaintext, &plaintext_len)) {
fprintf(stderr, "Unable to read file.\n");
return 0;
}
if(key_len != SM4_KEY_SIZE || iv_len != SM4_BLOCK_SIZE){
printf("key or iv error\n");
return 0;
}
SM4_KEY enc_key;
sm4_set_encrypt_key(&enc_key, key);
size_t max_ciphertext_len = plaintext_len + SM4_BLOCK_SIZE;
uint8_t *ciphertext = malloc(max_ciphertext_len);
if (ciphertext == NULL) {
fprintf(stderr, "内存分配失败。\n");
return EXIT_FAILURE;
}
size_t outlen;
int ret;
// 加密带填充的明文
ret = sm4_cbc_padding_encrypt(&enc_key, (uint8_t *) iv, (uint8_t *)plaintext, plaintext_len, ciphertext, &outlen);
if (ret != 1) {
fprintf(stderr, "加密失败。\n");
free(ciphertext);
return EXIT_FAILURE;
}
// 输出密文(十六进制格式)
printf("密文 (%zu 字节): ", outlen);
for (size_t i = 0; i < outlen; i++) {
printf("%02X ", ciphertext[i]);
}
printf("\n");
const char *output_file = "ciphertext.txt";
FILE *fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(ciphertext, 1, outlen, fp_out);
printf("Save ok\n");
fclose(fp_out);
free(ciphertext);
} else if (strcmp(argv[1], "-d") == 0) {
unsigned char *ciphertext = NULL, *key = NULL, *iv = NULL;
size_t ciphertext_len = 0, key_len = 0, iv_len = 0;
if (argc < 8) {
usage();
return 0;
}
if (strcmp(argv[2], "-key") != 0 || strcmp(argv[4], "-iv") != 0 || strcmp(argv[6], "-file") != 0) {
usage();
return 0;
}
if (read_file((const unsigned char *) argv[3], &key, &key_len) ||
read_file((const unsigned char *) argv[5], &iv, &iv_len) ||
read_file((const unsigned char *) argv[7], &ciphertext, &ciphertext_len)) {
fprintf(stderr, "Unable to read file.\n");
return 0;
}
if(key_len != SM4_KEY_SIZE || iv_len != SM4_BLOCK_SIZE){
printf("key or iv error\n");
return 0;
}
SM4_KEY dec_key;
sm4_set_decrypt_key(&dec_key, key);
size_t max_ciphertext_len = ciphertext_len;
uint8_t *decryptedtext = malloc(max_ciphertext_len + 1); // +1用于终止符
if (decryptedtext == NULL) {
fprintf(stderr, "内存分配失败。\n");
free(ciphertext);
free(key);
free(iv);
return EXIT_FAILURE;
}
size_t outlen;
// 解密带填充的密文
int ret = sm4_cbc_padding_decrypt(&dec_key, (uint8_t *) iv, (uint8_t *) ciphertext, max_ciphertext_len,
decryptedtext, &outlen);
if (ret != 1) {
fprintf(stderr, "解密失败。\n");
free(ciphertext);
free(decryptedtext);
return EXIT_FAILURE;
}
// 确保解密后的文本是以空字符结尾的字符串
decryptedtext[outlen] = '\0';
// 打印解密后的明文(以十六进制格式)
printf("解密后的明文 (%zu 字节): ", outlen);
for (size_t i = 0; i < outlen; i++) {
printf("%02X ", decryptedtext[i]);
}
printf("\n");
const char *output_file = "decryptedtext.txt";
FILE *fp_out = fopen(output_file, "wb");
if (!fp_out) {
printf("Save Error\n");
perror("Error opening output file\n");
fclose(fp_out);
return 1;
}
fwrite(decryptedtext, 1, outlen, fp_out);
printf("Save ok\n");
fclose(fp_out);
free(decryptedtext);
} else {
usage();
return EXIT_SUCCESS;
}
}
运行结果
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm4$ '/home/liuzujing/experiment-1-from-4-to-6/sm4/gm_sm4_en_decrypt' encrypt '/home/liuzujing/experiment-1-from-4-to-6/sm4/sm4_key.pem' '/home/liuzujing/experiment-1-from-4-to-6/sm4/just.txt' '/home/liuzujing/experiment-1-from-4-to-6/sm4/sm4_kc.bin'
Encryption completed successfully.
liuzujing@liuzujing-VirtualBox:~/experiment-1-from-4-to-6/sm4$ '/home/liuzujing/experiment-1-from-4-to-6/sm4/gm_sm4_en_decrypt' decrypt '/home/liuzujing/experiment-1-from-4-to-6/sm4/sm4_key.pem' '/home/liuzujing/experiment-1-from-4-to-6/sm4/sm4_kc.bin' '/home/liuzujing/experiment-1-from-4-to-6/sm4/message.txt'
Decryption completed successfully.
两⼈⼀组,在 Ubuntu或openEuler中(推荐 openEuler)中使⽤GmSSL编程实现带签名的数字信封协议。使⽤GmSSL库时,Bob发送,Alice接收。Ailice,Bob在实验中要替换为⾃⼰的8位学号+姓名。 使⽤Markdown记录详细记录实践过程,每完成⼀项git commit ⼀次。(5分)
接收到Bob的数字信封:
liuzujing@liuzujing-VirtualBox:~$ ls 1327sm2.der 1324_c.sig lzjsm4.cbc lzjsm4.cbc3 gmssl_1324_pub.pem key.bin sm2.pem sm2.sig 1324_c.cbc3 lzj.sm3 lzjsm4.cbc2 lzj.txt iv.bin sm2.der sm2pub.pem 三个文件:1327sm2.der 1324_c.sig 1324_c.cbc3
Alice:
liuzujing@liuzujing-VirtualBox:~$ gmssl sm2verify -pubkey gmssl_1324_pub.pem -sig 1324_c.sig -in 1324_c.cbc3 verify : success liuzujing@liuzujing-VirtualBox:~$ gmssl sm2decrypt -key sm2.pem -pass 1327 -in 1327sm2.der -out gm_k.bin liuzujing@liuzujing-VirtualBox:~$ gmssl sm4_cbc -decrypt -key $(xxd -p -c 32 gm_k.bin) -iv $(xxd -p -c 32 iv.bin) -in 1324_c.cbc3 -out plain.txt liuzujing@liuzujing-VirtualBox:~$ cat plain.txt 20221324ty