Visual Studio 2015 中使用 OpenSSL

该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/post/2015/12/02/using-openssl-with-vs2015/

Overview

在 Visual Studio 2015 中使用 OpenSSL 的记录。

1. 编译

编译 OpenSSL 没什么难度,直接命令行就可以搞定。不过要注意一点细节。

  1. 官网下载 OpenSSL-1.0.0s.tar.gz

  2. 安装 Perl For Windows,用于生产 mak 脚本,安装一个 ActivePerl 即可。

  3. 在开始菜单打开 VS2015 x86 本机工具命令提示符。(64位的也差不多,参考 INSTALL.w64)

  4. 先把 PERL 安装目录写入 PATH。

    1SET PATH=%PATH%;PERL安装目录\site\bin;PERL安装目录\bin
    
  5. 执行configure,注意 –prefix 是输出目录。

    1perl Configure VC-WIN32 no-asm --prefix=x:/openssl
    
  6. 接下来先不要急着编译,最重要的是先修改生成的 .mak 文件。因为 .mak 脚本强制把 C 编译警告当成错误处理,这会导致编译失败。

    方法是打开 ms/ntdll.mak,修改第 20 行,把 /WX 去掉。

    如果你要编译静态库,那么则应该修改 ms/nt.mak,修改方法一样。

    注意,如果要编译 DEBUG 版本,那么在 ms/ntdll.mak (或 ms/nt.mak)的第 20 行处,给 /MD(或/MT)后面加一个d,变成 /MDd(或 /MTd),即可。

  7. 打开 e_os.h,跳到 319 行,把这一行

    1#    if _MSC_VER>=1300
    

    替换成如下内容并保存。否则会导致链接错误,因为 VC2015 中标准IO流的定义被修改了。

    1#    if _MSC_VER>=1400
    2_ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);
    3#        define stdin  (__acrt_iob_func(0))
    4#        define stdout (__acrt_iob_func(1))
    5#        define stderr (__acrt_iob_func(2))
    6#    elif _MSC_VER>=1300
    
  8. 现在,开始编译。

    编译静态链接库

    1nmake -f ms\nt.mak
    2nmake -f ms\nt.mak install
    3nmake -f ms\nt.mak clean
    

    编译动态链接库

    1nmake -f ms\ntdll.mak
    2nmake -f ms\ntdll.mak install
    3nmake -f ms\ntdll.mak clean
    
  9. 测试代码,如果遇到报错

    1OPENSSL_Uplink(006E9000,08): no OPENSSL_Applink
    

    则包含文件

    1#include <openssl/applink.c>
    

2. 测试

  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <string.h>
  4#include <openssl/rsa.h>
  5#include <openssl/pem.h>
  6#include <openssl/err.h>
  7#include <openssl/applink.c>
  8#include <openssl/md5.h>
  9#include <openssl/sha.h>
 10
 11#define OPENSSLKEY	"test.key"
 12#define PUBLICKEY	"test_pub.key"
 13
 14typedef unsigned char			byte_t;
 15
 16byte_t *rsaEncrypt(byte_t *inputData, size_t *inputLength, byte_t *pBuffer, size_t bufLength, char *priKeyPath) {
 17
 18    RSA *pRSA;
 19    FILE *hFile;
 20    size_t lenRSA;
 21
 22    if ((hFile = fopen(priKeyPath, "r")) == NULL)
 23        return NULL;
 24
 25    if ((pRSA = PEM_read_RSA_PUBKEY(hFile, NULL, NULL, NULL)) == NULL)
 26        return NULL;
 27
 28    lenRSA = RSA_size(pRSA);
 29
 30    if (*inputLength > lenRSA - RSA_PKCS1_PADDING_SIZE || bufLength < lenRSA)
 31        return NULL;
 32
 33    memset(pBuffer, 0, lenRSA);
 34
 35    if ((lenRSA = RSA_public_encrypt(*inputLength, inputData, pBuffer, pRSA, RSA_PKCS1_PADDING)) == -1) {
 36        return NULL;
 37    }
 38
 39    *inputLength = lenRSA;
 40
 41    RSA_free(pRSA);
 42    fclose(hFile);
 43    return pBuffer;
 44}
 45
 46byte_t *rsaDecrypt(byte_t *inputData, size_t inputLength, byte_t *pBuffer, size_t bufLength, char *path_key) {
 47
 48    RSA *pRSA;
 49    FILE *hFile;
 50    int lenRSA;
 51
 52    if ((hFile = fopen(path_key, "r")) == NULL)
 53        return NULL;
 54
 55    if ((pRSA = PEM_read_RSAPrivateKey(hFile, NULL, NULL, NULL)) == NULL)
 56        return NULL;
 57
 58    lenRSA = RSA_size(pRSA);
 59
 60    if (inputLength != lenRSA)
 61        return NULL;
 62
 63    memset(pBuffer, 0, lenRSA);
 64
 65    if (RSA_private_decrypt(lenRSA, inputData, pBuffer, pRSA, RSA_PKCS1_PADDING) < 0)
 66        return NULL;
 67
 68    RSA_free(pRSA);
 69    fclose(hFile);
 70    return pBuffer;
 71}
 72
 73int main(int argc, char** argv) {
 74    char *pData = "Hello RSA, This is a test.";
 75    MD5_CTX md5Data;
 76    SHA_CTX sha1Data;
 77    byte_t encBuf[512], decBuf[512];
 78    size_t lenInput;
 79    int i;
 80    printf("Input Data:%s\n", pData);
 81
 82    /* RSA */
 83
 84    lenInput = strlen(pData);
 85
 86    rsaEncrypt((byte_t*)pData, &lenInput, encBuf, sizeof(encBuf), PUBLICKEY);
 87    printf("after encrypt[%lu]:%s\n", lenInput, encBuf);
 88
 89    rsaDecrypt(encBuf, lenInput, decBuf, sizeof(decBuf), OPENSSLKEY);
 90    printf("after decrypt:%s\n", decBuf);
 91
 92    /* MD5 */
 93
 94    lenInput = strlen(pData);
 95
 96    MD5_Init(&md5Data);
 97
 98    MD5_Update(&md5Data, pData, lenInput);
 99    MD5_Final(encBuf, &md5Data);
100
101    printf("MD5: ");
102    for (i = 0; i < 16; i++)
103        printf("%02x", encBuf[i]);
104    putchar('\n');
105
106    /* SHA-1 */
107
108    lenInput = strlen(pData);
109
110    SHA1_Init(&sha1Data);
111
112    SHA1_Update(&sha1Data, pData, lenInput);
113    SHA1_Final(encBuf, &sha1Data);
114
115    printf("SHA-1: ");
116    for (i = 0; i < 20; i++)
117        printf("%02x", encBuf[i]);
118    putchar('\n');
119
120    return 0;
121}

3. 参考文献

comments powered by Disqus