目录

静态链接OpenSSL进行RSA\MD5\Base64

简介

目标平台: Windows 10 amd64

使用静态链接方式,原因:动态链接库太大了,包含很多本次实验不需要的函数

准备工作

下载OpenSSL代码

git clone https://github.com/OpenSSL/OpenSSL.git

或者从官网 https://www.OpenSSL.org/source/ 下载源代码

我使用的是OpenSSL 1.1.1

安装perl环境,这里使用的是ActivePerl

https://www.activestate.com/products/perl/

安装NASM汇编器

https://www.nasm.us/

配置环境变量

将刚刚安装的nasm和perl的bin目录加入PATH

/posts/coding/openssl-first-try-rsa-md5-base64/env_hu1b339cdcef088ba71c0e08c5bd4346ed_9406_526x161_resize_q75_h2_box_3.webp

编译 OpenSSL 静态链接库

初始化环境

使用visual studio自带的命令提示工具初始化环境,因为需要使用nmake

/posts/coding/openssl-first-try-rsa-md5-base64/vs1_hu69c0279074ebca3855950d2a6e40bda3_363283_306x296_resize_q75_h2_box_3.webp

/posts/coding/openssl-first-try-rsa-md5-base64/vs2_huec5bcc4756c6ba8aa94a769c68107934_8156_560x171_resize_q75_h2_box_3.webp

生成编译配置文件

cd进入OpenSSL源码目录

执行 perl Configure VC-WIN64A no-asm no-shared --prefix="D:\Project\OpenSSLwork\OpenSSL\build" --OpenSSLdir="D:\Project\OpenSSLwork\OpenSSL\build\ssl"

进行编译并测试和安装

1
2
3
nmake
nmake test
nmake install

此时已经有了我们需要的头文件和静态链接lib库

/posts/coding/openssl-first-try-rsa-md5-base64/build1_hu019cf07ffb320f505a901e8f9e7586b0_14981_651x189_resize_q75_h2_box_3.webp

/posts/coding/openssl-first-try-rsa-md5-base64/build2_hudeaca1bd4f1a08f445bfebd53c3ef518_57314_155x92_resize_q75_h2_box_3.webp

使用OpenSSL的api进行编程

visual studio项目配置

vs创建空项目,然后配置头文件和库文件的路径

项目右键-属性,配置选择所有配置,平台选择x64

VC++ 目录 配置里面的 包含目录 添加OpenSSL的头文件目录, 我这里是 D:\Project\OpenSSLwork\OpenSSL\build\include;

/posts/coding/openssl-first-try-rsa-md5-base64/vsw1_hu175bf96b41aac86de79120bd8ed4b83a_26183_783x241_resize_q75_h2_box_3.webp

链接器 里面的 输入附加依赖项 添加 静态库名,libcrypto.lib;libssl.lib;

注意:在使用OpenSSL的静态链接库时,除了添加 libcrypto.lib;libssl.lib;,还需要添加系统的依赖库:crypt32.lib;WS2_32.lib;, 因为OpenSSL在windows平台使用了这些库。 完整的: kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);crypt32.lib;libcrypto.lib;libssl.lib;WS2_32.lib;

添加头文件

因为需要md5,rsa,Base64等操作,这里需要导入OpenSSL四个相关的头文件

1
2
3
4
#include <OpenSSL/rsa.h>
#include <OpenSSL/pem.h>
#include <OpenSSL/md5.h>
#include <OpenSSL/bio.h>

使用MD5对字符串生成摘要

1
2
3
4
5
6
7
8
int md5_hash(const char *in, unsigned char *md)
{
    unsigned char* data;
    const unsigned char* str;
    data = (unsigned char*)in;
    MD5(data, strlen(in), md); //调用OpenSSL的md5方法
    return 1;
}

生成rsa密钥对并以pem格式写入文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
RSA * gen_rsa()
{
    int bits = 1024;
    RSA* rsa = RSA_new();
    BIGNUM* e = BN_new();
    BN_set_word(e, RSA_F4);
    int rc = RSA_generate_key_ex(rsa, bits, e, NULL); //OpenSSL中生成rsa key的新方法
    BN_free(e);
    if (rc != 1) return NULL;   
    size_t pri_len;
    size_t pub_len;
    char* pri_key = NULL;
    char* pub_key = NULL;
    BIO* pubkey = BIO_new_file("public.pem", "w");
    BIO* prikey = BIO_new_file("private.pem", "w");
    PEM_write_bio_RSAPrivateKey(prikey, rsa, NULL, NULL, 0, NULL, NULL); //私钥写入文件
    PEM_write_bio_RSAPublicKey(pubkey, rsa); //公钥写入文件
    return rsa;
}

对数据进行Base64编码,Base64在BIO中有

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
int Base64_encode(const unsigned char* buffer, size_t length, char** b64text) {
    BIO* bio, * b64;
    BUF_MEM* bufferPtr;
    b64 = BIO_new(BIO_f_Base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
    BIO_set_flags(bio, BIO_FLAGS_Base64_NO_NL);
    BIO_write(bio, buffer, length);
    BIO_flush(bio);
    BIO_get_mem_ptr(bio, &bufferPtr);
    BIO_set_close(bio, BIO_NOCLOSE);
    *b64text = (char*)malloc((bufferPtr->length + 1) * sizeof(char));
    memcpy(*b64text, bufferPtr->data, bufferPtr->length);
    (*b64text)[bufferPtr->length] = '\0';
    BIO_free_all(bio);
    return 0;
}

最后通过main函数读入字符串并将三个过程连起来

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        printf("usage: work.exe \"string to hash and sign\"");
        return 0;
    }
    char* str = argv[1];
    printf("your str: %s\n", str);

    // first md5(str)
    unsigned char md[MD5_DIGEST_LENGTH];
    md5_hash(str, md);

    // then gen rsa pkey and sign the md
    RSA* rsa = gen_rsa();
    unsigned char* sig = new unsigned char;
    unsigned int siglen;
    RSA_sign(NID_sha1, md, MD5_DIGEST_LENGTH, sig, &siglen, rsa);

    // final Base64(sig)
    char* b64text;
    Base64_encode(sig, (size_t)siglen, &b64text);
    printf("%s\n", b64text);
    return 0;
}

因为是课程作业,就没有对出现的错误情况进行处理,实际使用时需要考虑到

运行

运行截图

/posts/coding/openssl-first-try-rsa-md5-base64/run1_hu1ebefd56625b0904e9af14ded86be8e5_16611_1110x118_resize_q75_h2_box_3.webp

生成的私钥文件

/posts/coding/openssl-first-try-rsa-md5-base64/key1_hufd17b09baea8e971a6b50544cb114dcc_29346_620x273_resize_q75_h2_box_3.webp

生成的公钥文件

/posts/coding/openssl-first-try-rsa-md5-base64/key2_hu77fcc465899aaf9c3e0be57f84e56c55_11897_643x163_resize_q75_h2_box_3.webp