实验1-2

1. 参考相关内容,在 Ubuntu或openEuler中(推荐 openEuler)中使用OpenSSL库编程实现调用SM2(加密解密,签名验签),SM3(摘要计算,HMAC 计算),SM4(加密解密)算法,使用Markdown记录详细记录实践过程,每完成一项git commit 一次。(5’)

SM2

加密解密
djy666@ubuntu:~/djy$ openssl ecparam -genkey -name SM2 -out private_key.pem
djy666@ubuntu:~/djy$ cat private_key.pem
-----BEGIN SM2 PARAMETERS-----
BggqgRzPVQGCLQ==
-----END SM2 PARAMETERS-----
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgdyzordRMyhIe5PmF
Y5oPPok6e3Vlii2CLSIs3E5GoUehRANCAAT0bfIm3qIYFxltwUQ3igqUIFCBjKiY
kmD6wHzJh76wChldmcH5XVIiBVTXqtK/3RxyjLJEVuT1M269U/FMOUn5
-----END PRIVATE KEY-----
djy666@ubuntu:~/djy$ vim encrypted_file
djy666@ubuntu:~/djy$ vim decrypted_file
djy666@ubuntu:~/djy$ vim sm2_encrypt.c
djy666@ubuntu:~/djy$ gcc -o sm2_encrypt sm2_encrypt.c -lcrypto
djy666@ubuntu:~/djy$ vim sm2_decrypt.c
djy666@ubuntu:~/djy$ gcc -o sm2_decrypt sm2_decrypt.c -lcrypto
djy666@ubuntu:~/djy$ openssl pkey -in private_key.pem -pubout -out public_key.pem
djy666@ubuntu:~/djy$ cat public_key.pem
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE9G3yJt6iGBcZbcFEN4oKlCBQgYyo
mJJg+sB8yYe+sAoZXZnB+V1SIgVU16rSv90ccoyyRFbk9TNuvVPxTDlJ+Q==
-----END PUBLIC KEY-----
djy666@ubuntu:~/djy$ vim plain.txt
djy666@ubuntu:~/djy$ ./sm2_encrypt public_key.pem  plain.txt encrypted_file
Encryption complete.
djy666@ubuntu:~/djy$ ./sm2_decrypt private_key.pem encrypted_file decrypted_file
Decryption successful.

git commit

djy666@ubuntu:~/djy$ git commit -m "sm2_test"
[master d747d30] sm2_test
 19 files changed, 409 insertions(+)
 create mode 100644 decrypted_file
 create mode 100644 encrypted_file
 create mode 100644 plain.txt
 create mode 100644 private_key.pem
 create mode 100644 public_key.pem
 create mode 100755 sm2_decrypt
 create mode 100644 sm2_decrypt.c
 create mode 100755 sm2_encrypt
 create mode 100644 sm2_encrypt.c
 create mode 100644 sm2_test/private_key.pem

代码

  • sm2_encrypt.c
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <stdio.h>
#include <stdlib.h>

void handleErrors(void) {
    fprintf(stderr, "An error occurred.\n");
    exit(1);
}

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <public_key.pem> <input file> <output file>\n", argv[0]);
        return 1;
    }

    char *public_key_filename = argv[1];
    char *input_file = argv[2];
    char *output_file = argv[3];

    FILE *f_input, *f_output, *f_public_key;
    unsigned char buffer[1024];
    unsigned char *ciphertext;
    size_t ciphertext_len;
    size_t bytes_read;

    EVP_PKEY *public_key = NULL;
    EVP_PKEY_CTX *ctx = NULL;

    if (!(f_public_key = fopen(public_key_filename, "r"))) {
        fprintf(stderr, "Unable to open public key file %s\n", public_key_filename);
        return 1;
    }

    if (!(public_key = PEM_read_PUBKEY(f_public_key, NULL, NULL, NULL))) {
        fprintf(stderr, "Error loading public key\n");
        fclose(f_public_key);
        return 1;
    }
    fclose(f_public_key);

    if (!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL))
        handleErrors();

    if (!(ctx = EVP_PKEY_CTX_new(public_key, NULL)))
        handleErrors();

    if (EVP_PKEY_encrypt_init(ctx) <= 0)
        handleErrors();

    if (!(f_input = fopen(input_file, "rb"))) {
        fprintf(stderr, "Could not open %s for reading\n", input_file);
        return 1;
    }
    if (!(f_output = fopen(output_file, "wb"))) {
        fprintf(stderr, "Could not open %s for writing\n", output_file);
        return 1;
    }

    if (EVP_PKEY_encrypt(ctx, NULL, &ciphertext_len, buffer, sizeof(buffer)) <= 0)
        handleErrors();
    ciphertext = malloc(ciphertext_len);
    if (!ciphertext) {
        fprintf(stderr, "Memory allocation failed\n");
        return 1;
    }

    while ((bytes_read = fread(buffer, 1, sizeof(buffer), f_input)) > 0) {
        if (EVP_PKEY_encrypt(ctx, ciphertext, &ciphertext_len, buffer, bytes_read) <= 0)
            handleErrors();
        fwrite(ciphertext, 1, ciphertext_len, f_output);
    }

    EVP_PKEY_free(public_key);
    EVP_PKEY_CTX_free(ctx);
    fclose(f_input);
    fclose(f_output);
    free(ciphertext);

    printf("Encryption complete.\n");
    return 0;
}
  • sm2_decrypt.c
#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <stdio.h>
#include <stdlib.h>

void handle_errors() {
    ERR_print_errors_fp(stderr);
    abort();
}

int main(int argc, char **argv) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <private_key.pem> <encrypted_file> <decrypted_file>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *private_key_file = argv[1];
    const char *encrypted_file = argv[2];
    const char *decrypted_file = argv[3];

    EVP_PKEY *private_key = NULL;
    FILE *fp;
    fp = fopen(private_key_file, "r");
    if (!fp) {
        perror("Error opening private key file");
        return EXIT_FAILURE;
    }
    private_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
    fclose(fp);
    if (!private_key) {
        handle_errors();
        return EXIT_FAILURE;
    }

    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(private_key, NULL);
    if (!ctx) {
        handle_errors();
        return EXIT_FAILURE;
    }
    if (EVP_PKEY_decrypt_init(ctx) <= 0) {
        handle_errors();
        return EXIT_FAILURE;
    }

    FILE *fin = fopen(encrypted_file, "rb");
    if (!fin) {
        perror("Error opening encrypted file");
        return EXIT_FAILURE;
    }
    fseek(fin, 0, SEEK_END);
    long encrypted_data_size = ftell(fin);
    fseek(fin, 0, SEEK_SET);
    unsigned char *encrypted_data = malloc(encrypted_data_size);
    fread(encrypted_data, 1, encrypted_data_size, fin);
    fclose(fin);

    unsigned char *decrypted_data = NULL;
    size_t decrypted_data_size = 0;
    if (EVP_PKEY_decrypt(ctx, NULL, &decrypted_data_size, encrypted_data, encrypted_data_size) <= 0) {
        handle_errors();
        return EXIT_FAILURE;
    }
    decrypted_data = malloc(decrypted_data_size);
    if (EVP_PKEY_decrypt(ctx, decrypted_data, &decrypted_data_size, encrypted_data, encrypted_data_size) <= 0) {
        handle_errors();
        return EXIT_FAILURE;
    }

    FILE *fout = fopen(decrypted_file, "wb");
    if (!fout) {
        perror("Error opening decrypted file");
        return EXIT_FAILURE;
    }
    fwrite(decrypted_data, 1, decrypted_data_size, fout);
    fclose(fout);

    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(private_key);
    free(encrypted_data);
    free(decrypted_data);

    printf("Decryption successful.\n");
    return EXIT_SUCCESS;
}
签名验签
djy666@ubuntu:~/djy$ vim sign.c
djy666@ubuntu:~/djy$ gcc sign.c -o sign -lcrypto
djy666@ubuntu:~/djy$ vim sign_file
djy666@ubuntu:~/djy$ ./sign private_key.pem plain.txt  sign_file
Signature successfully written to sign_file
djy666@ubuntu:~/djy$ vim verify.c
djy666@ubuntu:~/djy$ gcc verify.c -o verify -lcrypto
djy666@ubuntu:~/djy$ ./verify public_key.pem plain.txt sign_file
Signature verification successful!

git commit

djy666@ubuntu:~/djy$ git commit -m "sm2_test"
[master 097fb6a] sm2_test
 5 files changed, 208 insertions(+)
 create mode 100755 sign
 create mode 100644 sign.c
 create mode 100644 sign_file
 create mode 100755 verify
 create mode 100644 verify.c

代码

  • sign.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>

void handle_errors() {
    ERR_print_errors_fp(stderr);
    abort();
}

void sign_file(const char *private_key_file, const char *input_file, const char *output_file) {
    FILE *fp = fopen(input_file, "rb");
    if (!fp) {
        perror("Unable to open input file");
        exit(EXIT_FAILURE);
    }

    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    unsigned char *data = malloc(file_size);
    if (!data) {
        perror("Unable to allocate memory");
        fclose(fp);
        exit(EXIT_FAILURE);
    }
    fread(data, 1, file_size, fp);
    fclose(fp);

    FILE *key_fp = fopen(private_key_file, "r");
    if (!key_fp) {
        perror("Unable to open private key file");
        free(data);
        exit(EXIT_FAILURE);
    }

    EVP_PKEY *pkey = PEM_read_PrivateKey(key_fp, NULL, NULL, NULL);
    fclose(key_fp);
    if (!pkey) {
        handle_errors();
    }

    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    if (!ctx) {
        handle_errors();
    }

    if (EVP_DigestSignInit(ctx, NULL, EVP_sm3(), NULL, pkey) != 1) {
        handle_errors();
    }

    if (EVP_DigestSignUpdate(ctx, data, file_size) != 1) {
        handle_errors();
    }

    size_t sig_len;
    if (EVP_DigestSignFinal(ctx, NULL, &sig_len) != 1) {
        handle_errors();
    }

    unsigned char *sig = malloc(sig_len);
    if (!sig) {
        perror("Unable to allocate memory for signature");
        EVP_MD_CTX_free(ctx);
        EVP_PKEY_free(pkey);
        free(data);
        exit(EXIT_FAILURE);
    }

    if (EVP_DigestSignFinal(ctx, sig, &sig_len) != 1) {
        handle_errors();
    }

    FILE *out_fp = fopen(output_file, "wb");
    if (!out_fp) {
        perror("Unable to open output file");
        free(sig);
        EVP_MD_CTX_free(ctx);
        EVP_PKEY_free(pkey);
        free(data);
        exit(EXIT_FAILURE);
    }

    fwrite(sig, 1, sig_len, out_fp);
    fclose(out_fp);

    printf("Signature successfully written to %s\n", output_file);

    free(sig);
    EVP_MD_CTX_free(ctx);
    EVP_PKEY_free(pkey);
    free(data);
}

int main(int argc, char **argv) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <private_key.pem> <input_file> <output_file>\n", argv[0]);
        return EXIT_FAILURE;
    }
    sign_file(argv[1], argv[2], argv[3]);
    return EXIT_SUCCESS;
}
  • verify.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>

void handle_errors() {
    ERR_print_errors_fp(stderr);
    abort();
}

int verify_signature(const char *public_key_file, const char *input_file, const char *signature_file) {
    FILE *fp = fopen(input_file, "rb");
    if (!fp) {
        perror("Unable to open input file");
        return EXIT_FAILURE;
    }

    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    unsigned char *data = malloc(file_size);
    if (!data) {
        perror("Unable to allocate memory");
        fclose(fp);
        return EXIT_FAILURE;
    }
    fread(data, 1, file_size, fp);
    fclose(fp);

    FILE *sig_fp = fopen(signature_file, "rb");
    if (!sig_fp) {
        perror("Unable to open signature file");
        free(data);
        return EXIT_FAILURE;
    }

    fseek(sig_fp, 0, SEEK_END);
    long sig_size = ftell(sig_fp);
    fseek(sig_fp, 0, SEEK_SET);
    unsigned char *signature = malloc(sig_size);
    if (!signature) {
        perror("Unable to allocate memory for signature");
        fclose(sig_fp);
        free(data);
        return EXIT_FAILURE;
    }
    fread(signature, 1, sig_size, sig_fp);
    fclose(sig_fp);

    FILE *key_fp = fopen(public_key_file, "r");
    if (!key_fp) {
        perror("Unable to open public key file");
        free(signature);
        free(data);
        return EXIT_FAILURE;
    }

    EVP_PKEY *pkey = PEM_read_PUBKEY(key_fp, NULL, NULL, NULL);
    fclose(key_fp);
    if (!pkey) {
        handle_errors();
    }

    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    if (!ctx) {
        handle_errors();
    }

    if (EVP_DigestVerifyInit(ctx, NULL, EVP_sm3(), NULL, pkey) != 1) {
        handle_errors();
    }

    if (EVP_DigestVerifyUpdate(ctx, data, file_size) != 1) {
        handle_errors();
    }

    int ret = EVP_DigestVerifyFinal(ctx, signature, sig_size);
    if (ret == 1) {
        printf("Signature verification successful!\n");
    } else {
        printf("Signature verification failed!\n");
    }

    EVP_MD_CTX_free(ctx);
    EVP_PKEY_free(pkey);
    free(signature);
    free(data);

    return ret == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
}

int main(int argc, char **argv) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <public_key.pem> <input_file> <signature_file>\n", argv[0]);
        return EXIT_FAILURE;
    }
    return verify_signature(argv[1], argv[2], argv[3]);
}

SM3

摘要计算
djy666@ubuntu:~/djy/sm3_openssl$ vim hmac.c
djy666@ubuntu:~/djy/sm3_openssl$ vim hash.c
djy666@ubuntu:~/djy/sm3_openssl$ gcc -o hash hash.c -lcrypto
djy666@ubuntu:~/djy/sm3_openssl$ ./hash
Usage: ./hash <string_to_hash>
djy666@ubuntu:~/djy/sm3_openssl$ ./hash "20221413djy"
SM3 hash: 96f664b88bf6c381bd9af7ceda65641db5b32253b268d1a697c67284b35eec02

代码

  • digest.c
#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>

void sm3_hash(const char* data) {
    EVP_MD_CTX* mdctx;
    const EVP_MD* md;
    unsigned char md_value[EVP_MAX_MD_SIZE];
    unsigned int md_len;

    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("sm3");
    if (md == NULL) {
        printf("Unknown message digest sm3\n");
        return;
    }

    mdctx = EVP_MD_CTX_new();
    EVP_DigestInit_ex(mdctx, md, NULL);

    EVP_DigestUpdate(mdctx, data, strlen(data));

    EVP_DigestFinal_ex(mdctx, md_value, &md_len);

    printf("SM3 hash: ");
    for (int i = 0; i < md_len; i++) {
        printf("%02x", md_value[i]);
    }
    printf("\n");

    EVP_MD_CTX_free(mdctx);
    EVP_cleanup();
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("Usage: %s <string_to_hash>\n", argv[0]);
        return 1;
    }
    sm3_hash(argv[1]);
    return 0;
}
HMAC计算
djy666@ubuntu:~/djy/sm3_openssl$ vim hmac.c
djy666@ubuntu:~/djy/sm3_openssl$ gcc -o hmac hmac.c -lcrypto
djy666@ubuntu:~/djy/sm3_openssl$ ./hmac
Usage: ./hmac <key> <data>
djy666@ubuntu:~/djy/sm3_openssl$ ./hmac "1413" "dujiayan"
HMAC: 8ef98d45b1a83432d935be9d87d028376151f3360051f72b72b6cc5b64f29629

代码

  • hmac.c
#include <stdio.h>
#include <openssl/evp.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <key> <data>\n", argv[0]);
        return 1;
    }

    unsigned char *key = (unsigned char *)argv[1];
    unsigned char *data = (unsigned char *)argv[2];
    size_t key_len = strlen((char *)key);
    size_t data_len = strlen((char *)data);

    EVP_MAC_CTX *ctx;
    EVP_MAC *mac;
    OSSL_PARAM params[2];
    unsigned char *out;
    size_t out_len;

    mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
    ctx = EVP_MAC_CTX_new(mac);

    params[0] = OSSL_PARAM_construct_utf8_string("digest", "SM3", 0);
    params[1] = OSSL_PARAM_construct_end();

    if (!EVP_MAC_init(ctx, key, key_len, params)) {
        fprintf(stderr, "Failed to initialize HMAC\n");
        return 1;
    }

    if (!EVP_MAC_update(ctx, data, data_len)) {
        fprintf(stderr, "Failed to update HMAC\n");
        return 1;
    }

    EVP_MAC_final(ctx, NULL, &out_len, 0);
    out = malloc(out_len);

    if (!EVP_MAC_final(ctx, out, &out_len, out_len)) {
        fprintf(stderr, "Failed to finalize HMAC\n");
        return 1;
    }

    printf("HMAC: ");
    for (size_t i = 0; i < out_len; i++) {
        printf("%02x", out[i]);
    }
    printf("\n");

    EVP_MAC_CTX_free(ctx);
    EVP_MAC_free(mac);
    free(out);

    return 0;
}

SM4

加密解密
djy666@ubuntu:~/djy/sm4_test$ vim plaint.txt
djy666@ubuntu:~/djy/sm4_test$ vim encrypt.c
djy666@ubuntu:~/djy/sm4_test$ gcc -o encrypt encrypt.c -lcrypto
djy666@ubuntu:~/djy/sm4_test$ touch encrypt.bin
djy666@ubuntu:~/djy/sm4_test$ ./encrypt
Usage: ./encrypt <key> <iv> <input file> <output file>
djy666@ubuntu:~/djy/sm4_test$ ./encrypt 1234567812345678 1111111111111111 plain.txt encrypt.bin
Encryption complete.
djy666@ubuntu:~/djy/sm4_test$ vim decrypt.c
djy666@ubuntu:~/djy/sm4_test$ vim decrypt_file
djy666@ubuntu:~/djy/sm4_test$ gcc -o decrypt decrypt.c -lcrypto
djy666@ubuntu:~/djy/sm4_test$ ./decrypt 1234567812345678 1111111111111111 encrypt.bin decrypt_file
Decryption complete.

git commit

djy666@ubuntu:~/djy/sm4_test$ git commit -m "sm4_test"
[master 1802d70] sm4_test
 9 files changed, 132 insertions(+)
 create mode 100755 sm4_test/decrypt
 create mode 100644 sm4_test/decrypt.c
 create mode 100644 sm4_test/decrypt_file
 create mode 100755 sm4_test/encrypt
 create mode 100644 sm4_test/encrypt.bin
 create mode 100644 sm4_test/encrypt.c
 create mode 100644 sm4_test/encrypt_file
 create mode 100644 sm4_test/plain.txt
 create mode 100644 sm4_test/plaint.txt

代码

  • encrypt.c
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>

void handleErrors(void) {
    fprintf(stderr, "An error occurred.\n");
    exit(1);
}

int main(int argc, char *argv[]) {
    if (argc != 5) {
        fprintf(stderr, "Usage: %s <key> <iv> <input file> <output file>\n", argv[0]);
        return 1;
    }

    char *key = argv[1];
    char *iv = argv[2];
    char *input_file = argv[3];
    char *output_file = argv[4];

    FILE *f_input, *f_output;
    unsigned char buffer[1024];
    unsigned char ciphertext[1024 + EVP_MAX_BLOCK_LENGTH];
    int bytes_read, ciphertext_len;

    EVP_CIPHER_CTX *ctx;

    // Initialise the library
    if(!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL))
        handleErrors();

    // Create and initialise the context
    if(!(ctx = EVP_CIPHER_CTX_new())) 
        handleErrors();

    // Initialise the encryption operation.
    if(1 != EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, (unsigned char*)key, (unsigned char*)iv))
        handleErrors();

    // Open files
    if(!(f_input = fopen(input_file, "rb"))) {
        fprintf(stderr, "Could not open %s for reading\n", input_file);
        return 1;
    }

    if(!(f_output = fopen(output_file, "wb"))) {
        fprintf(stderr, "Could not open %s for writing\n", output_file);
        return 1;
    }

    // Provide the message to be encrypted
    while((bytes_read = fread(buffer, 1, 1024, f_input)) > 0) {
        if(1 != EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, buffer, bytes_read))
            handleErrors();
        fwrite(ciphertext, 1, ciphertext_len, f_output);
    }

    // Finalise the encryption
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &ciphertext_len))
        handleErrors();
    fwrite(ciphertext, 1, ciphertext_len, f_output);

    // Clean up
    EVP_CIPHER_CTX_free(ctx);
    fclose(f_input);
    fclose(f_output);

    printf("Encryption complete.\n");

    return 0;
}
  • decrypt.c
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>

void handleErrors(void) {
    fprintf(stderr, "An error occurred.\n");
    exit(1);
}

int main(int argc, char *argv[]) {
    if (argc != 5) {
        fprintf(stderr, "Usage: %s <key> <iv> <input file> <output file>\n", argv[0]);
        return 1;
    }

    char *key = argv[1];
    char *iv = argv[2];
    char *input_file = argv[3];
    char *output_file = argv[4];

    FILE *f_input, *f_output;
    unsigned char buffer[1024];
    unsigned char plaintext[1024 + EVP_MAX_BLOCK_LENGTH];
    int bytes_read, plaintext_len;

    EVP_CIPHER_CTX *ctx;

    // Initialise the library
    if(!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL))
        handleErrors();

    // Create and initialise the context
    if(!(ctx = EVP_CIPHER_CTX_new())) 
        handleErrors();

    // Initialise the decryption operation.
    if(1 != EVP_DecryptInit_ex(ctx, EVP_sm4_cbc(), NULL, (unsigned char*)key, (unsigned char*)iv))
        handleErrors();

    // Open files
    if(!(f_input = fopen(input_file, "rb"))) {
        fprintf(stderr, "Could not open %s for reading\n", input_file);
        return 1;
    }

    if(!(f_output = fopen(output_file, "wb"))) {
        fprintf(stderr, "Could not open %s for writing\n", output_file);
        return 1;
    }

    // Provide the message to be decrypted
    while((bytes_read = fread(buffer, 1, 1024, f_input)) > 0) {
        if(1 != EVP_DecryptUpdate(ctx, plaintext, &plaintext_len, buffer, bytes_read))
            handleErrors();
        fwrite(plaintext, 1, plaintext_len, f_output);
    }

    // Finalise the decryption
    if(1 != EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &plaintext_len))
        handleErrors();
    fwrite(plaintext, 1, plaintext_len, f_output);

    // Clean up
    EVP_CIPHER_CTX_free(ctx);
    fclose(f_input);
    fclose(f_output);

    printf("Decryption complete.\n");
    return 0;
}

2. 参考相关内容,在 Ubuntu或openEuler中(推荐 openEuler)中使用GmSSL库编程实现调用SM2(加密解密,签名验签),SM3(摘要计算,HMAC 计算),SM4(加密解密)算法,使用Markdown记录详细记录实践过程,每完成一项git commit 一次。(5’)

SM2

加密
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_keygen.c
djy666@ubuntu:~/djy/sm2_gmssl$ gcc -o sm2_keygen sm2_keygen.c -lgmssl
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_keygen
Usage: ./sm2_keygen <private_key_file> <public_key_file>
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_keygen sm2_private_key.pem sm2_public_key.pem
SM2 key pair generated successfully.
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_encrypt.c
djy666@ubuntu:~/djy/sm2_gmssl$ gcc -o sm2_encrypt sm2_encrypt.c -lgmssl
djy666@ubuntu:~/djy/sm2_gmssl$ ls
plain.txt  sm2_encrypt  sm2_encrypt.c  sm2_keygen  sm2_keygen.c  sm2_private_key.pem  sm2_public_key.pem
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_encrypt
Usage: sm2_encrypt <public_key.pem> <input_file> <output_file>
djy666@ubuntu:~/djy/sm2_gmssl$ touch encrypt_file.bin
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_encrypt sm2_public_key.pem plain.txt encrypt_file.bin
Encryption successful, output written to encrypt_file.bin
djy666@ubuntu:~/djy/sm2_gmssl$ vim encrypt_file.bin

代码

  • keygen.c
#include <stdio.h>
#include <stdlib.h>
#include <gmssl/sm2.h>
#include <gmssl/error.h>
#include <gmssl/pem.h>

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <private_key_file> <public_key_file>\n", argv[0]);
        return 1;
    }

    const char *private_key_file = argv[1];
    const char *public_key_file = argv[2];

    SM2_KEY sm2_key;
    FILE *fp;

    if (sm2_key_generate(&sm2_key) != 1) {
        fprintf(stderr, "Failed to generate SM2 key pair.\n");
        return 1;
    }

    if (!(fp = fopen(private_key_file, "wb"))) {
        perror("Failed to open private key file");
        return 1;
    }
    if (sm2_private_key_info_to_pem(&sm2_key, fp) != 1) {
        fprintf(stderr, "Failed to write private key to file.\n");
        fclose(fp);
        return 1;
    }
    fclose(fp);

    if (!(fp = fopen(public_key_file, "wb"))) {
        perror("Failed to open public key file");
        return 1;
    }
    if (sm2_public_key_info_to_pem(&sm2_key, fp) != 1) {
        fprintf(stderr, "Failed to write public key to file.\n");
        fclose(fp);
        return 1;
    }
    fclose(fp);

    printf("SM2 key pair generated successfully.\n");
    return 0;
}
  • sm2_encrypt.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/sm2.h>
#include <gmssl/pem.h>

#define SM2_CIPHERTEXT_SIZE 1024

void print_usage() {
    printf("Usage: sm2_encrypt <public_key.pem> <input_file> <output_file>\n");
}

int main(int argc, char *argv[]) {
    if (argc != 4) {
        print_usage();
        return 1;
    }

    const char *public_key_file = argv[1];
    const char *input_file = argv[2];
    const char *output_file = argv[3];

    SM2_KEY sm2_key;
    FILE *fp = fopen(public_key_file, "r");
    if (!fp) {
        perror("Failed to open public key file");
        return 1;
    }

    if (sm2_public_key_info_from_pem(&sm2_key, fp) != 1) {
        fprintf(stderr, "Failed to read public key from PEM\n");
        fclose(fp);
        return 1;
    }
    fclose(fp);

    FILE *in_fp = fopen(input_file, "rb");
    if (!in_fp) {
        perror("Failed to open input file");
        return 1;
    }

    fseek(in_fp, 0, SEEK_END);
    long input_len = ftell(in_fp);
    fseek(in_fp, 0, SEEK_SET);
    unsigned char *input_data = malloc(input_len);
    if (fread(input_data, 1, input_len, in_fp) != input_len) {
        perror("Failed to read input file");
        free(input_data);
        fclose(in_fp);
        return 1;
    }
    fclose(in_fp);

    unsigned char ciphertext[SM2_CIPHERTEXT_SIZE];
    size_t ciphertext_len = sizeof(ciphertext);
    
    if (sm2_encrypt(&sm2_key, input_data, input_len, ciphertext, &ciphertext_len) != 1) {
        fprintf(stderr, "SM2 encryption failed\n");
        free(input_data);
        return 1;
    }

    free(input_data);

    FILE *out_fp = fopen(output_file, "wb");
    if (!out_fp) {
        perror("Failed to open output file");
        return 1;
    }

    if (fwrite(ciphertext, 1, ciphertext_len, out_fp) != ciphertext_len) {
        perror("Failed to write output file");
        fclose(out_fp);
        return 1;
    }
    fclose(out_fp);

    printf("Encryption successful, output written to %s\n", output_file);
    return 0;
}
解密
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_decrypt.c
djy666@ubuntu:~/djy/sm2_gmssl$ rm sm2_decrypt.c
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_decrypt.c
djy666@ubuntu:~/djy/sm2_gmssl$ rm sm2_decrypt.c
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_decrypt.c
djy666@ubuntu:~/djy/sm2_gmssl$ gcc -o sm2_decrypt sm2_decrypt.c -lgmssl
djy666@ubuntu:~/djy/sm2_gmssl$ ls
encrypt_file.bin  sm2_decrypt    sm2_encrypt    sm2_keygen    sm2_private_key.pem
plain.txt         sm2_decrypt.c  sm2_encrypt.c  sm2_keygen.c  sm2_public_key.pem
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_decrypt
Usage: sm2_decrypt <private_key.pem> <input_file> <output_file>
djy666@ubuntu:~/djy/sm2_gmssl$ touch decrypt_file.bin
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_decrypt sm2_private_key.pem encrypt_file.bin decrypt_file.bin
/home/djy/GmSSL/src/asn1.c:1932:asn1_length_is_zero():
/home/djy/GmSSL/src/sm2_enc.c:517:sm2_decrypt():
SM2 decryption failed
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_encrypt sm2_public_key.pem plain.txt encrypt_file.bin
Encryption successful, output written to encrypt_file.bin
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_decrypt sm2_private_key.pem encrypt_file.bin decrypt_file.bin
Decryption successful, output written to decrypt_file.bin
djy666@ubuntu:~/djy/sm2_gmssl$ vim decrypt_file.bin

代码

  • sm2_decrypt.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/sm2.h>
#include <gmssl/pem.h>

#define SM2_CIPHERTEXT_SIZE 1024

void print_usage() {
    printf("Usage: sm2_decrypt <private_key.pem> <input_file> <output_file>\n");
}

int main(int argc, char *argv[]) {
    if (argc != 4) {
        print_usage();
        return 1;
    }

    const char *private_key_file = argv[1];
    const char *input_file = argv[2];
    const char *output_file = argv[3];

    SM2_KEY sm2_key;
    FILE *fp = fopen(private_key_file, "r");
    if (!fp) {
        perror("Failed to open private key file");
        return 1;
    }

    if (sm2_private_key_info_from_pem(&sm2_key, fp) != 1) {
        fprintf(stderr, "Failed to read private key from PEM\n");
        fclose(fp);
        return 1;
    }
    fclose(fp);

    FILE *in_fp = fopen(input_file, "rb");
    if (!in_fp) {
        perror("Failed to open input file");
        return 1;
    }

    fseek(in_fp, 0, SEEK_END);
    long input_len = ftell(in_fp);
    fseek(in_fp, 0, SEEK_SET);
    unsigned char *ciphertext = malloc(input_len);
    if (fread(ciphertext, 1, input_len, in_fp) != input_len) {
        perror("Failed to read input file");
        free(ciphertext);
        fclose(in_fp);
        return 1;
    }
    fclose(in_fp);

    unsigned char decrypted[SM2_CIPHERTEXT_SIZE];
    size_t decrypted_len = sizeof(decrypted);
    
    if (sm2_decrypt(&sm2_key, ciphertext, input_len, decrypted, &decrypted_len) != 1) {
        fprintf(stderr, "SM2 decryption failed\n");
        free(ciphertext);
        return 1;
    }

    free(ciphertext);

    FILE *out_fp = fopen(output_file, "wb");
    if (!out_fp) {
        perror("Failed to open output file");
        return 1;
    }

    if (fwrite(decrypted, 1, decrypted_len, out_fp) != decrypted_len) {
        perror("Failed to write output file");
        fclose(out_fp);
        return 1;
    }
    fclose(out_fp);

    printf("Decryption successful, output written to %s\n", output_file);
    return 0;
}
签名验签
djy666@ubuntu:~/djy/sm2_gmssl$ ls
decrypt_file.bin  plain.txt    sm2_decrypt.c  sm2_encrypt.c  sm2_keygen.c         sm2_public_key.pem
encrypt_file.bin  sm2_decrypt  sm2_encrypt    sm2_keygen     sm2_private_key.pem  sm2_sign.c
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_sign.c
djy666@ubuntu:~/djy/sm2_gmssl$ gcc -o sm2_sign sm2_sign.c -lgmssl
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_sign
Usage: ./sm2_sign <private_key.pem> <input.txt> <signature.sig>
djy666@ubuntu:~/djy/sm2_gmssl$ touch signature.sig
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_sign sm2_private_key.pem plain.txt signature.sig
Signature generated and saved to signature.sig
djy666@ubuntu:~/djy/sm2_gmssl$ vim sm2_verify.c
djy666@ubuntu:~/djy/sm2_gmssl$ gcc -o sm2_verify sm2_verify.c -lgmssl
djy666@ubuntu:~/djy/sm2_gmssl$ ls
decrypt_file.bin  signature.sig  sm2_encrypt    sm2_keygen.c         sm2_sign    sm2_verify.c
encrypt_file.bin  sm2_decrypt    sm2_encrypt.c  sm2_private_key.pem  sm2_sign.c
plain.txt         sm2_decrypt.c  sm2_keygen     sm2_public_key.pem   sm2_verify
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_verify
Usage: ./sm2_verify <public key PEM file> <input file> <signature file>
djy666@ubuntu:~/djy/sm2_gmssl$ ./sm2_verify sm2_public_key.pem plain.txt signature.sig
Signature is valid.

git commit

djy666@ubuntu:~/djy/sm2_gmssl$ git add .
djy666@ubuntu:~/djy/sm2_gmssl$ git commit -m "sm2_sign & sm2_verify"
[master a18c4fd] sm2_sign & sm2_verify
 5 files changed, 162 insertions(+)
 create mode 100644 sm2_gmssl/signature.sig
 create mode 100755 sm2_gmssl/sm2_sign
 create mode 100644 sm2_gmssl/sm2_sign.c
 create mode 100755 sm2_gmssl/sm2_verify
 create mode 100644 sm2_gmssl/sm2_verify.c

代码

  • sm2_sign.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/sm2.h>
#include <gmssl/pem.h>
#include <gmssl/error.h>
#include <gmssl/sm3.h>

int main(int argc, char **argv)
{
    if (argc != 4) {
        printf("Usage: %s <private_key.pem> <input.txt> <signature.sig>\n", argv[0]);
        return 1;
    }

    const char *private_key_file = argv[1];
    const char *input_file = argv[2];
    const char *signature_file = argv[3];

    SM2_KEY sm2_key;
    FILE *key_fp = NULL;
    FILE *input_fp = NULL;
    FILE *sig_fp = NULL;
    unsigned char dgst[32];
    unsigned char sig[SM2_MAX_SIGNATURE_SIZE];
    size_t siglen;
    unsigned char buffer[1024];
    size_t len;

    key_fp = fopen(private_key_file, "r");
    if (!key_fp) {
        perror("Failed to open private key file");
        return 1;
    }

    if (sm2_private_key_info_from_pem(&sm2_key, key_fp) != 1) {
        fprintf(stderr, "Failed to read private key from PEM\n");
        fclose(key_fp);
        return 1;
    }
    fclose(key_fp);

    input_fp = fopen(input_file, "r");
    if (!input_fp) {
        fprintf(stderr, "Error opening input file: %s\n", input_file);
        return 1;
    }

    SM3_CTX sm3_ctx;
    sm3_init(&sm3_ctx);

    while ((len = fread(buffer, 1, sizeof(buffer), input_fp)) > 0) {
        sm3_update(&sm3_ctx, buffer, len);
    }
    fclose(input_fp);

    sm3_finish(&sm3_ctx, dgst);

    siglen = sizeof(sig);
    if (sm2_sign(&sm2_key, dgst, sig, &siglen) != 1) {
        fprintf(stderr, "Error generating SM2 signature\n");
        return 1;
    }

    sig_fp = fopen(signature_file, "wb");
    if (!sig_fp) {
        fprintf(stderr, "Error opening signature file: %s\n", signature_file);
        return 1;
    }

    if (fwrite(sig, 1, siglen, sig_fp) != siglen) {
        fprintf(stderr, "Error writing signature to file: %s\n", signature_file);
        fclose(sig_fp);
        return 1;
    }
    fclose(sig_fp);

    printf("Signature generated and saved to %s\n", signature_file);
    return 0;
}
  • sm2_verify.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
#include <gmssl/pem.h>
#include <gmssl/error.h>

int main(int argc, char **argv) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <public key PEM file> <input file> <signature file>\n", argv[0]);
        return 1;
    }

    const char *pubkey_filename = argv[1];
    const char *input_filename = argv[2];
    const char *signature_filename = argv[3];

    SM2_KEY key;
    FILE *fp;
    SM3_CTX sm3_ctx;
    uint8_t dgst[32];
    if (!(fp = fopen(pubkey_filename, "r"))) {
        perror("Error opening public key file");
        return 1;
    }
    if (!sm2_public_key_info_from_pem(&key, fp)) {
        fprintf(stderr, "Error reading public key from PEM file %s\n", pubkey_filename);
        fclose(fp);
        return 1;
    }
    fclose(fp);

    if (!(fp = fopen(input_filename, "rb"))) {
        perror("Error opening input file");
        return 1;
    }
    
    sm3_init(&sm3_ctx);
    unsigned char buf[1024];
    size_t len;
    while ((len = fread(buf, 1, sizeof(buf), fp)) > 0) {
        sm3_update(&sm3_ctx, buf, len);
    }
    if (ferror(fp)) {
        fprintf(stderr, "Error reading input file %s\n", input_filename);
        fclose(fp);
        return 1;
    }
    sm3_finish(&sm3_ctx, dgst);
    fclose(fp);

    unsigned char signature[256];
    size_t siglen;
    if (!(fp = fopen(signature_filename, "rb"))) {
        perror("Error opening signature file");
        return 1;
    }
    siglen = fread(signature, 1, sizeof(signature), fp);
    if (ferror(fp)) {
        fprintf(stderr, "Error reading signature file %s\n", signature_filename);
        fclose(fp);
        return 1;
    }
    fclose(fp);
    if (siglen == 0) {
        fprintf(stderr, "Signature file %s is empty or could not be read.\n", signature_filename);
        return 1;
    }

    int verify_result = sm2_verify(&key, dgst, signature, siglen);
    if (verify_result == 1) {
        printf("Signature is valid.\n");
    } else {
        fprintf(stderr, "Signature is invalid. Please check the public key, input file, and signature file.\n");
        return 1;
    }

    return 0;
}

SM3

摘要
djy666@ubuntu:~/djy/sm3_gmssl$ vim plain.txt
djy666@ubuntu:~/djy/sm3_gmssl$ vim sm3_hash.c
djy666@ubuntu:~/djy/sm3_gmssl$ ls
plain.txt  sm3_hash.c
djy666@ubuntu:~/djy/sm3_gmssl$ gcc -o sm3_hash sm3_hash.c -lgmssl
djy666@ubuntu:~/djy/sm3_gmssl$ ./sm3_hash
Usage: sm3_digest <input_file> <output_file>
djy666@ubuntu:~/djy/sm3_gmssl$ touch hash.bin
djy666@ubuntu:~/djy/sm3_gmssl$ ./sm3_hash plain.txt hash.bin
SM3 digest computed and written to hash.bin

git commit

djy666@ubuntu:~/djy/sm3_gmssl$ git add .
djy666@ubuntu:~/djy/sm3_gmssl$ git commit -m "sm3_hash"
[master df327da] sm3_hash
 4 files changed, 66 insertions(+)
 create mode 100644 sm3_gmssl/hash.bin
 create mode 100644 sm3_gmssl/plain.txt
 create mode 100755 sm3_gmssl/sm3_hash
 create mode 100644 sm3_gmssl/sm3_hash.c

代码

  • sm3_hash.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/sm3.h>

#define SM3_DIGEST_LENGTH 32 

void print_usage() {
    fprintf(stderr, "Usage: sm3_digest <input_file> <output_file>\n");
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        print_usage();
        return EXIT_FAILURE;
    }

    const char *input_file = argv[1];
    const char *output_file = argv[2];

    FILE *fp_input = fopen(input_file, "rb");
    if (!fp_input) {
        perror("Error opening input file");
        return EXIT_FAILURE;
    }

    unsigned char buffer[1024];
    size_t bytes_read;
    SM3_CTX ctx;
    unsigned char digest[SM3_DIGEST_LENGTH];

    sm3_init(&ctx);

    while ((bytes_read = fread(buffer, 1, sizeof(buffer), fp_input)) > 0) {
        sm3_update(&ctx, buffer, bytes_read);
    }

    if (ferror(fp_input)) {
        perror("Error reading input file");
        fclose(fp_input);
        return EXIT_FAILURE;
    }

    sm3_finish(&ctx, digest);
    fclose(fp_input);

    FILE *fp_output = fopen(output_file, "wb");
    if (!fp_output) {
        perror("Error opening output file");
        return EXIT_FAILURE;
    }

    if (fwrite(digest, 1, sizeof(digest), fp_output) != sizeof(digest)) {
        perror("Error writing output file");
        fclose(fp_output);
        return EXIT_FAILURE;
    }

    fclose(fp_output);

    printf("SM3 digest computed and written to %s\n", output_file);
    return EXIT_SUCCESS;
}
HMAC
djy666@ubuntu:~/djy/sm3_gmssl$ vim sm3_hmac.c
djy666@ubuntu:~/djy/sm3_gmssl$ gcc -o sm3_hmac sm3_hmac.c -lgmssl
djy666@ubuntu:~/djy/sm3_gmssl$ ./sm3_hmac
Usage: ./sm3_hmac <key_hex> <input_string>
djy666@ubuntu:~/djy/sm3_gmssl$ ./sm3_hmac "0123456789abcdef0123456789abcdef" "HelloWorld"
HMAC-SM3 result: 8aa2abfb3b902b1693e5af68821cade9ed6f3011d4e52e31f511e9bc57594dd5

git commit

djy666@ubuntu:~/djy/sm3_gmssl$ git add .
djy666@ubuntu:~/djy/sm3_gmssl$ git commit -m "hmac"
[master e9e03aa] hmac
 2 files changed, 38 insertions(+)
 create mode 100755 sm3_gmssl/sm3_hmac
 create mode 100644 sm3_gmssl/sm3_hmac.c

代码

  • sm3_hmac.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HMAC_COMMAND_FORMAT "gmssl sm3hmac -key %s -in_str %s"

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <key_hex> <input_string>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *key_hex = argv[1];
    const char *input_string = argv[2];

    char command[512];
    snprintf(command, sizeof(command), HMAC_COMMAND_FORMAT, key_hex, input_string);

    FILE *fp = popen(command, "r");
    if (fp == NULL) {
        perror("popen failed");
        return EXIT_FAILURE;
    }

    char buffer[128];
    printf("HMAC-SM3 result: ");
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
    }

    if (pclose(fp) == -1) {
        perror("pclose failed");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

SM4

加密
djy666@ubuntu:~/djy/sm4_gmssl$ mv sm4_encrypt.c sm4_keygen.c
djy666@ubuntu:~/djy/sm4_gmssl$ gcc -o sm4_keygen sm4_keygen.c -lgmssl
djy666@ubuntu:~/djy/sm4_gmssl$ ls
sm4_keygen  sm4_keygen.c
djy666@ubuntu:~/djy/sm4_gmssl$ ./sm4_keygen
Usage: ./sm4_keygen <output_filename>
djy666@ubuntu:~/djy/sm4_gmssl$ ./sm4_keygen sm4_key.pem
Key generated and saved to sm4_key.pem
djy666@ubuntu:~/djy/sm4_gmssl$ vim sm4_encrypt.c
djy666@ubuntu:~/djy/sm4_gmssl$ ls
sm4_encrypt.c  sm4_key.pem  sm4_keygen  sm4_keygen.c
djy666@ubuntu:~/djy/sm4_gmssl$ gcc -o sm4_encrypt sm4_encrypt.c -lgmssl
djy666@ubuntu:~/djy/sm4_gmssl$ ls
sm4_encrypt  sm4_encrypt.c  sm4_key.pem  sm4_keygen  sm4_keygen.c
djy666@ubuntu:~/djy/sm4_gmssl$ vim plain.txt
djy666@ubuntu:~/djy/sm4_gmssl$ ls
plain.txt  sm4_encrypt  sm4_encrypt.c  sm4_key.pem  sm4_keygen  sm4_keygen.c
djy666@ubuntu:~/djy/sm4_gmssl$ ./sm4_encrypt
Usage: ./sm4_encrypt <key_file> <input_file> <output_file>
djy666@ubuntu:~/djy/sm4_gmssl$ touch encry_file.bin
djy666@ubuntu:~/djy/sm4_gmssl$ ./sm4_encrypt sm4_key.pem plain.txt encry_file.bin
Encryption completed successfully.

代码

  • sm4_keygen.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmssl/sm4.h>
#include <gmssl/rand.h>

void generate_key(const char *filename) {
    unsigned char key[16];
    FILE *file;

    if (rand_bytes(key, sizeof(key)) != 1) {
        fprintf(stderr, "Error generating random bytes for the key.\n");
        exit(EXIT_FAILURE);
    }

    file = fopen(filename, "wb");
    if (!file) {
        fprintf(stderr, "Error opening file %s for writing.\n", filename);
        exit(EXIT_FAILURE);
    }

    size_t written = fwrite(key, sizeof(unsigned char), sizeof(key), file);
    if (written != sizeof(key)) {
        fprintf(stderr, "Error writing key to file.\n");
        fclose(file);
        exit(EXIT_FAILURE);
    }

    fclose(file);
    printf("Key generated and saved to %s\n", filename);
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <output_filename>\n", argv[0]);
        return EXIT_FAILURE;
    }

    generate_key(argv[1]);
    return EXIT_SUCCESS;
}
  • sm4_encrypt.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "gmssl/sm4.h"

void handleErrors(const char *message);
void sm4_encrypt_file(const char *key_file, const char *input_file, const char *output_file);

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <key_file> <input_file> <output_file>\n", argv[0]);
        return EXIT_FAILURE;
    }

    sm4_encrypt_file(argv[1], argv[2], argv[3]);

    return EXIT_SUCCESS;
}

void sm4_encrypt_file(const char *key_file, const char *input_file, const char *output_file) {
    FILE *kf, *inf, *outf;
    SM4_KEY sm4_key;
    uint8_t key[SM4_KEY_SIZE];
    uint8_t input[SM4_BLOCK_SIZE];
    uint8_t output[SM4_BLOCK_SIZE];
    size_t bytes_read;

    kf = fopen(key_file, "rb");
    if (!kf) {
        handleErrors("Failed to open key file");
    }

    if (fread(key, 1, SM4_KEY_SIZE, kf) != SM4_KEY_SIZE) {
        fclose(kf);
        handleErrors("Failed to read key from file");
    }
    fclose(kf);

    sm4_set_encrypt_key(&sm4_key, key);

    inf = fopen(input_file, "rb");
    if (!inf) {
        handleErrors("Failed to open input file");
    }

    outf = fopen(output_file, "wb");
    if (!outf) {
        fclose(inf);
        handleErrors("Failed to open output file");
    }

    while ((bytes_read = fread(input, 1, SM4_BLOCK_SIZE, inf)) > 0) {
        if (bytes_read < SM4_BLOCK_SIZE) {
            memset(input + bytes_read, 0, SM4_BLOCK_SIZE - bytes_read);
        }
        sm4_encrypt(&sm4_key, input, output);
        fwrite(output, 1, SM4_BLOCK_SIZE, outf);
    }

    fclose(inf);
    fclose(outf);
    printf("Encryption completed successfully.\n");
}

void handleErrors(const char *message) {
    fprintf(stderr, "Error: %s\n", message);
    exit(EXIT_FAILURE);
}
解密
djy666@ubuntu:~/djy/sm4_gmssl$ gcc -o sm4_decrypt sm4_decrypt.c -lgmssl
djy666@ubuntu:~/djy/sm4_gmssl$ ls
encry_file.bin  sm4_decrypt    sm4_encrypt    sm4_key.pem  sm4_keygen.c
plain.txt       sm4_decrypt.c  sm4_encrypt.c  sm4_keygen
djy666@ubuntu:~/djy/sm4_gmssl$ touch decrypt_file.bin
djy666@ubuntu:~/djy/sm4_gmssl$ ./sm4_decrypt
Usage: ./sm4_decrypt <key_file> <input_file> <output_file>
djy666@ubuntu:~/djy/sm4_gmssl$ ./sm4_decrypt sm4_key.pem encry_file.bin decrypt_file.bin
Decryption completed successfully.
djy666@ubuntu:~/djy/sm4_gmssl$ cat decrypt_file.bin
20221413djy

git commit

djy666@ubuntu:~/djy/sm4_gmssl$ git add .
djy666@ubuntu:~/djy/sm4_gmssl$ git commit -m "sm4_encrypt & sm4_decrypt"
[master e4c3218] sm4_encrypt & sm4_decrypt
 10 files changed, 183 insertions(+)
 create mode 100644 sm4_gmssl/decrypt_file.bin
 create mode 100644 sm4_gmssl/encry_file.bin
 create mode 100644 sm4_gmssl/plain.txt
 create mode 100755 sm4_gmssl/sm4_decrypt
 create mode 100644 sm4_gmssl/sm4_decrypt.c
 create mode 100755 sm4_gmssl/sm4_encrypt
 create mode 100644 sm4_gmssl/sm4_encrypt.c
 create mode 100644 sm4_gmssl/sm4_key.pem
 create mode 100755 sm4_gmssl/sm4_keygen
 create mode 100644 sm4_gmssl/sm4_keygen.c

代码

  • sm4_decrypt.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "gmssl/sm4.h"

void handleErrors(const char *message);
void sm4_decrypt_file(const char *key_file, const char *input_file, const char *output_file);

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <key_file> <input_file> <output_file>\n", argv[0]);
        return EXIT_FAILURE;
    }

    sm4_decrypt_file(argv[1], argv[2], argv[3]);
    return EXIT_SUCCESS;
}

void sm4_decrypt_file(const char *key_file, const char *input_file, const char *output_file) {
    FILE *kf, *inf, *outf;
    SM4_KEY sm4_key;
    uint8_t key[SM4_KEY_SIZE];
    uint8_t input[SM4_BLOCK_SIZE];
    uint8_t output[SM4_BLOCK_SIZE];
    size_t bytes_read;

    kf = fopen(key_file, "rb");
    if (!kf) {
        handleErrors("Failed to open key file");
    }

    if (fread(key, 1, SM4_KEY_SIZE, kf) != SM4_KEY_SIZE) {
        fclose(kf);
        handleErrors("Failed to read key from file");
    }
    fclose(kf);

    sm4_set_decrypt_key(&sm4_key, key);

    inf = fopen(input_file, "rb");
    if (!inf) {
        handleErrors("Failed to open input file");
    }

    outf = fopen(output_file, "wb");
    if (!outf) {
        fclose(inf);
        handleErrors("Failed to open output file");
    }

    while ((bytes_read = fread(input, 1, SM4_BLOCK_SIZE, inf)) > 0) {
        sm4_encrypt(&sm4_key, input, output);
        fwrite(output, 1, SM4_BLOCK_SIZE, outf);
    }

    fclose(inf);
    fclose(outf);
    printf("Decryption completed successfully.\n");
}

void handleErrors(const char *message) {
    fprintf(stderr, "Error: %s\n", message);
    exit(EXIT_FAILURE);
}

3. 两人一组,在 Ubuntu或openEuler中(推荐 openEuler)中使用OpenSSL编程实现带签名的数字信封协议。使用OpenSSL库时,Alice发送,Bob接收。Ailice,Bob在实验中要替换为自己的8位学号+姓名。 使用Markdown记录详细记录实践过程,每完成一项git commit 一次。(5分)

  • Alice,Bob生成自己的公私钥匙对,记作:(PKa,SKa),(PKb,SKb),Alice,Bob分别拥有:(PKa,SKa,PKb),(PKb,SKb,PKa),实验中把公钥文件拷贝给对方
  • Alice发给Bob的明文plain.txt,内容为自己的姓名学号
  • Alice:sm4 key使用gmssl rand 产生,16字节,记作k
  • Alice:Sm4Enc(k,P) = C
  • Alice:Sm2Enc(PKb,k) = KC
  • Alice:Sm2Sign(SKa,C)= S1
  • Alice: 数字信封 C||KC||S1 发给Bob
  • Bob:Sm2Very(PKa,S1)
  • Bob:Sm2Dec(SKb,KC)= k
  • Bob:Sm4Dec(k,C)= P

交换密钥

djy666@ubuntu:~/djy/email$ ./sm2_keygen bob_private.pem bob_public.pem
SM2 key pair generated successfully.
djy666@ubuntu:~/djy/email$ cp ./bob_public.pem /mnt/c/1020
djy666@ubuntu:~/djy/email$ ls
bob_private.pem   encrypt_file.bin  sm2_decrypt    sm2_encrypt.c  sm2_private_key.pem  sm2_sign.c
bob_public.pem    plain.txt         sm2_decrypt.c  sm2_keygen     sm2_public_key.pem   sm2_verify
decrypt_file.bin  signature.sig     sm2_encrypt    sm2_keygen.c   sm2_sign             sm2_verify.c
djy666@ubuntu:~/djy/email$ cp /mnt/c/1020/alice_pub.pem ./
djy666@ubuntu:~/djy/email$ ls
alice_pub.pem    decrypt_file.bin  signature.sig  sm2_encrypt    sm2_keygen.c         sm2_sign    sm2_verify.c
bob_private.pem  encrypt_file.bin  sm2_decrypt    sm2_encrypt.c  sm2_private_key.pem  sm2_sign.c
bob_public.pem   plain.txt         sm2_decrypt.c  sm2_keygen     sm2_public_key.pem   sm2_verify
djy666@ubuntu:~/djy/email$ cat alice_pub.pem
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEuY8HKqctI6rfYtqEy/6dhxaHk0GZ
EJJayFj2dNehonL3tkzFi8ADsV4vpwGG+whXz+ZRUfxyetnxQkWtqsrQbA==
-----END PUBLIC KEY-----

git commit

djy666@ubuntu:~/djy/email$ git add .
djy666@ubuntu:~/djy/email$ git commit -m "keyburn & changepublickey"
[master 9e03dcd] keyburn & changepublickey
 20 files changed, 399 insertions(+)
 create mode 100644 email/.swp
 create mode 100755 email/alice_pub.pem
 create mode 100644 email/bob_private.pem
 create mode 100644 email/bob_public.pem
 create mode 100644 email/decrypt_file.bin
 create mode 100644 email/encrypt_file.bin
 create mode 100644 email/plain.txt
 create mode 100644 email/signature.sig
 create mode 100755 email/sm2_decrypt
 create mode 100644 email/sm2_decrypt.c
 create mode 100755 email/sm2_encrypt
 create mode 100644 email/sm2_encrypt.c
 create mode 100755 email/sm2_keygen
 create mode 100644 email/sm2_keygen.c
 create mode 100644 email/sm2_private_key.pem
 create mode 100644 email/sm2_public_key.pem
 create mode 100755 email/sm2_sign
 create mode 100644 email/sm2_sign.c
 create mode 100755 email/sm2_verify
 create mode 100644 email/sm2_verify.c

验签

djy666@ubuntu:~/djy/email$ cp /mnt/c/1020/* ./
djy666@ubuntu:~/djy/email$ ls
alice_pub.pem     encrypt_file.bin       signature.sig               sm2_encrypt    sm2_private_key.pem  sm2_verify
bob_private.pem   encrypted_plain.bin    signed_encrypted_plain.sig  sm2_encrypt.c  sm2_public_key.pem   sm2_verify.c
bob_public.pem    encrypted_sm4_key.bin  sm2_decrypt                 sm2_keygen     sm2_sign
decrypt_file.bin  plain.txt              sm2_decrypt.c               sm2_keygen.c   sm2_sign.c
djy666@ubuntu:~/djy/email$ ./sm2_verify alice_pub.pem signed_encrypted_plain.sig
Usage: ./sm2_verify <public key PEM file> <input file> <signature file>
djy666@ubuntu:~/djy/email$ ./sm2_verify alice_pub.pem encrypted_plain.bin signed_encrypted_plain.sig
Signature is valid.

git commit

djy666@ubuntu:~/djy/email$ git add .
djy666@ubuntu:~/djy/email$ git commit -m "verify"
[master 0ee9d8b] verify
 3 files changed, 2 insertions(+)
 create mode 100755 email/encrypted_plain.bin
 create mode 100755 email/encrypted_sm4_key.bin
 create mode 100755 email/signed_encrypted_plain.sig

解密SM4密钥

djy666@ubuntu:~/djy/email$ touch decrypted_key.bin
djy666@ubuntu:~/djy/email$ ./sm2_decrypt bob_private.pem encrypted_sm4_key.bin decrypted_key.bin
/home/djy/GmSSL/src/sm2_enc.c:517:sm2_decrypt():
SM2 decryption failed
djy666@ubuntu:~/djy/email$ cp /mnt/c/1020/encrypted_sm4_key.bin ./
djy666@ubuntu:~/djy/email$ ls
alice_pub.pem     decrypted_key.bin      plain.txt                   sm2_decrypt.c  sm2_keygen.c         sm2_sign.c
bob_private.pem   encrypt_file.bin       signature.sig               sm2_encrypt    sm2_private_key.pem  sm2_verify
bob_public.pem    encrypted_plain.bin    signed_encrypted_plain.sig  sm2_encrypt.c  sm2_public_key.pem   sm2_verify.c
decrypt_file.bin  encrypted_sm4_key.bin  sm2_decrypt                 sm2_keygen     sm2_sign
djy666@ubuntu:~/djy/email$ ./sm2_decrypt bob_private.pem encrypted_sm4_key.bin decrypted_key.bin
Decryption successful, output written to decrypted_key.bin
djy666@ubuntu:~/djy/email$ hexdump decrypt_key.bin
hexdump: decrypt_key.bin: No such file or directory
hexdump: all input file arguments failed
djy666@ubuntu:~/djy/email$ hexdump decrypted_key.bin
0000000 d68d 774e 764a 008e 1893 a6ca 8fc0 27d8
0000010

解密明文

djy666@ubuntu:~/djy/email$ vim sm4_decrypt.c
djy666@ubuntu:~/djy/email$ gcc -o sm4_decrypt sm4_decrypt.c -lgmssl
djy666@ubuntu:~/djy/email$ ./sm4_decrypt decrypted_key.bin encrypted_plain.bin output.txt
Decryption completed successfully.
djy666@ubuntu:~/djy/email$ cat output.txt
20221413djy&20221422glx

git commit

djy666@ubuntu:~/djy/email$ git add .
djy666@ubuntu:~/djy/email$ git commit -m "sm4_decrypted"
[master 3fd84d2] sm4_decrypted
 3 files changed, 65 insertions(+)
 create mode 100644 email/output.txt
 create mode 100755 email/sm4_decrypt
 create mode 100644 email/sm4_decrypt.c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值