Windows平台RSA加解密

RSA加密算法是当前常用的非对称加密算法;windows平台有RSA相关API,不需要借助openssl等三方库即可在C/C++代码进行RSA密钥生成及加解密处理。windows在Vista版本后提供了全新加解密API,本文结合实现代码介绍这些API的使用方法。

生成密钥

#include “windows.h”
#include “bcrypt.h”
#pragma comment(lib, "Bcrypt.lib")

void generate_rsakey() {
  BCRYPT_ALG_HANDLE alg;
  BCRYPT_KEY_HANDLE  keyHandle;
  BCryptOpenAlgorithmProvider(&alg, BCRYPT_RSA_ALGORITHM, NULL, 0);

  BCryptGenerateKeyPair(alg, &keyHandle, 1024, 0);
  BCryptFinalizeKeyPair(keyHandle, 0); /* 生成密钥后一定要调用此函数,否则无法导出 */

  UCHAR output[1024];
  ULONG len;
  BCryptExportKey(keyHandle, NULL, BCRYPT_RSAPUBLIC_BLOB, output, sizeof(output), &len, 0);  /* 如果要导出公钥,则使用BCRYPT_RSAPRIVATE_BLOB类型导出 */

  /* 导出后可以存储到文件... */

  /* 释放资源 */
  BCryptDestroyKey(keyHandle);
  BCryptCloseAlgorithmProvider(alg, 0);
}

密钥格式

PKCS8及ASN.1编码

网上很多资料都写PKCS8是用于私钥格式,但实际上公钥同样可以使用PKCS8;openssl工具生成的公钥就是这种格式,而且一般是base64化后的文本形式,其原始二进制(即DER)是ASN.1编码格式。如果需要了解ASN.1及PKCS细节,可以进一步查看参考资料。

简而言之,密钥可以认为“密钥头部 + 密钥 + 密钥指数“三部分组成:相同长度的密钥其头部封装是相同的,指数由算法确定

BCryptExportKey函数输出信息

BCryptExportKey函数的输出信息(上文中output),公钥由三部分组成

BCRYPT_RSAKEY_BLOB
PublicExponent[cbPublicExp] // Big-endian.
Modulus[cbModulus] // Big-endian.

BCRYPT_RSAKEY_BLOB结构格式如下

typedef struct _BCRYPT_RSAKEY_BLOB {
  ULONG Magic;
  ULONG BitLength;
  ULONG cbPublicExp; //密钥指数长度
  ULONG cbModulus;
  ULONG cbPrime1;
  ULONG cbPrime2;
} BCRYPT_RSAKEY_BLOB;

根据上述信息,可以输出需要的最终密钥文件

生成1024长度密钥的完整代码参考
DWORD RsaGenKey() {
  UCHAR pkcs8header[] = { 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00 };

  BCRYPT_ALG_HANDLE alg;
  BCRYPT_KEY_HANDLE  keyHandle;
  BCryptOpenAlgorithmProvider(&alg, BCRYPT_RSA_ALGORITHM, NULL, 0);

  BCryptGenerateKeyPair(alg, &keyHandle, 1024, 0);
  BCryptFinalizeKeyPair(keyHandle, 0);

  UCHAR output[2 * 1024];
  ULONG len;
  char base64[2 * 1024];
  ULONG base64len = sizeof(base64);
  BCryptExportKey(keyHandle, NULL, BCRYPT_RSAPRIVATE_BLOB, output, sizeof(output), &len, 0);

  HANDLE xfile = CreateFileA("rsa", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  WriteFile(xfile, output, len, &len, NULL);
  CloseHandle(xfile);

  BCryptExportKey(keyHandle, NULL, BCRYPT_RSAPUBLIC_BLOB, output + 1000, sizeof(output) - 1000, &len, 0);
   _BCRYPT_RSAKEY_BLOB* info = (_BCRYPT_RSAKEY_BLOB*)&output[1000];
   /* for 1024bit der */
  UCHAR* p = output + 1000 + len;
   //以下三行是指数的ASN.1编码,0x02表示整数,接着长度和值
  *p = 0x02;
  *(p + 1) = info->cbPublicExp;
  memcpy(p + 2, info + 1, info->cbPublicExp);

  p = (UCHAR*)(info + 1) + info->cbPublicExp - sizeof(pkcs8header);
  memcpy(p, pkcs8header, sizeof(pkcs8header));
  CryptBinaryToStringA(p, 0x9F + 3, CRYPT_STRING_BASE64, base64, &base64len); //base64转化为字符串

  xfile = CreateFileA("pkcs8.pub", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  WriteFile(xfile, base64, base64len, &len, NULL);
  CloseHandle(xfile);

  BCryptDestroyKey(keyHandle);
  BCryptCloseAlgorithmProvider(alg, 0);

  return 0;
}

加解密

string RsaDecrypt(const UCHAR* decrypt, int len) {
  BCRYPT_ALG_HANDLE alg;
  BCRYPT_KEY_HANDLE hKey;

  BCryptOpenAlgorithmProvider(&alg, BCRYPT_RSA_ALGORITHM, NULL, 0);

  UCHAR key[1024];
  ULONG xlen;
  /* ...从文件读入密钥到数组key */

  BCryptImportKeyPair(alg, NULL, BCRYPT_RSAPRIVATE_BLOB, &hKey, key, xlen, 0);

  UCHAR plain[1024];
  BCryptDecrypt(hKey, bin, len, NULL, NULL, 0, plain, sizeof(plain), &xlen, BCRYPT_PAD_PKCS1); //填充方式必须和加密端相同,此处是BCRYPT_PAD_PKCS1
  plain[xlen] = 0; // 如果明文是字符串,必须增加字符串结尾0

  /* 释放资源 */
  BCryptDestroyKey(hKey);
  BCryptCloseAlgorithmProvider(alg, 0);

  return (char*)plain;
}
 

参考资料

微软官方API说明

PKCS1与PKCS8的小知识 - 简书 (jianshu.com)

密码学基础3:密钥文件格式完全解析 - 简书 (jianshu.com)

RFC 8017 - PKCS #1: RSA Cryptography Specifications Version 2.2 (ietf.org)

openssl - How is OID 2a 86 48 86 f7 0d parsed as 1.2.840.113549? - Cryptography Stack Exchange

Windows平台RSA加解密 (ziliuyun.net)

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MFC(Microsoft Foundation Class)是微软公司提供的一套用于开发Windows应用程序的C++类库。RSA(Rivest-Shamir-Adleman)是一种非对称密算法,用于实现数据的密和解密。 在MFC中使用RSA进行文件解密,首先需要生成RSA密钥对。可以使用MFC中提供的CRSAKey类来生成公钥和私钥。 对于文件密,可以先打开需要密的文件,读取文件内容,并使用公钥对文件内容进行密。密后的内容可以写入到新的文件中,或者覆盖原始文件。密过程可以使用MFC中的CRSAEncrypt类来实现。 对于文件解密,可以先打开需要解密的文件,读取文件内容,并使用私钥对文件内容进行解密解密后的内容可以写入到新的文件中,或者覆盖原始文件。解密过程可以使用MFC中的CRSADecrypt类来实现。 需要注意的是,RSA密算法对于大文件来说效率较低,因此在实际应用中可能需要对大文件进行分块处理。同时,为了保证密的安全性,私钥应该妥善保管,防止泄露。 总结来说,使用MFC实现RSA文件的解密需要生成RSA密钥对,然后使用公钥对文件内容进行密,使用私钥对文件内容进行解密密和解密的过程可以利用MFC中提供的相关类来实现。但在实际应用中,还需要对大文件进行分块处理,并确保私钥的安全性。 ### 回答2: MFC是一种基于Microsoft的Windows操作系统的编程框架,它提供了一些强大的工具和组件,方便开发人员创建各种Windows应用程序。RSA是一种非对称密算法,广泛应用于信息安全领域。 在MFC中使用RSA进行文件解密,首先需要使用RSA算法库提供的函数生成公钥和私钥。公钥用于密文件,私钥用于解密文件。一般来说,公钥是用于密的,私钥是用于解密的。 密文件的过程如下: 1. 打开待密的文件。 2. 读取文件内容,并将内容转换成可被RSA密的格式。 3. 使用公钥对数据进行密。 4. 将密后的数据写入到新的文件中。 5. 关闭文件。 解密文件的过程如下: 1. 打开待解密的文件。 2. 读取文件内容。 3. 使用私钥对数据进行解密。 4. 将解密后的数据写入到新的文件中。 5. 关闭文件。 在实际操作中,可以使用MFC提供的文件操作类(如CFile)来打开和操作文件,使用RSA算法库提供的函数来进行解密操作。 总结起来,使用MFC的RSA文件解密涉及到生成公钥和私钥、打开文件、读取和写入文件、解密数据等过程。这些步骤需要结合MFC和RSA算法库进行完成。 ### 回答3: MFC(Microsoft Foundation Class)是一种用于开发Windows桌面应用程序的C++类库。RSA(Rivest-Shamir-Adleman)是一种非对称密算法,广泛用于保护敏感信息的安全传输和存储。 MFC提供了一些与文件操作相关的类,可以方便地进行文件的读写操作。对于RSA文件解密,可以按照以下步骤进行: 1. 导入所需的MFC类库以及包含RSA算法相关的头文件。 2. 创建一个用于存储公钥和私钥的密钥对。可以使用RSA算法生成公私钥对,并将其保存在文件中。 3. 对需要密的文件进行处理。可以使用MFC提供的类读取原始文件的内容,并将其存储在内存中。 4. 使用公钥对内存中的数据进行密。可以使用RSA算法提供的密函数,在内存中对数据进行密操作。 5. 将密后的数据保存到新的文件中。可以使用MFC提供的类将密后的数据写入新的文件中。 6. 对密后的文件进行解密。可以使用私钥对密后的文件进行解密操作,还原出原始数据。 通过以上步骤,便可以使用MFC的RSA文件解密功能实现对文件的保护。需要注意的是,在实际使用过程中,还需要考虑异常处理、文件读写权限等因素,以确保程序的稳定性和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值