Fork me on GitHub

openssl的安装与简单使用

openssl是一个功能丰富且自包含的开源安全工具箱。它提供的主要功能有:SSL协议实现 (包括SSLv2、SSLv3和TLSv1)、大量软算法(对称/非对称/摘要)、大数运算、非对称算法密钥生成、ASN.1编解码库、证书请求 (PKCS10)编解码、数字证书编解码、CRL编解码、OCSP协议、数字证书验证、PKCS7标准实现和PKCS12个人数字证书格式实现等功能。上述知识各位可以去官网看看,或参考网上资料。

本文只针对本人实践过的openssl的安装过程以及关于RSA、AES的两种加解密算法的简单使用实例

一、Linux下安装过程(本人是Centos 64bit系统)

1、 官方下载相应的源码,相应的安装教程,网上应该能找到很多的,这里就不在累赘了。

需要提醒的是,安装完openssl后,发现程序编译提示-lcrypto 无法链接,表示缺少crypto库,此时参照该篇帖子[http://blog.chinaunix.net/uid-14704264-id-4204452.html](http://blog.chinaunix.net/uid-14704264-id-4204452.html) 完成即可。本人选择直接yum安装openssl-devel

即 yum install openssl-devel

二、Windows7 64bit 操作系统下编译openssl过程

(仅讲述本人机器环境下,编译成功的一些步骤,若有偏差,请动脑筋自己找解决方案)

在windows下,我们可以选择要编译openssl为32bit还是64bit,以便后期VS2010开发时候,既可以WIN32程序使用,也可以X64程序使用。安装openssl之前,我们需要先下载安装Windows版本的Perl,因为后期需要使用它来进行编译链接。 **(PS:如果你想看看原始的INSTALL文件,那么请打开OpenSSL的解压缩目录,下面有两个文件INSTALL.W32和INSTALL.W64,用记事本方式打开,你可以看到详细的关于安装的解释,这也是最正规的学习方式咯哦,下面只是我们实践之后,帮您快速安装的指南而已)**

1、好了,现在开始先讲解下win64位下的openssl编译安装步骤

1.1 安装好perl后,进入perl目录下的eg文件夹下,执行example.pl,安装成功会显示出来相应的信息

1.2 打开vs2010的工具中命令提示行,运行C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\bin\\amd64下的vcvars64.bat, ‍此步骤主要是完成vs的64bit的环境变量配置

1.3 进入openssl的目录下,依次执行如下命令即可

 \> perl Configure VC-WIN64A  
     \> ms\\do_win64a  
     \> nmake -f ms\\ntdll.mak        ()

     \> nmake -f ms\\ntdll.mak test   检查上一步编译是否成功  
     \> nmake -f ms\\ntdll.mak install  安装编译后的openssl到指定目录

说明:编译分两种情况,生成静态库和动态库  

  (1) 如果是编译OpenSSL动态库,则在命令行键入 nmake -f ms\ntdll.mak
    编译成功课在文件夹out32dll里面查看输出的文件,包括应用程序的exe文件、lib文件、dll文件。
  (2) 如果是编译OpenSSL静态库,则在命令行键入 nmake -f ms\nt.mak
    编译成功课在文件夹out32里面查看输出的文件,包括应用程序的exe文件、lib文件。

2、下面介绍32bit下的openssl安装配置

2.1 首先设定好环境变量

    设定环境变量:桌面计算机图标右键->属性->高级系统设置->环境变量->在系统变量当中找到变量名称为path的变量 (如果没有找到这新建)点击编辑->在变量名称中填入"C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\bin;C:\\Perl64\\bin;c:\\windows\\system32"->点击确定完成设定。(说明:C: \\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\bin路径是VS2010的路径。C:\\Perl64\\bin是运行perl的路径,不若不设定那么perl命令将找不到。c: \\windows\\system32这个路径很少提到但是很重要,如果不设置那么会造成后面vcvars32.bat环境变量执行出错。)到此环境变量路 径设置好之后重启下电脑才能生效。



2.2 使用Visual Studio命令提示(2010)进入控制台模式:开始菜单->所有程序->Microsoft Visual Studio 2010->Visual Studio Tools->Visual Studio命令提示(2010),(PS:以管理员身份运行), 使用cd命令将目录指向C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\bin(PS:自己的VC安装路径), 命令行键入vcvars32,运行vcvars32.bat..完成后进入OpenSSL源码的 目录(C:\\openssl)



2.3 执行Configure命令(配置编译参数)(需将目录跳到OpenSSL源码目录下)

        在命令行中键入"perl configure VC-WIN32 no-asm --prefix=c:\\openssl"  

        (PS:--prefix=c:\\openssl命令为指定安装位置)



2.4 运行ms\\do_ms命令(需将目录跳到OpenSSL源码目录下)

        在命令行中键入”ms\\do_nasm“。



2.5 运行“nmake -f ms\\ntdll.mak -a”命令进行代码编译(需将目录跳到OpenSSL源码目录下)



2.6 测试使用命令“nmake -f ms\\ntdll.mak test”(若安装成功则可以使用此命令来验证)

三、RSA与AES的简单代码示例

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//AES加密,不足128位的需要在前面补0,再加上128bit来表示补零的长度
std::string EncodeAES( const std::string& password, const std::string& data )
{
    unsigned char Iv[17]="12345678abcdefgh";
    AES_KEY aes_key;
    if(AES_set_encrypt_key( (const unsigned char*)password.c_str(), password.length() * 8,
        &aes_key) < 0)
    {
        assert(false);
        return "";
    }
    std::string strRet;
    std::string data_bak(data);

    unsigned int data_length = data_bak.length();
    int padding = 0;
    if (data_bak.length() % AES_BLOCK_SIZE > 0)
    {
        padding =  AES_BLOCK_SIZE - data_bak.length() % AES_BLOCK_SIZE;
    }
    data_length += padding;

    //此函数在p0处插入n个字符c(前补零)
    data_bak.insert(0, padding, '\0');

    //用128位告知补了多少个0
    char* padding_zero_length = new char[AES_BLOCK_SIZE];
    memset(padding_zero_length, 0, AES_BLOCK_SIZE-1);
    padding_zero_length[AES_BLOCK_SIZE-1] = padding * 8 ;

    std::string num_head(padding_zero_length, AES_BLOCK_SIZE);
    delete[] padding_zero_length;
    data_bak.insert(0,num_head);
    data_length +=AES_BLOCK_SIZE;

    //加密的明文一定要是AES_BLOCK_SIZE的整数倍
    for(unsigned int i = 0; i < data_length/AES_BLOCK_SIZE; i++)
    {
        std::string str16 = data_bak.substr(i*AES_BLOCK_SIZE, AES_BLOCK_SIZE);
        unsigned char out[AES_BLOCK_SIZE];
        memset(out, 0, AES_BLOCK_SIZE);
        AES_cbc_encrypt((const unsigned char*)str16.c_str(),out,AES_BLOCK_SIZE,
            &aes_key,Iv,AES_ENCRYPT);

        strRet += std::string((const char*)out, AES_BLOCK_SIZE);
    }
    return strRet;
}

//AES解密
std::string DecodeAES( const std::string& strPassword, const std::string& strData )
{
    //双方指定就好
    unsigned char Iv[17]="12345678abcdefgh";
    AES_KEY aes_key;
    if(AES_set_decrypt_key( (const unsigned char*)strPassword.c_str(), 
                          strPassword.length() * 8, &aes_key )  < 0 )
    {
        assert(false);
        return "";
    }
    std::string strRet;
    for(unsigned int i = 0; i < strData.length()/AES_BLOCK_SIZE; i++)
    {
        std::string str16 = strData.substr(i*AES_BLOCK_SIZE, AES_BLOCK_SIZE);
        unsigned char out[AES_BLOCK_SIZE];
        memset(out, 0, AES_BLOCK_SIZE);
        AES_cbc_encrypt((const unsigned char*)str16.c_str(),out,AES_BLOCK_SIZE,
          &aes_key,Iv,AES_DECRYPT);

        strRet += std::string((const char*)out, AES_BLOCK_SIZE);
    }

    // 解密后跳过补零的长度
    unsigned char num_head = strRet[AES_BLOCK_SIZE-1];
    int len=num_head/8;

    strRet = strRet.substr(AES_BLOCK_SIZE+len);
    return strRet;
}

//RSA加密,加解密使用的都是公钥
std::string EncodeRSAKeyFile( const std::string& strRsaPubkey, const std::string& strData )
{
    if (strRsaPubkey.empty() || strData.empty())
    {
        assert(false);
        return "";
    }

    std::string strRet;
    RSA* pRSAPublicKey = NULL;
    BIO    *bio = NULL;

    /* 从内存数据读 */
    bio = BIO_new(BIO_s_mem());
    BIO_puts(bio, strRsaPubkey.c_str());

    pRSAPublicKey = PEM_read_bio_RSA_PUBKEY(bio, &pRSAPublicKey, NULL, NULL);
    if (pRSAPublicKey == NULL) 
    {
        return NULL;
    }


    int nLen = RSA_size(pRSAPublicKey);
    int iblock_size = nLen - 11;
    int oblock_size = nLen ;
    int nblocks = (strData.length() / iblock_size) + 
         ((strData.length() % iblock_size == 0) ? 0 : 1);  

    char* pEncode = new char[nblocks*nLen + 1];
    for (int i = 0; i < nblocks ; ++i)
    {
        int ret=0;
        if (i == nblocks - 1) 
        { 
          ret = RSA_public_encrypt(strData.length() % iblock_size,
                 (const unsigned char*)(strData.c_str()+(i * iblock_size)),
                 (unsigned char*)(&pEncode[i*oblock_size]),
                  pRSAPublicKey, 
                  RSA_PKCS1_PADDING); 
        } 
        else 
        {
          ret = RSA_public_encrypt(iblock_size,
                  (const unsigned char*)(strData.c_str()+(i * iblock_size)), 
                  (unsigned char*)(&pEncode[i*oblock_size]), 
                  pRSAPublicKey, 
                  RSA_PKCS1_PADDING); 
        } 
        strRet = strRet + std::string(&pEncode[i*oblock_size], ret);
    }
    delete[] pEncode;
    BIO_free(bio);
    RSA_free(pRSAPublicKey);
    CRYPTO_cleanup_all_ex_data(); 
    return strRet;
}

//RSA解密,加解密使用的都是公钥
std::string DecodeRSAKeyFile( const std::string& strRsaPubkey, const std::string& strData )
{
    if (strRsaPubkey.empty() || strData.empty())
    {
        assert(false);
        return "";
    }
    std::string strRet;
    RSA* pRSAPublicKey = NULL;
    BIO    *bio = NULL;

    /* 从内存数据读秘钥 */
    bio = BIO_new(BIO_s_mem());
    BIO_puts(bio, strRsaPubkey.c_str());

    pRSAPublicKey = PEM_read_bio_RSA_PUBKEY(bio, &pRSAPublicKey, NULL, NULL);
    if (pRSAPublicKey == NULL) 
    {
        return NULL;
    }

    int nLen = RSA_size(pRSAPublicKey);
    int block_size = nLen; 
    int nblocks =  strData.length() / block_size; 
    char* pDecode = new char[nLen+1];
    for (int i= 0; i < nblocks; i++) 
    { 
        //加解密使用的都是公钥
        int ret = RSA_public_decrypt(block_size, 
                        (const unsigned char*)(strData.c_str()+(i * block_size)),
                         (unsigned char*)pDecode, 
                         pRSAPublicKey, 
                         RSA_PKCS1_PADDING); 
        if(ret >= 0)
        {
            strRet = strRet + std::string((char*)pDecode, ret);
        }
    } 
    delete [] pDecode;
    BIO_free(bio);
    RSA_free(pRSAPublicKey);
    CRYPTO_cleanup_all_ex_data(); 
    return strRet;
}

其中例子中rsa加解密都是用公钥来加解密的哦,至于如何按私钥来,自主思考或查阅资料吧

linux编译选项需要加上: -lcrypto -lssl

windows下需要在VS2010中配置相应的项目属性,即

项目->属性->配置属性->vc++目录->包含目录

项目->属性->配置属性->vc++目录->库目录

感谢您的赞赏,赚点辛苦奶粉钱