الفريق العربي للهندسة العكسية

نسخة كاملة : C code for oppenssl 3.5.2 x64 signature RSA signature verification
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
C code for oppenssl 3.5.2 x64 signature RSA signature verification, practice material for replacing the public key with a single byte.

Writing code is hard work, so please give it a like.
This can be used by beginners to practice replacing public keys with one byte.
MinGW x64 compilation command:
gcc verify_license.c -o verify_license.exe -ladvapi32.
Signature verification command: 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>
 
// Define OpenSSL initialization flags
#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
 
// Declare OpenSSL opaque struct type
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;
 
// Define password callback type
typedef int (*pem_password_cb)(char* buf, int size, int rwflag, void* u);
 
// Define the minimal function pointer type
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);
 
// Global function pointer
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;
 
// Load OpenSSL functions (minimized version)
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; \
        }
 
    // Core verification function
    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 functions
    LOAD_FUNC(fp_BIO_new_mem_buf, BIO_new_mem_buf);
    LOAD_FUNC(fp_BIO_free, BIO_free);
     
    // Key function
    LOAD_FUNC(fp_PEM_read_bio_PUBKEY, PEM_read_bio_PUBKEY);
    LOAD_FUNC(fp_EVP_PKEY_free, EVP_PKEY_free);
     
    // Hash function
    LOAD_FUNC(fp_EVP_sha256, EVP_sha256);
     
    // OpenSSL 3.0+ Initialization
    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);
 
    // Initialize 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;
    }
     
    // Load the default provider
    default_provider = OSSL_PROVIDER_load(NULL, "default");
    if (!default_provider) {
        printf("Failed to load default provider\n");
        return 0;
    }
 
    return 1;
    #undef LOAD_FUNC
}
 
// Read binary file
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;
}
 
// Correct PEM format
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;
}
 
// Read public key file
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[file_size] = '\0';
    fclose(file);
 
    char* fixed_pem = fix_pem_format(pem_data);
    free(pem_data);
    return fixed_pem;
}
 
// Verify signature (minimum version)
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 return = 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[4096];
    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[0]);
        return 1;
    }
 
    // Attempt to load OpenSSL
    const char* dll_names[] = {
        "libcrypto-3-x64.dll", // Windows default name
        "libcrypto-3.dll", // Possible names for some installations
        NULL
    };
 
    HMODULE hLib = NULL;
    for (int i = 0; dll_names[i]; i++) {
        hLib = LoadLibraryA(dll_names[i]);
        if (hLib) break;
    }
 
    if (!hLib) {
        printf("Failed to load OpenSSL library. Tried:\n");
        for (int i = 0; dll_names[i]; i++) printf(" - %s\n", dll_names[i]);
        print_search_paths();
        return 1;
    }
 
    if (!init_openssl_functions(hLib)) {
        FreeLibrary(hLib);
        return 1;
    }
 
    // Read file
    char* public_key = read_public_key_pem(argv[1]);
    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[2], &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[3], &data, &data_len)) {
        printf("Invalid data file\n");
        free(public_key);
        free(signature);
        FreeLibrary(hLib);
        return 1;
    }
 
    // Verify signature
    if (verify_signature((const char*)data, data_len, signature, sig_len, public_key)) {
        printf("Signature VALID\n");
    } else {
        printf("Signature INVALID\n");
    }
 
    // Clean up
    free(public_key);
    free(signature);
    free(data);
    FreeLibrary(hLib);
    return 0;
}