一、需要的软件和环境
1) OpenSSL(自行到官网下载最新版本openssl-1.0.2d.tar.gz!)
2) Perl(ActivePerl-5.12.2)
3) Microsoft Visual Studio 2010(及以上版本)
二、安装步骤
1、正确安装和设置ActivePerl,Visual Studio 2010
常规方式安装好ActivePerl-5.12.2和Visual Studio 2010。
检验Perl是否安装成功的方法:
在windows命令行下运行如下命令:
1) cd C:\Perl\eg (假定Perl的安装目录是C:\Perl);
2) 在该目录下执行:perl example.pl;
3) 若结果显示“Hello from ActivePerl!”,则说明Perl安装成功,可以开始使用Perl的相关命令来进行OpenSSL的安装了。
为Visual Studio 2010(VisualC++)设置临时环境变量
在命令行切换到VisualStudio 2010的安装目录下的VC子目录
1) cd C:\Program Files\MicrosoftVisual Studio\VC (假定VisualStudio的安装目录为C:\ProgramFiles\Microsoft Visual Studio\);
2) 在命令行运行vcvarsall.BAT
注意:用这个命令来设置环境变量,其环境变量仅对当前的命令行窗口有效。
3)保留如图1窗口,切记不要关闭。
4)下载nasm-2.11.08-win32,解包后将两个可执行文件拷贝到VC的安装目录的子目录bin下。
2、正式开始安装OpenSSL
注意:因为为Visual Studio2010(Visual C++)设置的是临时环境变量,所以以下步骤所要执行的命令行命令必须是在步骤1的如图1的同一个命令行窗口下面执行。
(1)先将openssl软件包解压,并在命令行窗口中,切换到openssl解压后所在的主目录。
(2)执行Configure命令(该步骤的目的是配置编译参数,对编译环境进行基本的配置):
perl Configure VC-WIN32(注意该命令是大小写敏感的)
(3)执行如下命令(ms目录下的批处理命令do_ nasm生成makefile配置文件“ntdll.mak”):
ms\do_nasm
(4)执行如下命令(根据步骤(1)和(2)所生成的makefile文件“ntdll.mak”编译所有源代码):nmake -f ms\ntdll.mak
其中可能出现各种错误,可以在百度或者www.aol.com上输入返回错误信息,以寻找到相应的处理措施。
(5) 对所有密码算法、SSL协议和相关功能进行测试:
nmake -f ms\ntdll.mak test
如果出现以上提示("passedall tests")则说明成功。如果编译成功,最后的输出结果都在out32dll目录下:包括可执行文件、两个dll和两个lib文件: libeay32.dll,libeay32.lib,ssleay32.dll,ssleay32.lib,openssl.exe;
(6)将编译后的OpenSSL安装到缺省目录(如果上述的操作是在D:盘完成,则OpenSSL缺省按照到这个目录:D:\usr\local\ssl)nmake -f ms\ntdll.mak install
把安装目录下的bin子目录和lib子目录的目录路径(例如D:\usr\local\ssl\bin和D:\usr\local\ssl\lib)添加到PATH环境变量中。
三、代码调试环境配置
VS-打开项目-项目-属性-VC++目录
更改包含目录以及库目录路径
注意包含目录只需要到include文件夹下即可,因为代码中openssl/evp.h已经包含了openssl文件夹。
然后在-连接器-输入中,将
文件夹下的两个库文件添加到附加依赖项
调试成功:
附调试代码:
/* -------------------------------------------------------------------------
* Copyright (c) 2007 JianShen.
* All rights reserved.
* This source code and any compilation or derivative thereof is the
* proprietary information of Author(s). and is confidential in nature.
*
* Under no circumstances is this software to be combined with any Open
* Source Software in any way or placed under an Open Source License of
* any type without the express written permission of Author(s).
* ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
* Description:
* 一个测试例子用于对消息进使用指定的算法进行加解密以及BASE64编码。
* Author: Jian Shen
* Created:2007/05/19
* Change History:
* ------------------------------------------------------------------------- */
#include
#include
#include
//base64中每行的长度,最后一位是换行符号
#define CHARS_PER_LINE_BASE64 65 //64+1(\r)
void print(const char *promptStr,unsigned char *data,int len)
{
int i;
printf("======%s[长度=%d]======\n",promptStr,len);
for(i = 0; i < len; i++) printf("%02x", data[i]);
printf("\n===============\n");
}
//base64编码
void encode(unsigned char* outData,
int * outlen,
const unsigned char* data,
int datalen)
{
int tmp=0;
EVP_ENCODE_CTX base64;
EVP_EncodeInit(&base64);//base64编码初始化
//编码数据,由于数据不多,所以没有使用循环
EVP_EncodeUpdate(&base64,//base64编码上下文对象
outData,//编码后的数据
outlen, //编码后的数据长度
data, //要编码的数据
datalen //要编码的数据长度
);
tmp=*outlen;
//结束base64编码,事实上此时数据已经编码完全
EVP_EncodeFinal(&base64,outData+*outlen,outlen);
*outlen+=tmp;
outData[*outlen]=0;
print("base64编码后:",outData,*outlen);
}
//base64解码
bool decode(unsigned char* outData,
int * outlen,
const unsigned char* data,
int datalen)
{
int tmp=0,i=0,lines=0,currpos=0;
EVP_ENCODE_CTX base64;
EVP_DecodeInit(&base64);//base64解码初始化
//假定outData缓冲区能够容纳所有的结果
for (;;)
{
currpos+=CHARS_PER_LINE_BASE64*lines++;
//下面函数的返回值中:i=1 表示还有更多行需要解码
//i=0 表示没有进一步的数据需要解码
i=EVP_DecodeUpdate(&base64,//base64解码上下文对象
outData+tmp, //解码后的数据
outlen, //解码后的数据长度
data+currpos, //要解码的数据
datalen-currpos);//要解码的数据长度
if (i < 0)
{
printf("解码错误!\n");
return false;
}
tmp+=*outlen;
if (i == 0) break;//数据结束
}
//结束base64解码
EVP_DecodeFinal(&base64,outData+tmp,outlen);
*outlen=tmp;
outData[*outlen]=0;
print("base64解码后:",outData,*outlen);
return true;
}
void main(int argc, char *argv[])
{
const int ITERATIVE_ROUND_FOR_KEY=3;
unsigned char key[EVP_MAX_KEY_LENGTH];//密钥
unsigned char iv[EVP_MAX_IV_LENGTH];//初始向量
EVP_CIPHER_CTX ctx;//加密上下文对象
unsigned char out[512+8];
int outl;
unsigned char txtAfterDecrypt[512];
int txtLenAfterDecrypt;
char simpleText[]="Let's pray for peace of our lovely world";
unsigned char txtAfterBase64[sizeof(simpleText)*3];
//密码
const char *passwd="a78b5C";//用于产生密钥的口令字符串
const EVP_CIPHER *type;//加密类型对象
OpenSSL_add_all_ciphers();//加载加密算法
OpenSSL_add_all_digests();//加载摘要计算算法
printf("密码是:%s\n",passwd);
type=EVP_des_ede3_cbc();
printf("密钥长度=%d,向量长度=%d\n",type->key_len,type->iv_len);
//从文本密码中产生 密钥/向量
//这个例程使用MD5并且采用来自RSA的PCKS#5的标准
EVP_BytesToKey(type,//密钥类型
EVP_md5(),//摘要计算类型
NULL,
(const unsigned char *)passwd,//口令串
(int)strlen(passwd),//口令串长度
ITERATIVE_ROUND_FOR_KEY,//迭代轮数
key,//输出的密钥
iv //输出的初始向量
);
//加密初始化,ctx是加密上下文对象
EVP_EncryptInit(&ctx,type,key,iv);
int tmp=(int)strlen(simpleText);
//由于数据量少,不用循环加入数据
EVP_EncryptUpdate(&ctx,//加密上下文对象
out,//加密后的内容
&outl, //加密后的内容长度
(const unsigned char*)simpleText, //要加密的内容
(int)strlen(simpleText) //要加密的内容长度
);
tmp=outl;
//结束加密
EVP_EncryptFinal(&ctx,out+outl,&outl);
outl+=tmp;
//清除加密上下文,因为下文还要重用
EVP_CIPHER_CTX_cleanup(&ctx);
print("加密之后的结果:",out,outl);
//进行base64编码
encode(txtAfterBase64,&tmp,out,outl);
memset(out,0,sizeof(out));
//进行base64解码
decode(out,&outl,txtAfterBase64,tmp);
//解密初始化,解密类型,密钥,初始向量必需和加密时相同,否则解密不能成功
EVP_DecryptInit(&ctx,type,key,iv);
EVP_DecryptUpdate(&ctx,//解密上下文对象
txtAfterDecrypt, //解密后的内容
&txtLenAfterDecrypt,//解密后的内容长度
out, //要解密的内容
outl //要解密的内容长度
);
tmp=txtLenAfterDecrypt;
//结束解密
EVP_DecryptFinal(&ctx,txtAfterDecrypt+txtLenAfterDecrypt,&txtLenAfterDecrypt);
txtLenAfterDecrypt+=tmp;
EVP_CIPHER_CTX_cleanup(&ctx);
txtAfterDecrypt[txtLenAfterDecrypt]=0;
printf("解密之后(长度=%d):\n[%s]\n\n",txtLenAfterDecrypt,txtAfterDecrypt);
printf("click any key to continue.");
//相当于暂停,观察运行结果
getchar();
}