slzslz 发表于 6 天前

oppenssl 3.5.2 x64签名RSA签名验证的C代码,一字节替换公钥的练习素材

本帖最后由 slzslz 于 2025-8-10 16:23 编辑

敲代码不易,求点赞
可以作为小白练习一字节替换公钥的对象
加密自己软件也可以在这个模版上深化
mingw x64 编译命令
gcc verify_license.c -o verify_license.exe -ladvapi32
签名验证命令   verify_license.exe public_key.pem license_sig.bin data.txt
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

// 定义 OpenSSL 初始化标志
#define OPENSSL_INIT_LOAD_CONFIG         0x00000004L
#define OPENSSL_INIT_ADD_ALL_CIPHERS   0x00000004L
#define OPENSSL_INIT_ADD_ALL_DIGESTS   0x00000008L
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L

// 声明OpenSSL不透明结构体类型
typedef struct evp_md_ctx_st EVP_MD_CTX;
typedef struct bio_st BIO;
typedef struct evp_pkey_st EVP_PKEY;
typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
typedef struct engine_st ENGINE;
typedef struct evp_md_st EVP_MD;
typedef struct ossl_provider_st OSSL_PROVIDER;

// 定义密码回调类型
typedef int (*pem_password_cb)(char* buf, int size, int rwflag, void* u);

// 定义最小化函数指针类型
typedef EVP_MD_CTX* (*fp_EVP_MD_CTX_new)(void);
typedef void (*fp_EVP_MD_CTX_free)(EVP_MD_CTX* ctx);
typedef int (*fp_EVP_DigestVerifyInit)(EVP_MD_CTX* ctx, EVP_PKEY_CTX** pctx, const EVP_MD* type, ENGINE* e, EVP_PKEY* pkey);
typedef int (*fp_EVP_DigestVerifyUpdate)(EVP_MD_CTX* ctx, const void* d, size_t cnt);
typedef int (*fp_EVP_DigestVerifyFinal)(EVP_MD_CTX* ctx, const unsigned char* sig, size_t siglen);
typedef BIO* (*fp_BIO_new_mem_buf)(const void* buf, int len);
typedef int (*fp_BIO_free)(BIO* a);
typedef EVP_PKEY* (*fp_PEM_read_bio_PUBKEY)(BIO* bp, EVP_PKEY** x, pem_password_cb cb, void* u);
typedef void (*fp_EVP_PKEY_free)(EVP_PKEY* pkey);
typedef const EVP_MD* (*fp_EVP_sha256)(void);
typedef int (*fp_OPENSSL_init_crypto)(uint64_t opts, const void* settings);
typedef OSSL_PROVIDER* (*fp_OSSL_PROVIDER_load)(void* ctx, const char* name);
typedef int (*fp_OSSL_PROVIDER_unload)(OSSL_PROVIDER* prov);

// 全局函数指针
static fp_EVP_MD_CTX_new EVP_MD_CTX_new = NULL;
static fp_EVP_MD_CTX_free EVP_MD_CTX_free = NULL;
static fp_EVP_DigestVerifyInit EVP_DigestVerifyInit = NULL;
static fp_EVP_DigestVerifyUpdate EVP_DigestVerifyUpdate = NULL;
static fp_EVP_DigestVerifyFinal EVP_DigestVerifyFinal = NULL;
static fp_BIO_new_mem_buf BIO_new_mem_buf = NULL;
static fp_BIO_free BIO_free = NULL;
static fp_PEM_read_bio_PUBKEY PEM_read_bio_PUBKEY = NULL;
static fp_EVP_PKEY_free EVP_PKEY_free = NULL;
static fp_EVP_sha256 EVP_sha256 = NULL;
static fp_OPENSSL_init_crypto OPENSSL_init_crypto = NULL;
static fp_OSSL_PROVIDER_load OSSL_PROVIDER_load = NULL;
static fp_OSSL_PROVIDER_unload OSSL_PROVIDER_unload = NULL;
static OSSL_PROVIDER* default_provider = NULL;

// 加载OpenSSL函数(最小化版本)
int init_openssl_functions(HMODULE hLib) {
    #define LOAD_FUNC(type, name) \
      name = (type)GetProcAddress(hLib, #name); \
      if (!name) { \
            printf("Failed to load function: %s\n", #name); \
            return 0; \
      }

    // 核心验证函数
    LOAD_FUNC(fp_EVP_MD_CTX_new, EVP_MD_CTX_new);
    LOAD_FUNC(fp_EVP_MD_CTX_free, EVP_MD_CTX_free);
    LOAD_FUNC(fp_EVP_DigestVerifyInit, EVP_DigestVerifyInit);
    LOAD_FUNC(fp_EVP_DigestVerifyUpdate, EVP_DigestVerifyUpdate);
    LOAD_FUNC(fp_EVP_DigestVerifyFinal, EVP_DigestVerifyFinal);
   
    // BIO函数
    LOAD_FUNC(fp_BIO_new_mem_buf, BIO_new_mem_buf);
    LOAD_FUNC(fp_BIO_free, BIO_free);
   
    // 密钥函数
    LOAD_FUNC(fp_PEM_read_bio_PUBKEY, PEM_read_bio_PUBKEY);
    LOAD_FUNC(fp_EVP_PKEY_free, EVP_PKEY_free);
   
    // 哈希函数
    LOAD_FUNC(fp_EVP_sha256, EVP_sha256);
   
    // OpenSSL 3.0+ 初始化
    LOAD_FUNC(fp_OPENSSL_init_crypto, OPENSSL_init_crypto);
    LOAD_FUNC(fp_OSSL_PROVIDER_load, OSSL_PROVIDER_load);
    LOAD_FUNC(fp_OSSL_PROVIDER_unload, OSSL_PROVIDER_unload);

    // 初始化OpenSSL 3.0
    uint64_t init_flags = OPENSSL_INIT_LOAD_CONFIG |
                         OPENSSL_INIT_ADD_ALL_CIPHERS |
                         OPENSSL_INIT_ADD_ALL_DIGESTS |
                         OPENSSL_INIT_LOAD_CRYPTO_STRINGS;
   
    if (OPENSSL_init_crypto(init_flags, NULL) == 0) {
      printf("OPENSSL_init_crypto failed\n");
      return 0;
    }
   
    // 加载默认提供者
    default_provider = OSSL_PROVIDER_load(NULL, "default");
    if (!default_provider) {
      printf("Failed to load default provider\n");
      return 0;
    }

    return 1;
    #undef LOAD_FUNC
}

// 读取二进制文件
int read_binary_file(const char* filename, unsigned char** data, size_t* len) {
    FILE* file = fopen(filename, "rb");
    if (!file) {
      perror("Error opening file");
      return 0;
    }

    fseek(file, 0, SEEK_END);
    *len = ftell(file);
    fseek(file, 0, SEEK_SET);

    *data = (unsigned char*)malloc(*len);
    if (!*data) {
      fclose(file);
      printf("Memory allocation failed\n");
      return 0;
    }

    if (fread(*data, 1, *len, file) != *len) {
      fclose(file);
      free(*data);
      printf("Error reading file\n");
      return 0;
    }

    fclose(file);
    return 1;
}

// 修正PEM格式
char* fix_pem_format(const char* pem_data) {
    const char* header = "-----BEGIN";
    const char* footer = "-----END";
   
    const char* begin = strstr(pem_data, header);
    if (!begin) return NULL;
   
    const char* end = strstr(pem_data, footer);
    if (!end) return NULL;
   
    end += strlen(footer);
    while (*end && *end != '\n' && *end != '\r') end++;
   
    size_t length = end - begin;
    char* fixed = (char*)malloc(length + 2);
    if (!fixed) return NULL;
   
    const char* src = begin;
    char* dst = fixed;
   
    while (src < end) {
      if (*src == '\r') { src++; continue; }
      *dst++ = *src++;
    }
   
    if (*(dst-1) != '\n') *dst++ = '\n';
    *dst = '\0';
   
    return fixed;
}

// 读取公钥文件
char* read_public_key_pem(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
      perror("Error opening public key file");
      return NULL;
    }

    fseek(file, 0, SEEK_END);
    long file_size = ftell(file);
    fseek(file, 0, SEEK_SET);

    char* pem_data = (char*)malloc(file_size + 1);
    if (!pem_data) {
      fclose(file);
      return NULL;
    }

    fread(pem_data, 1, file_size, file);
    pem_data = '\0';
    fclose(file);

    char* fixed_pem = fix_pem_format(pem_data);
    free(pem_data);
    return fixed_pem;
}

// 验证签名(最小化版本)
int verify_signature(const char* plaintext, size_t text_len,
                  const unsigned char* signature, size_t sig_len,
                  const char* public_key_pem) {
    EVP_MD_CTX* ctx = NULL;
    BIO* bio = NULL;
    EVP_PKEY* pkey = NULL;
    int ret = 0;

    if (!(bio = BIO_new_mem_buf(public_key_pem, -1))) {
      printf("Error creating BIO\n");
      goto cleanup;
    }

    if (!(pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL))) {
      printf("Error loading public key\n");
      goto cleanup;
    }

    if (!(ctx = EVP_MD_CTX_new())) {
      printf("Error creating EVP_MD_CTX\n");
      goto cleanup;
    }

    if (EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, pkey) <= 0) {
      printf("Error initializing verification\n");
      goto cleanup;
    }

    if (EVP_DigestVerifyUpdate(ctx, plaintext, text_len) <= 0) {
      printf("Error updating verification data\n");
      goto cleanup;
    }

    ret = (EVP_DigestVerifyFinal(ctx, signature, sig_len) == 1);

cleanup:
    if (ctx) EVP_MD_CTX_free(ctx);
    if (pkey) EVP_PKEY_free(pkey);
    if (bio) BIO_free(bio);
    return ret;
}

void print_search_paths() {
    char path;
    if (GetEnvironmentVariableA("PATH", path, sizeof(path))) {
      printf("Current PATH: %s\n", path);
    }
}

int main(int argc, char** argv) {
    if (argc != 4) {
      printf("Usage: %s <public_key.pem> <signature.bin> <data.txt>\n", argv);
      return 1;
    }

    // 尝试加载OpenSSL
    const char* dll_names[] = {
      "libcrypto-3-x64.dll",// Windows默认名称
      "libcrypto-3.dll",      // 某些安装可能的名称
      NULL
    };

    HMODULE hLib = NULL;
    for (int i = 0; dll_names; i++) {
      hLib = LoadLibraryA(dll_names);
      if (hLib) break;
    }

    if (!hLib) {
      printf("Failed to load OpenSSL library. Tried:\n");
      for (int i = 0; dll_names; i++) printf(" - %s\n", dll_names);
      print_search_paths();
      return 1;
    }

    if (!init_openssl_functions(hLib)) {
      FreeLibrary(hLib);
      return 1;
    }

    // 读取文件
    char* public_key = read_public_key_pem(argv);
    if (!public_key) {
      printf("Invalid public key file\n");
      FreeLibrary(hLib);
      return 1;
    }

    unsigned char* signature = NULL;
    size_t sig_len = 0;
    if (!read_binary_file(argv, &signature, &sig_len)) {
      printf("Invalid signature file\n");
      free(public_key);
      FreeLibrary(hLib);
      return 1;
    }

    unsigned char* data = NULL;
    size_t data_len = 0;
    if (!read_binary_file(argv, &data, &data_len)) {
      printf("Invalid data file\n");
      free(public_key);
      free(signature);
      FreeLibrary(hLib);
      return 1;
    }

    // 验证签名
    if (verify_signature((const char*)data, data_len, signature, sig_len, public_key)) {
      printf("Signature VALID\n");
    } else {
      printf("Signature INVALID\n");
    }

    // 清理
    free(public_key);
    free(signature);
    free(data);
    FreeLibrary(hLib);
    return 0;
}

52soft 发表于 昨天 21:40

谢谢分享

chchhau 发表于 5 天前

PYG20周年生日快乐!

wgz001 发表于 5 天前

表哥开始教学了,赞

linxiansen 发表于 6 天前

PYG有你更精彩!

toneger 发表于 6 天前

膜拜大神~!
PYG有你更精彩!

大椿 发表于 6 天前

请问:是什么用途????????、

linxiansen 发表于 6 天前

PYG有你更精彩!
页: [1]
查看完整版本: oppenssl 3.5.2 x64签名RSA签名验证的C代码,一字节替换公钥的练习素材