OpenSSL初学总结
2008年12月29日星期一
最近一段时间看些关于OpenSSL加密函数的使用,现将一些使用总结如下:
1、 OpenSSL简介:
openssl是一个功能丰富且自包含的开源安全工具箱。它提供的主要功能有:SSL协议实现(包括SSLv2、SSLv3和TLSv1)、大量软算法(对称/非对称/摘要)、大数运算、非对称算法密钥生成、ASN.1编解码库、证书请求(PKCS10)编解码、数字证书编解码、CRL编解码、OCSP协议、数字证书验证、PKCS7标准实现和PKCS12个人数字证书格式实现等功能。
openssl采用C语言作为开发语言,这使得它具有优秀的跨平台性能。openssl支持Linux、UNIX、windows、Mac等平台。
2、 OpenSSL加密算法——AES加密流程:
(1) 加密
设置加密密钥:AES_set_encrypt_key
加密:AES_encrypt
(2) 减密
设置减密密钥:AES_set_decrypt_key
减密:AES_decrypt
3、 OpenSSL加密算法——RSA加密流程:
(1) 公钥加密,私钥减密
初始化RSA加密:RSA_new
设置密钥:RSA_general_key(自动生成)和BN_bin2bn(加载)
验证密钥:RSA_check_key
指定Padding和要加密的长度(通常选择RSA_PKCS1_PADDING)
加密:RSA_public_encrypt
减密:RSA_private_decrypt
释放RSA:RSA_free
(2) 私钥加密,公钥减密
初始化RSA加密:RSA_new
设置密钥:RSA_general_key(自动生成)和BN_bin2bn(加载)
验证密钥:RSA_check_key
指定Padding和要加密的长度(通常选择RSA_PKCS1_PADDING)
加密:RSA_private_encrypt
减密:RSA_public_decrypt
释放RSA:RSA_free
4、 对上述两种算法接口的简单封装:
类CMyOpenSSL头文件:
//------------------------------------------------------------------------------------------
/*
类名:CMyOpenSSL
功能:实现了对OpenSSL中RSA和AES加密的基本操作的简单封装
*/
#pragmaonce
#include<openssl/rsa.h>
#include<openssl/sha.h>
#include<openssl/aes.h>
#pragmacomment(lib,"libeay32.lib")
#include"define.h"
#define OPENSSL_RSA_BUFFBLOCK 128 // RSA缓冲区块
#define OPENSSL_AES_BUFFBLOCK 16 // AES缓冲区块
enum RSA_TYPE // 加密类型
{
PUBENCRYPT,
PRIENCRYPT
};
enum PADDING // Padding类型
{
RSA_NO,
RSA_PKCS1,
RSA_SSLV23,
// RSA_X931,
RSA_PKCS1_OAEP
};
constint RSA_bits = 1024; // RSA bits
constunsignedlong e = RSA_3;
constint AES_bits = 128; // AES bits
// class CMyOpenSSL //----
class CMyOpenSSL
{
public:
CMyOpenSSL(void);
~CMyOpenSSL(void);
ULONGLONG m_sourceFileLen; // 原文件大小
int m_len; // 加减密缓存大小
virtualvoid GetSourceFileLen(ULONGLONG len);
// RSA Encrypt/Decrypt //----
public:
void InitRSA(); // 初始化RSA加密
void FreeRSA(); // 释放RSA加密
void GenerateKey(); // 自动生成密钥
void GetEncryptKey(RSA_TYPE type); // 根据加密类型,将外界导入的密钥生成RSA加密密钥
void GetDecryptKey(RSA_TYPE type); // 根据加密类型,将外界导入的密钥生成RSA减密密钥
BOOL CheckKey(); // 验证RSA密钥信息
int RSAEncrypt(unsignedchar from[OPENSSL_RSA_BUFFBLOCK],unsignedchar to[OPENSSL_RSA_BUFFBLOCK],
RSA_TYPE type); // RSA加密函数
void RSADecrypt(unsignedchar from[OPENSSL_RSA_BUFFBLOCK],unsignedchar to[OPENSSL_RSA_BUFFBLOCK],
RSA_TYPE type); // RSA减密函数
void MyEncryptFile(LPCTSTR sourceFileName,LPCTSTR destFileName,RSA_TYPE type);
// RSA文件加密函数
void MyDecryptFile(LPCTSTR sourceFileName,LPCTSTR destFileName,RSA_TYPE type);
// RSA文件减密函数
int GetBuffLen(PADDING padding); // 获取加减密缓冲区大小
private:
RSA *m_rsa; // RSA密钥
int m_padding; // RSA padding类型
int m_nRetLen; // 加密返回的密文长度
int m_nRet; // 返回值
//------------------------------------------------------------------------------------------
// AES Encrypt/Decrypt //----
public:
void SetEncryptKey(unsignedchar *aes_key); // 设置AES加密密钥
void SetDecryptKey(unsignedchar *aes_key); // 设置AES减密密钥
void MyAESEncryptFile(LPCTSTR sourceFileName,LPCTSTR destFileName,unsignedchar *aes_key);
// AES文件加密函数
void MyAESDecryptFile(LPCTSTR sourceFileName,LPCTSTR destFileName,unsignedchar *aes_key);
// AES文件减密函数
private:
AES_KEY m_key; // AES密钥
unsignedchar m_from[OPENSSL_AES_BUFFBLOCK],m_to[OPENSSL_AES_BUFFBLOCK]; // 输入、输出缓冲区
};
//--------------------------------------------------------------------------------------
类CMyOpenSSL源文件:
#include"StdAfx.h"
#include"MyOpenSSL.h"
CMyOpenSSL::CMyOpenSSL(void)
{
m_len = 0;
m_nRetLen = OPENSSL_RSA_BUFFBLOCK;
}
CMyOpenSSL::~CMyOpenSSL(void)
{
}
// RSA //-----
void CMyOpenSSL::InitRSA()
{
m_rsa = RSA_new();
}
void CMyOpenSSL::FreeRSA()
{
RSA_free(m_rsa);
}
void CMyOpenSSL::GenerateKey()
{
m_rsa = RSA_generate_key(RSA_bits,e,NULL,NULL);
}
void CMyOpenSSL::GetEncryptKey(RSA_TYPE type)
{
m_rsa->n = BN_bin2bn(rsa_N,sizeof(rsa_N),m_rsa->n);
// if (type == PUBENCRYPT)
// {
// m_rsa->e = BN_bin2bn(rsa_E,sizeof(rsa_E),m_rsa->e);
// }
// else if (type == PRIENCRYPT)
{
m_rsa->e = BN_bin2bn(rsa_E,sizeof(rsa_E),m_rsa->e);
m_rsa->d = BN_bin2bn(rsa_D,sizeof(rsa_D),m_rsa->d);
}
m_rsa->p = BN_bin2bn(rsa_P,sizeof(rsa_P),m_rsa->p);
m_rsa->q = BN_bin2bn(rsa_Q,sizeof(rsa_Q),m_rsa->q);
m_rsa->dmp1 = BN_bin2bn(rsa_DP,sizeof(rsa_DP),m_rsa->dmp1);
m_rsa->dmq1 = BN_bin2bn(rsa_DQ,sizeof(rsa_DQ),m_rsa->dmq1);
m_rsa->iqmp = BN_bin2bn(rsa_InverseQ,sizeof(rsa_InverseQ),m_rsa->iqmp);
}
void CMyOpenSSL::GetDecryptKey(RSA_TYPE type)
{
m_rsa->n = BN_bin2bn(rsa_N,sizeof(rsa_N),m_rsa->n);
// if (type == PRIENCRYPT)
// {
// m_rsa->e = BN_bin2bn(rsa_E,sizeof(rsa_E),m_rsa->e);
// }
// else if (type == PUBENCRYPT)
{
m_rsa->e = BN_bin2bn(rsa_E,sizeof(rsa_E),m_rsa->e);
m_rsa->d = BN_bin2bn(rsa_D,sizeof(rsa_D),m_rsa->d);
}
m_rsa->p = BN_bin2bn(rsa_P,sizeof(rsa_P),m_rsa->p);
m_rsa->q = BN_bin2bn(rsa_Q,sizeof(rsa_Q),m_rsa->q);
m_rsa->dmp1 = BN_bin2bn(rsa_DP,sizeof(rsa_DP),m_rsa->dmp1);
m_rsa->dmq1 = BN_bin2bn(rsa_DQ,sizeof(rsa_DQ),m_rsa->dmq1);
m_rsa->iqmp = BN_bin2bn(rsa_InverseQ,sizeof(rsa_InverseQ),m_rsa->iqmp);
}
BOOL CMyOpenSSL::CheckKey()
{
m_nRet = RSA_check_key(m_rsa);
return m_nRet;
}
int CMyOpenSSL::GetBuffLen(PADDING padding)
{
m_len = RSA_size(m_rsa);
switch (padding)
{
case RSA_NO:
m_padding = RSA_NO_PADDING;
m_len = m_len;
break;
case RSA_PKCS1:
m_padding = RSA_PKCS1_PADDING;
m_len -= 11;
break;
case RSA_SSLV23:
m_padding = RSA_SSLV23_PADDING;
m_len -= 11;
break;
// case RSA_X931:
// m_padding = RSA_X931_PADDING;
// m_len -= 2;
// break;
case RSA_PKCS1_OAEP:
m_padding = RSA_PKCS1_OAEP_PADDING;
m_len = m_len - 2 * SHA_DIGEST_LENGTH - 2;
break;
default:
break;
}
return m_len;
}
int CMyOpenSSL::RSAEncrypt(unsignedchar *from,unsignedchar *to,
RSA_TYPE type)
{
if (type == PUBENCRYPT)
{
m_nRet = RSA_public_encrypt(m_len,from,to,m_rsa,m_padding);
}
else
{
m_nRet = RSA_private_encrypt(m_len,from,to,m_rsa,m_padding);
}
return m_nRet;
}
void CMyOpenSSL::RSADecrypt(unsignedchar *from,unsignedchar *to,
RSA_TYPE type)
{
if (type == PUBENCRYPT)
{
m_nRet = RSA_private_decrypt(m_nRetLen,from,to,m_rsa,m_padding);
}
else
{
m_nRet = RSA_public_decrypt(m_nRetLen,from,to,m_rsa,m_padding);
}
}
void CMyOpenSSL::MyEncryptFile(LPCTSTR sourceFileName, LPCTSTR destFileName, RSA_TYPE type)
{
// Open source file and dest file
CFile sourceFile,destFile;
sourceFile.Open(sourceFileName,CFile::modeRead);
destFile.Open(destFileName,CFile::modeCreate | CFile::modeWrite);
ULONGLONG sourceLen,destLen,sourceOff,destOff;
sourceLen = sourceFile.GetLength();
m_sourceFileLen = sourceLen;
destLen = 0;
sourceOff = 0;
destOff = 0;
// read, encrypt and write
unsignedchar sourceBuff[OPENSSL_RSA_BUFFBLOCK],destBuff[OPENSSL_RSA_BUFFBLOCK];
while (sourceLen > destLen)
{
sourceFile.Read(sourceBuff,m_len);
// Encrypt
m_nRetLen = RSAEncrypt(sourceBuff,destBuff,PRIENCRYPT);
destFile.Write(destBuff,m_nRetLen);
// Update
destLen = destFile.GetLength();
sourceOff += m_len;
destOff += m_nRetLen;
// Move the point to current pos
sourceFile.Seek(sourceOff,CFile::begin);
destFile.Seek(destOff,CFile::begin);
}
// Close file
sourceFile.Close();
destFile.Close();
}
void CMyOpenSSL::MyDecryptFile(LPCTSTR sourceFileName, LPCTSTR destFileName, RSA_TYPE type)
{
// Open and read file
CFile sourceFile,destFile;
sourceFile.Open(sourceFileName,CFile::modeRead);
destFile.Open(destFileName,CFile::modeCreate | CFile::modeWrite);
ULONGLONG destLen,sourceOff,destOff;
destLen = 0;
sourceOff = 0;
destOff = 0;
unsignedchar sourceBuff[OPENSSL_RSA_BUFFBLOCK],destBuff[OPENSSL_RSA_BUFFBLOCK];
while (m_sourceFileLen > destLen)
{
sourceFile.Read(sourceBuff,m_nRetLen);
// Decrypt
RSADecrypt(sourceBuff,destBuff,PRIENCRYPT);
if (m_sourceFileLen - destLen < OPENSSL_RSA_BUFFBLOCK)
m_len = (int)(m_sourceFileLen - destLen);
destFile.Write(destBuff,m_len);
// Update
destLen = destFile.GetLength();
sourceOff += m_nRetLen;
destOff += m_len;
// Move the point to current pos
sourceFile.Seek(sourceOff,CFile::begin);
destFile.Seek(destOff,CFile::begin);
}
// Close file
sourceFile.Close();
destFile.Close();
}
//---------------------------------------------------------------------------------------------
// AES //----
void CMyOpenSSL::SetEncryptKey(unsignedchar *aes_key)
{
AES_set_encrypt_key(aes_key,AES_bits,&m_key);
}
void CMyOpenSSL::SetDecryptKey(unsignedchar *aes_key)
{
AES_set_decrypt_key(aes_key,AES_bits,&m_key);
}
void CMyOpenSSL::MyAESEncryptFile(LPCTSTR sourceFileName, LPCTSTR destFileName,unsignedchar *aes_key)
{
// Set Encrypt Key
SetEncryptKey(aes_key);
// Open source file and dest file
CFile sourceFile,destFile;
sourceFile.Open(sourceFileName,CFile::modeRead);
destFile.Open(destFileName,CFile::modeCreate | CFile::modeWrite);
ULONGLONG sourceLen,destLen,sourceOff,destOff;
sourceLen = sourceFile.GetLength();
m_sourceFileLen = sourceLen;
destLen = 0;
sourceOff = 0;
destOff = 0;
m_len = OPENSSL_AES_BUFFBLOCK;
// read, encrypt and write
while (sourceLen > destLen)
{
sourceFile.Read(m_from,m_len);
// Encrypt
AES_encrypt(m_from,m_to,&m_key);
destFile.Write(m_to,m_len);
// Update
destLen = destFile.GetLength();
sourceOff += m_len;
destOff += m_len;
// Move the point to current pos
sourceFile.Seek(sourceOff,CFile::begin);
destFile.Seek(destOff,CFile::begin);
}
// Close file
sourceFile.Close();
destFile.Close();
}
void CMyOpenSSL::MyAESDecryptFile(LPCTSTR sourceFileName, LPCTSTR destFileName,unsignedchar *aes_key)
{
// Set Decrypt Key
SetDecryptKey(aes_key);
// Open and read file
CFile sourceFile,destFile;
sourceFile.Open(sourceFileName,CFile::modeRead);
destFile.Open(destFileName,CFile::modeCreate | CFile::modeWrite);
ULONGLONG destLen,sourceOff,destOff;
destLen = 0;
sourceOff = 0;
destOff = 0;
m_len = OPENSSL_AES_BUFFBLOCK;
while (m_sourceFileLen > destLen)
{
sourceFile.Read(m_from,m_len);
// Decrypt
AES_decrypt(m_from,m_to,&m_key);
if (m_sourceFileLen - destLen < OPENSSL_AES_BUFFBLOCK)
m_len = (int)(m_sourceFileLen - destLen);
destFile.Write(m_to,m_len);
// Update
destLen = destFile.GetLength();
sourceOff += m_len;
destOff += m_len;
// Move the point to current pos
sourceFile.Seek(sourceOff,CFile::begin);
destFile.Seek(destOff,CFile::begin);
}
// Close file
sourceFile.Close();
destFile.Close();
}
void CMyOpenSSL::GetSourceFileLen(ULONGLONG len)
{
m_sourceFileLen = len;
}
类CMyCryptClass头文件:
//--------------------------------------------------------------------------------------------------------
/*
类名:CMyCryptClass
功能:实现了RSA非对称加密对称密钥,AES对称加密文件数据
*/
#pragmaonce
#include"MyOpenSSL.h"
#define MYCRYPT_PLAINTEXT_BLOCK OPENSSL_AES_BUFFBLOCK // 明文缓冲区块
#define MYCRYPT_CIPHERTEXT_BLOCK OPENSSL_RSA_BUFFBLOCK // 密文缓冲区块
class CMyCryptClass
{
public:
CMyCryptClass(void);
~CMyCryptClass(void);
// Operations
public:
BOOL InitCrypt(); // 初始化加密
void DestroyCrypt(); // 销毁加密
BOOL MyKeyEncrypt(unsignedchar *KeyFrom,unsignedchar *KeyTo,RSA_TYPE type);
// 加密密钥函数
BOOL MyKeyDecrypt(unsignedchar *KeyFrom,unsignedchar *KeyTo,RSA_TYPE type);
// 减密密钥函数
BOOL MyFileEncrypt(LPCTSTR sourceFileName,LPCTSTR destFileName,unsignedchar *key);
// 文件加密函数
BOOL MyFileDecrypt(LPCTSTR sourceFileName,LPCTSTR destFileName,unsignedchar *key);
// 文件减密函数
void GetSourceFileLen(ULONGLONG len);
private:
CMyOpenSSL *m_OpenSSL;
ULONGLONG m_sourceFileLen;
};
//---------------------------------------------------------------------------------------
类CMyCryptClass源文件:
#include"StdAfx.h"
#include"MyCryptClass.h"
CMyCryptClass::CMyCryptClass(void)
{
m_OpenSSL = new CMyOpenSSL();
}
CMyCryptClass::~CMyCryptClass(void)
{
delete m_OpenSSL;
}
BOOL CMyCryptClass::InitCrypt()
{
m_OpenSSL->InitRSA();
return TRUE;
}
void CMyCryptClass::DestroyCrypt()
{
m_OpenSSL->FreeRSA();
}
BOOL CMyCryptClass::MyKeyEncrypt(unsignedchar *KeyFrom,unsignedchar *KeyTo,
RSA_TYPE type)
{
m_OpenSSL->GetEncryptKey(type);
if (!m_OpenSSL->CheckKey()) return FALSE;
m_OpenSSL->GetBuffLen(RSA_PKCS1);
m_OpenSSL->RSAEncrypt(KeyFrom,KeyTo,type);
return TRUE;
}
BOOL CMyCryptClass::MyKeyDecrypt(unsignedchar *KeyFrom,unsignedchar *KeyTo,
RSA_TYPE type)
{
m_OpenSSL->GetDecryptKey(type);
if (!m_OpenSSL->CheckKey()) return FALSE;
m_OpenSSL->GetBuffLen(RSA_PKCS1);
m_OpenSSL->RSADecrypt(KeyFrom,KeyTo,type);
return TRUE;
}
BOOL CMyCryptClass::MyFileEncrypt(LPCTSTR sourceFileName,LPCTSTR destFileName,unsignedchar *key)
{
m_OpenSSL->MyAESEncryptFile(sourceFileName,destFileName,key);
return TRUE;
}
BOOL CMyCryptClass::MyFileDecrypt(LPCTSTR sourceFileName,LPCTSTR destFileName,unsignedchar *key)
{
m_OpenSSL->MyAESDecryptFile(sourceFileName,destFileName,key);
return TRUE;
}
void CMyCryptClass::GetSourceFileLen(ULONGLONG len)
{
m_sourceFileLen = len;
}
5、 使用上面的封装类实现RSA加密对称密钥,AES对称加密文件的小示例:
CMyCryptClass myCrypt;
ULONGLONG fileLen;
char sourceCABFileName[] = "C://Documents and Settings//Administrator//桌面//old//GlobalUpdateFile(src).cab";
char EncryptedCABFileName[] = "C://Documents and Settings//Administrator//桌面//old//GlobalUpdateFile.cab";
void CTestCabDlg::OnBnClickedButton5()
{
// 制作CAB文件,加密并加密密钥写入CAB文件
unsignedchar KeyBeforeEncrypt[MYCRYPT_PLAINTEXT_BLOCK];
unsignedchar KeyAfterEncrypt[MYCRYPT_CIPHERTEXT_BLOCK];
for (int i = 0; i < MYCRYPT_PLAINTEXT_BLOCK; i++)
KeyBeforeEncrypt[i] = aes_Key[i];
// Make CAB file //----
CCabinet a;
a.CreateCabinet(sourceCABFileName);
a.AddFile2Cab("C://Documents and Settings//Administrator//桌面//old//爱要怎么说出口(赵传).mp3");
a.AddFile2Cab("C://Documents and Settings//Administrator//桌面//old//TSReader.ocx");
// add new file for CAB file
// ...
a.FlushCab();
// Get source file len
CFile cab;
cab.Open(EncryptedCABFileName,CFile::modeRead);
fileLen = cab.GetLength();
cab.Close();
// Encrypt the CAB file //----
if (!myCrypt.InitCrypt()) return;
if (!myCrypt.MyKeyEncrypt(KeyBeforeEncrypt,KeyAfterEncrypt,PRIENCRYPT)) return;
if (!myCrypt.MyFileEncrypt((LPCTSTR)sourceCABFileName,(LPCTSTR)EncryptedCABFileName,KeyBeforeEncrypt)) return;
myCrypt.DestroyCrypt();
// 将KeyAfterEncrypt发送给远程接收端
CFile file;
file.Open(EncryptedCABFileName,CFile::modeWrite);
file.SeekToEnd();
file.Write(KeyAfterEncrypt,MYCRYPT_CIPHERTEXT_BLOCK);
file.Close();
}
// Get the file name
CString FileBeforeDecrypt("C://Documents and Settings//Administrator//桌面//old//GlobalUpdateFile.cab"),
FileAfterDecrypt("C://Documents and Settings//Administrator//桌面//new//GlobalUpdateFile(des).cab");
void CTestCabDlg::OnBnClickedButton6()
{
// 从CAB文件中读取密钥密文,解密密钥并解密文件
CFile sourceFile,destFile;
ULONGLONG sourceFileLen;
sourceFile.Open(FileBeforeDecrypt,CFile::modeRead);
sourceFileLen = sourceFile.GetLength();
sourceFile.Seek(sourceFileLen - MYCRYPT_CIPHERTEXT_BLOCK, CFile::begin);
unsignedchar KeyBeforeDecrypt[MYCRYPT_CIPHERTEXT_BLOCK],KeyAfterDecrypt[MYCRYPT_PLAINTEXT_BLOCK];
sourceFile.Read(KeyBeforeDecrypt,MYCRYPT_CIPHERTEXT_BLOCK);
sourceFile.SeekToBegin();
sourceFile.Close();
// Init the crypt
if (!myCrypt.InitCrypt()) return;
// Use RSA to decrypt the key
if (!myCrypt.MyKeyDecrypt(KeyBeforeDecrypt,KeyAfterDecrypt,PRIENCRYPT))
{
MessageBox("解密密钥错误");
return;
}
// Get source file len from ini file
ULONGLONG len = fileLen;
myCrypt.GetSourceFileLen(len);
// Use AES to decrypt the file
if (!myCrypt.MyFileDecrypt(FileBeforeDecrypt.GetBuffer(),FileAfterDecrypt.GetBuffer(),
KeyAfterDecrypt))
{
MessageBox("解密失败");
return;
}
FileBeforeDecrypt.ReleaseBuffer();
FileAfterDecrypt.ReleaseBuffer();
// Free the crypt
myCrypt.DestroyCrypt();
}