vc++网络安全编程范例(17)-open ssl 实现文件加密与解密

vc++网络安全编程范例(17)-open ssl 实现文件加密与解密
2011年12月17日
  OpenSSL整个软件包大概可以分成三个主要的功能部分:密码算法库、SSL协议库以及应用程序。OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。 作为一个基于密码学的安全开发包,OpenSSL提供的功能相当强大和全面,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。
  对称加密算法
  OpenSSL一共提供了8种对称加密算法,其中7种是分组加密算法,仅有的一种流加密算法是RC4。这7种分组加密算法分别是AES、DES、Blowfish、CAST、IDEA、RC2、RC5,都支持电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)四种常用的分组密码加密模式。其中,AES使用的加密反馈模式(CFB)和输出反馈模式(OFB)分组长度是128位,其它算法使用的则是64位。事实上,DES算法里面不仅仅是常用的DES算法,还支持三个密钥和两个密钥3DES算法。
  非对称加密算法
  OpenSSL一共实现了4种非对称加密算法,包括DH算法、RSA算法、DSA算法和椭圆曲线算法(EC)。DH算法一般用户密钥交换。RSA算法既可以用于密钥交换,也可以用于数字签名,当然,如果你能够忍受其缓慢的速度,那么也可以用于数据加密。DSA算法则一般只用于数字签名。
  信息摘要算法
  OpenSSL实现了5种信息摘要算法,分别是MD2、MD5、MDC2、SHA(SHA1)和RIPEMD。SHA算法事实上包括了SHA和SHA1两种信息摘要算法,此外,OpenSSL还实现了DSS标准中规定的两种信息摘要算法DSS和DSS1。
  我们来用VC++实现文件加密,请见代码实现与注释讲解 #include #include #include #include #include #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #define KEYLENGTH 0x00800000 void HandleError(char *s); HCRYPTPROV GetCryptProv(); #define ENCRYPT_ALGORITHM CALG_RC4 #define ENCRYPT_BLOCK_SIZE 8 BOOL EncryptFile( PCHAR szSource, PCHAR szDestination, PCHAR szPassword); HCRYPTKEY GenKeyByPassword(HCRYPTPROV hCryptProv,PCHAR szPassword); HCRYPTKEY GenKeyByRandom(HCRYPTPROV hCryptProv,FILE* hDestination); //------------------------------------------------ ------------------- // Begin main. void main(void) { PCHAR szSource; PCHAR szDestination; CHAR szPassword[100] = ""; char response; if(!(szSource=(char *)malloc(100))) HandleError("Memory allocation failed."); if(!(szDestination=(char *)malloc(100))) HandleError("Memory allocation failed."); printf("加密一个文件. \n\n"); printf("请输入需要被加密文件的名称: "); fgets(szSource, 100, stdin); if(szSource[strlen(szSource)-1] == '\n') szSource[strlen(szSource)-1] = '\0'; printf("请输入需要输出文件文件的名称: "); fgets(szDestination, 100, stdin); if(szDestination[strlen(szDestination)-1] == '\n') szDestination[strlen(szDestination)-1] = '\0'; printf("要使用密码对这个文件加密吗? ( y/n ) "); response = getchar(); if(response == 'y') { printf("请输入密码:"); getchar(); gets(szPassword); } else { printf("密钥将生成但没有使用密码. \n"); } //------------------------------------------------ ------------------- // 调用函数 EncryptFile 进行实际的加密操作. if(EncryptFile(szSource, szDestination, szPassword)) { printf("对文件 %s 的加密已经成功! \n", szSource); printf("加密后的数据存储在文件 %s 中.\n",szDestination); } else { HandleError("解密文件出错!"); } //------------------------------------------------ ------------------- // 释放内存. if(szSource) free(szSource); if(szDestination) free(szDestination); } // end main //------------------------------------------------ ------------------- // 功能:加密原文szSource文件,加密后的数据存储在szDestination文件中 // 参数: // szSource:原文文件名 // szDestination:加密后数据存储文件 // szPassword:用户输入的密码 static BOOL EncryptFile( PCHAR szSource, PCHAR szDestination, PCHAR szPassword) { //------------------------------------------------ ------------------- // 变量申明与初始化. FILE *hSource; FILE *hDestination; HCRYPTPROV hCryptProv; HCRYPTKEY hKey; PBYTE pbBuffer; DWORD dwBlockLen; DWORD dwBufferLen; DWORD dwCount; //------------------------------------------------ ------------------- // 打开原文文件. if(hSource = fopen(szSource,"rb")) { printf("原文文件 %s 已经打开. \n", szSource); } else { HandleError("打开原文文件出错!"); } //------------------------------------------------ ------------------- // 打开目标文件. if(hDestination = fopen(szDestination,"wb")) { printf("目标文件 %s 已经打开. \n", szDestination); } else { HandleError("打开目标文件出错!"); } //获取加密服务者句柄 hCryptProv = GetCryptProv(); //------------------------------------------------ ------------------- // 创建会话密钥. if(!szPassword || strcmp(szPassword,"")==0 ) { //------------------------------------------------ -------------- // 当输入密码为空时,则创建随机的加密密钥,并导出创建的密钥保存到文件中. hKey = GenKeyByRandom( hCryptProv, hDestination); } else { //------------------------------------------------ -------------- // 当输入密码不为空时,则通过输入密码创建加密密钥 hKey=GenKeyByPassword( hCryptProv, szPassword); } //------------------------------------------------ -------------------- // 因为加密算法按ENCRYPT_BLOCK_SIZE 大小块加密,所以被加密的 // 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍。下面计算一次加密的 // 数据长度。 dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE; //------------------------------------------------ -------------------- // 确定加密后密文数据块大小. 若是分组密码模式,则必须有容纳额外块的空间 if(ENCRYPT_BLOCK_SIZE > 1) dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE; else dwBufferLen = dwBlockLen; //------------------------------------------------ ------------------- // 分配内存空间. if(pbBuffer = (BYTE *)malloc(dwBufferLen)) { printf("已经为缓冲区分配了内存. \n"); } else { HandleError("所需内存不够. \n"); } //------------------------------------------------ ------------------- // 循环加密 原文件 do { //------------------------------------------------ ------------------- // 每次从原文件中读取dwBlockLen字节数据. dwCount = fread(pbBuffer, 1, dwBlockLen, hSource); if(ferror(hSource)) { HandleError("读取明文文件出错!\n"); } //------------------------------------------------ ------------------- // 加密数据. if(!CryptEncrypt( hKey, //密钥 0, //如果数据同时进行散列和加密,这里传入一个散列对象 feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输入FALSE. //这里通过判断是否到文件尾来决定是否为最后一块。 0, //保留 pbBuffer, //输入被加密数据,输出加密后的数据 &dwCount, //输入被加密数据实际长度,输出加密后数据长度 dwBufferLen)) //pbBuffer的大小。 { HandleError("Error during CryptEncrypt. \n"); } //------------------------------------------------ ------------------- // 把加密后数据写到密文文件中 fwrite(pbBuffer, 1, dwCount, hDestination); if(ferror(hDestination)) { HandleError("写入密文时出错."); } } while(!feof(hSource)); //------------------------------------------------ ------------------- // 关闭文件 if(hSource) { if(fclose(hSource)) HandleError("关闭原文文件出错!"); } if(hDestination) { if(fclose(hDestination)) HandleError("关闭目标文件出错!"); } //------------------------------------------------ ------------------- // 释放内存空间. if(pbBuffer) free(pbBuffer); //------------------------------------------------ ------------------- // 销毁会话密钥 if(hKey) { if(!(CryptDestroyKey(hKey))) HandleError("Error during CryptDestroyKey"); } //------------------------------------------------ ------------------- // 释放CSP句柄 if(hCryptProv) { if(!(CryptReleaseContext(hCryptProv, 0))) HandleError("Error during CryptReleaseContext"); } return(TRUE); } // end Encryptfile //获取加密提供者句柄 HCRYPTPROV GetCryptProv() { HCRYPTPROV hCryptProv; // 加密服务提供者句柄 //获取加密提供者句柄 if(CryptAcquireContext( &hCryptProv, // 加密服务提供者句柄 NULL, // 密钥容器名,这里使用登陆用户名 MS_ENHANCED_PROV, // 加密服务提供者 PROV_RSA_FULL, // 加密服务提供者类型,可以提供加密和签名等功能 0)) // 标志 { printf("加密服务提供者句柄获取成功!\n"); } else { //重新建立一个新的密钥集 if(!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { HandleError("重新建立一个新的密钥集出错!"); } } return hCryptProv; } // HandleError:错误处理函数,打印错误信息,并退出程序 void HandleError(char *s) { printf("程序执行发生错误!\n"); printf("%s\n",s); printf("错误代码为: %x.\n",GetLastError()); printf("程序终止执行!\n"); exit(1); } // GenKeyByRandom:通过随机数创建会话密钥 // 参数:hCryptProv CSP句柄 // hDestination 目标文件,导出的会话密钥保存在此文件中 HCRYPTKEY GenKeyByRandom(HCRYPTPROV hCryptProv,FILE* hDestination) { HCRYPTKEY hKey; HCRYPTKEY hXchgKey; PBYTE pbKeyBlob; DWORD dwKeyBlobLen; if(CryptGenKey( hCryptProv, ENCRYPT_ALGORITHM, KEYLENGTH | CRYPT_EXPORTABLE, &hKey)) { printf("一个会话密钥已经被创建. \n"); } else { HandleError("Error during CryptGenKey. \n"); } //------------------------------------------------ -------------- // 创建交换密钥 if(CryptGenKey( hCryptProv, AT_KEYEXCHANGE, 0, &hXchgKey)) { printf("交换密钥对已经创建.\n"); } else { HandleError("在试图创建交换密钥时出错.\n"); } //------------------------------------------------ -------------- // 确定密钥数据块长度,并分配空间. if(CryptExportKey( hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwKeyBlobLen)) { printf("此密钥块的长度是 %d 字节. \n",dwKeyBlobLen); } else { HandleError("计算密钥数据块长度出错! \n"); } if(pbKeyBlob =(BYTE *)malloc(dwKeyBlobLen)) { printf("已经问此密钥块分配了内存. \n"); } else { HandleError("所需内存不够. \n"); } //------------------------------------------------ -------------- // 导出会话密钥到简单密钥数据块中. if(CryptExportKey( hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwKeyBlobLen)) { printf("此会话密钥已经被导出. \n"); } else { HandleError("Error during CryptExportKey!\n"); } //------------------------------------------------ -------------- //释放交换密钥句柄. if(hXchgKey) { if(!(CryptDestroyKey(hXchgKey))) HandleError("Error during CryptDestroyKey"); hXchgKey = 0; } //------------------------------------------------ -------------- // 写密钥块长度到目标文件. fwrite(&dwKeyBlobLen, sizeof(DWORD), 1, hDestination); if(ferror(hDestination)) { HandleError("写密钥块长度出错."); } else { printf("密钥块长度已经被写入. \n"); } //------------------------------------------------ -------------- //写密钥块数据到目标文件. fwrite(pbKeyBlob, 1, dwKeyBlobLen, hDestination); if(ferror(hDestination)) { HandleError("写密钥数据出错"); } else { printf("此密钥块数据已经被写入目标文件. \n"); } // 释放内存空间. free(pbKeyBlob); //返回创建的会话密钥 return hKey; } // GenKeyByRandom:通过输入密码创建会话密钥 // 参数:hCryptProv CSP句柄 // szPassword 输入密码 HCRYPTKEY GenKeyByPassword(HCRYPTPROV hCryptProv,PCHAR szPassword) { HCRYPTKEY hKey; HCRYPTHASH hHash; //------------------------------------------------ ------------------- // 创建哈希句柄. if(CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash)) { printf("一个哈希句柄已经被创建. \n"); } else { HandleError("Error during CryptCreateHash!\n"); } //------------------------------------------------ ------------------- // 计算输入密码的哈希值. if(CryptHashData( hHash, (BYTE *)szPassword, strlen(szPassword), 0)) { printf("密码已经被添加到了哈希表中. \n"); } else { HandleError("Error during CryptHashData. \n"); } //------------------------------------------------ ------------------- // 通过哈希值创建会话密钥. if(CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, &hKey)) { printf("通过密码的哈希值获得了加密密钥. \n"); } else { HandleError("Error during CryptDeriveKey!\n"); } //------------------------------------------------ ------------------- // 销毁哈希句柄. if(hHash) { if(!(CryptDestroyHash(hHash))) HandleError("Error during CryptDestroyHash"); hHash = 0; } //返回创建的会话密钥 return hKey; }
  我们来用VC++实现文件解密,请见代码实现与注释讲解
  #include #include #include #include #include #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #define KEYLENGTH 0x00800000 void HandleError(char *s); HCRYPTPROV GetCryptProv(); #define ENCRYPT_ALGORITHM CALG_RC4 #define ENCRYPT_BLOCK_SIZE 8 BOOL DecryptFile( PCHAR szSource, PCHAR szDestination, CHAR *szPassword); HCRYPTKEY GenKeyByPassword(HCRYPTPROV hCryptProv,PCHAR szPassword); HCRYPTKEY GenKeyFromFile(HCRYPTPROV hCryptProv,FILE* hSource); void main(void) { //------------------------------------------------ -------------------- // 变量申明与初始化. PCHAR szSource; PCHAR szDestination; CHAR szPassword[100] = ""; char response; if(!(szSource=(char *)malloc(100))) HandleError("Memory allocation failed."); if(!(szDestination=(char *)malloc(100))) HandleError("Memory allocation failed."); printf("解密一个文件. \n\n"); printf("请输入需要解密文件的名称: "); fgets(szSource, 100, stdin); if(szSource[strlen(szSource)-1] == '\n') szSource[strlen(szSource)-1] = '\0'; printf("请输入要输出文件的名称: "); fgets(szDestination, 100, stdin); if(szDestination[strlen(szDestination)-1] == '\n') szDestination[strlen(szDestination)-1] = '\0'; printf("加密这个文件时是否使用了密码? ( y/n ) "); response = getchar(); if(response == 'y') { getchar(); printf("请输入密码:"); gets(szPassword); } else { printf("密钥将被生成但没有使用密码. \n"); } //解密文件 if(!DecryptFile(szSource, szDestination, szPassword)) { printf("\nError decrypting file. \n"); } else { printf("\n对文件 %s 的解密成功了. \n", szSource); printf("被解密的文件是 %s .\n",szDestination); } //------------------------------------------------ -------------------- // 释放内存空间. if(szSource) free(szSource); if(szDestination) free(szDestination); } // End main //------------------------------------------------ ------------------- // 功能:解密密文szSource文件,解密后的数据存储在szDestination文件中 // 参数: // szSource:密文文件名 // szDestination:解密后数据存储文件 // szPassword:用户输入的密码 static BOOL DecryptFile( PCHAR szSource, PCHAR szDestination, PCHAR szPassword) { //------------------------------------------------ -------------------- // 局部变量申明与初始化. FILE *hSource; FILE *hDestination; HCRYPTPROV hCryptProv; HCRYPTKEY hKey; PBYTE pbBuffer; DWORD dwBlockLen; DWORD dwBufferLen; DWORD dwCount; BOOL status = FALSE; //------------------------------------------------ -------------------- // 打开密文文件. if(!(hSource = fopen(szSource,"rb"))) { HandleError("打开密文文件出错!"); } //------------------------------------------------ -------------------- // 打开目标文件,用于存储解密后的数据. if(!(hDestination = fopen(szDestination,"wb"))) { HandleError("打开明文文件出错!"); } //获取加密服务者句柄 hCryptProv = GetCryptProv(); //获取或创建会话密钥 if(!szPassword|| strcmp(szPassword,"")==0 ) { //------------------------------------------------ -------------------- //从密文文件导入保存的会话密钥 hKey = GenKeyFromFile( hCryptProv,hSource); } else { //------------------------------------------------ -------------------- // 通过输入密码重新创建会话密钥. hKey=GenKeyByPassword( hCryptProv, szPassword); } // 计算一次解密的数据长度,它是ENCRYPT_BLOCK_SIZE 的整数倍 dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE; dwBufferLen = dwBlockLen; //------------------------------------------------ -------------------- // 分配内存空间. if(!(pbBuffer = (BYTE *)malloc(dwBufferLen))) { HandleError("所需内存不够!\n"); } //------------------------------------------------ -------------------- // 解密密文文件,解密后数据保存在目标文件 do { //------------------------------------------------ -------------------- // 每次从密文文件中读取dwBlockLen字节数据. dwCount = fread( pbBuffer, 1, dwBlockLen, hSource); if(ferror(hSource)) { HandleError("读取密文文件出错!"); } //------------------------------------------------ -------------------- // 解密 数据 if(!CryptDecrypt( hKey, 0, feof(hSource), 0, pbBuffer, &dwCount)) { HandleError("Error during CryptDecrypt!"); } //------------------------------------------------ -------------------- // 把解密后的数据写入目标文件中. fwrite( pbBuffer, 1, dwCount, hDestination); if(ferror(hDestination)) { HandleError("Error writing plaintext!"); } } while(!feof(hSource)); status = TRUE; //------------------------------------------------ -------------------- // 关闭文件 if(hSource) { if(fclose(hSource)) HandleError("关闭原文件出错"); } if(hDestination) { if(fclose(hDestination)) HandleError("关闭目标文件出错"); } //------------------------------------------------ -------------------- // 释放内存空间 if(pbBuffer) free(pbBuffer); //------------------------------------------------ -------------------- // 销毁会话密钥 if(hKey) { if(!(CryptDestroyKey(hKey))) HandleError("Error during CryptDestroyKey"); } //------------------------------------------------ -------------------- // 释放CSP句柄 if(hCryptProv) { if(!(CryptReleaseContext(hCryptProv, 0))) HandleError("Error during CryptReleaseContext"); } return status; } // end Decryptfile //获取加密提供者句柄 HCRYPTPROV GetCryptProv() { HCRYPTPROV hCryptProv; // 加密服务提供者句柄 //获取加密提供者句柄 if(CryptAcquireContext( &hCryptProv, // 加密服务提供者句柄 NULL, // 密钥容器名,这里使用登陆用户名 MS_ENHANCED_PROV, // 加密服务提供者 PROV_RSA_FULL, // 加密服务提供者类型,可以提供加密和签名等功能 0)) // 标志 { printf("加密服务提供者句柄获取成功!\n"); } else { //重新建立一个新的密钥集 if(!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { HandleError("重新建立一个新的密钥集出错!"); } } return hCryptProv; } // HandleError:错误处理函数,打印错误信息,并退出程序 void HandleError(char *s) { printf("程序执行发生错误!\n"); printf("%s\n",s); printf("错误代码为: %x.\n",GetLastError()); printf("程序终止执行!\n"); exit(1); } // GenKeyFromFile:从密文文件中导出会话密钥 // 参数:hCryptProv CSP句柄 // hSource 保存会话密钥的文件 HCRYPTKEY GenKeyFromFile(HCRYPTPROV hCryptProv,FILE* hSource) { HCRYPTKEY hKey; PBYTE pbKeyBlob; DWORD dwKeyBlobLen; //从密文文件中获取密钥数据块长度,并分配内存空间. fread(&dwKeyBlobLen, sizeof(DWORD), 1, hSource); if(ferror(hSource) || feof(hSource)) { HandleError("读取密文文件中密钥数据块长度出错!"); } if(!(pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen))) { HandleError("内存分配出错."); } //------------------------------------------------ -------------------- // 从密文文件中获取密钥数据块 fread(pbKeyBlob, 1, dwKeyBlobLen, hSource); if(ferror(hSource) || feof(hSource)) { HandleError("读取密文文件中密钥数据块出错!\n"); } //------------------------------------------------ -------------------- // 导入会话密钥到 CSP. if(!CryptImportKey( hCryptProv, pbKeyBlob, dwKeyBlobLen, 0, 0, &hKey)) { HandleError("Error during CryptImportKey!"); } if(pbKeyBlob) free(pbKeyBlob); //返回导出的会话密钥 return hKey; } // GenKeyByPassword:通过输入密码创建会话密钥 // 参数:hCryptProv CSP句柄 // szPassword 输入密码 HCRYPTKEY GenKeyByPassword(HCRYPTPROV hCryptProv,PCHAR szPassword) { HCRYPTKEY hKey; HCRYPTHASH hHash; //------------------------------------------------ ------------------- // 创建哈希句柄. if(CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash)) { printf("一个哈希句柄已经被创建. \n"); } else { HandleError("Error during CryptCreateHash!\n"); } //------------------------------------------------ ------------------- // 计算输入密码的哈希值. if(CryptHashData( hHash, (BYTE *)szPassword, strlen(szPassword), 0)) { printf("此密码已经被添加到了哈希表中. \n"); } else { HandleError("Error during CryptHashData. \n"); } //------------------------------------------------ ------------------- // 通过哈希值创建会话密钥. if(CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, &hKey)) { printf("从这个密码的哈希值获得了一个加密密钥. \n"); } else { HandleError("Error during CryptDeriveKey!\n"); } //------------------------------------------------ ------------------- // 销毁哈希句柄. if(hHash) { if(!(CryptDestroyHash(hHash))) HandleError("Error during CryptDestroyHash"); hHash = 0; } //返回创建的会话密钥 return hKey; }

你可能感兴趣的:(vc++网络安全编程范例(17)-open ssl 实现文件加密与解密)