通过CryptExportKey( hKey, NULL, PUBLICKEYBLOB,0, NULL, &dwBlobLen)

函数导出的公钥信息如下:
06 02 00 00 00 A4 00 00 52 53
41 31 00 04 00 00 01 00 01 00
CD 85 DA 77 E8 CE 2D 25 84 C5
6F 4F E8 0C BA 30 12 1B 4E 73
49 5D 37 9D 9A BD 21 41 F6 36
C3 84 76 EA 95 9F AD D5 7A E1
27 94 32 6C DA 2E F9 E1 4E 4B
D3 4A AE 1A F9 C2 19 1E 66 DE
59 CB D1 D6 BF 4F 2B 68 E1 35
FD 8E 0D 2E 26 3A 29 09 10 FB
56 73 00 CB 22 9E AE 4C 4B 0E
2E 20 F0 1E 5C 48 47 D7 A2 2A
C3 B2 B2 A8 90 BF AF 10 77 31
7F 0F 62 A2 F5 5B 48 1A B1 A9
51 C6 2F B6 1C 72 17 C5
 
 
其中红色部分是key BLOBHeader
紫色部分表示公钥magic
黄色部分表示公钥模长
浅绿色表示公钥指数
蓝色部分表示公钥的模
 
 
 
接下来主要分析BLOBHeader部分
PUBLICKEYSTRUC 结构,也即BLOBHEADER结构,表明了一个key的算法及BLOB类型
结构体如下:
typedef struct _PUBLICKEYSTRUC{
    BYTE     bType;
    BYTE     bVersion;
    WORD  reserved;
    ALG_ID aiKeyAlg;
}BLOBHEARER,
PUBLICKEYSTURC;
 
 
结构成员解释如下
(1) bType------(1个字节)表示 key的BLOB类型
            列表如下:
 
(2)bVersion------(2个字节)表示BLOB格式的版本信息
            目前该值为CUR_BLOB_VERSION(0x02)
 
(3)reserved------保留将来用,目前设置为0
 
(4)aiKeyAlg------(4个字节)ALG_ID结构,包含该key的算法信息
            注:并不是所有的算法标志都是有效的BLOB类型。例如,一个RC4的密钥,它是交换密钥,并不能被PUBLICKEYBLOB导出
 
 
 
公钥结构体如下:
typedef struct _RSAPUBKEY{
    DWORD    magic;
    DWORD    bitlen;
    DWORD    pubexp;
}RSAPUBKEY;
 
 
结构体成员如下
(1)magic--------Set to RSA1 (0x31415352) for public keys and to RSA2 (0x32415352) for private keys.
(2)bitlen--------公钥模长(比特长度)
(3)pubexp------公钥指数
 
 
再后边就是公钥的模了,长度为公钥的模长。
由于csp的数据排列和其他不用,因此需要将获取到的后边的模作一次颠倒处理。既将最后一个字节和第一个字节对调,依次类推。
 
 
 
 
 
通过函数

CryptExportKey( hKey, NULL, PRIVATEKEYBLOB,0, pbKeyBlob, &dwBlobLen)
导出的密钥对信息如下
注:在产生该密钥对时,需要
CryptGenKey(hCryptProv, AT_KEYEXCHANGE,CRYPT_EXPORTABLE,&hKey)
这个CRYPT_EXPORTABLE必须要有,否则该密钥对会因为权限问题导出失败
 
07 02 00 00 00 A4 00 00 52 53
41 32 00 04 00 00 01 00 01 00
CD DD 41 C4 99 BC E2 0E BC 4C
09 CC 7A D9 62 7F 29 24 25 66
E5 4F 56 42 13 30 96 9E 1B 42
1B 99 BF 24 66 B8 CB DD 4B E7
02 2A 67 1E C5 54 0A 83 88 F8
80 5C 0A E9 FA 19 24 41 4F 9F
B4 A7 1A 52 36 7D D1 44 1A 17
DF F1 12 73 EF 12 61 51 5E 13
00 ED 50 A6 85 98 98 17 03 E6
CF 5B 51 BE 22 CC 3E 39 1F 94
58 EC 84 07 91 69 C3 EB 5B F3
0B D6 26 F5 3E AB 58 C1 55 8A
A7 43 89 E0 87 1D 9C 8B 95 09
D5 9E 80 70 21 FA 84 82 F0 C4
DC 75 F7 BB 78 E5 02 F2 B6 90
8E B6 65 DD DD A0 F5 52 34 8A
F4 70 41 C7 36 33 84 4C 17 42
43 71 1E D5 B3 C8 44 44 45 EE
6B AC 0D 27 5C A8 5C 18 3A 3E
3F C0 59 25 D3 6C 1C A7 36 05
EE 4B E5 84 5A 7C 72 AA 15 10
E1 04 A5 41 D0 70 A9 34 48 44
51 90 34 AA 30 B4 BF EA 08 75
19 5F AF B4 C7 64 84 10 47 C3
F7 74 0B 56 BF BA 51 75 C8 E6
61 81 3F 40 E8 B9 79 8A BA 34
17 71 ED B8 C9 8E 0A AC A4 AC
39 6B 88 50 C8 A8 8D 89 4F ED
E2 C8 49 00 CA 3D 0B 0C A9 B8
63 68 58 9E 9C 69 48 21 28 9D
83 91 06 01 70 62 E7 C9 98 64
3B C7 38 7E AE B7 55 61 9B 77
01 C7 6D D8 34 07 D0 5A 10 EA
28 13 47 12 66 CB A2 5A B8 48
44 F4 B0 E1 39 BB 74 EB 36 67
83 73 34 91 CA 6A 03 C4 3E C2
66 8C FC 04 48 C5 2A 5A C5 40
AF 90 CB 20 A4 AF 37 BA 12 63
B5 E0 24 93 75 FF C4 8A F8 43
E3 7E EB 84 E3 4C A0 2F AC 5D
73 F7 53 7D 60 82 75 DF 2C 3C
CF CA C5 95 06 2F 8C 2E 5C 2F
7C 27 83 29 B6 F6 34 09 AA 5C
F1 9E 8C A4 10 95 3B EA 10 26
51 31 97 08 6F DD 85 82 E1 94
12 16 21 C9 08 B3 21 33 F1 9A
FB 8F 2F 4B A4 B7 1D D3 76 9A
17 E1 60 89 6F D8 B4 64 26 47
4A 5C 62 77 77 06 B9 B5 C3 52
D5 1E 75 6A 6F BA 3E 4E 05 A6
C3 0C C5 3F 5E B5 F5 EB AB 15
94 1D AB 11 A1 A3 9B 58 67 C9
8B 17 07 22 26 A1 8C 8D 3E 7D
DA AA AC 9B 0A 58 B6 A1 97 38
6C D6 DF 73 1F 4E 74 C2 E0 FE
34 E2 06 A0 DA E5 D7 73 F3 C4
82 68 B2 88 1A AE 7C 0E DF 75
A8 2B F7 C5 6C 63
 
 
分析如下:
私钥BLOB
BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];

 
 
 
 
 
//BLOBHEADER
0702000000A40000
//密钥magic
52534132
//公钥模长
00040000
//公钥指数
01000100
//公钥n 也即公钥的模 即 prime1*prime2
CDDD41C499BCE20EBC4C09CC7AD9627F29242566E54F56421330969E1B421B99BF2466B8CBDD4BE7022A671EC5540A8388F8805C0AE9FA1924414F9FB4A71A52367DD1441A17DFF11273EF1261515E1300ED50A68598981703E6CF5B51BE22CC3E391F9458EC84079169C3EB5BF30BD626F53EAB58C1558AA74389E0871D9C8B
//私钥p 也即prime1
9509D59E807021FA8482F0C4DC75F7BB78E502F2B6908EB665DDDDA0F552348AF47041C73633844C174243711ED5B3C8444445EE6BAC0D275CA85C183A3E3FC0
//私钥q 也即prime2
5925D36C1CA73605EE4BE5845A7C72AA1510E104A541D070A9344844519034AA30B4BFEA0875195FAFB4C764841047C3F7740B56BFBA5175C8E661813F40E8B9
//私钥exponent1 私钥指数1    也即d mod (p - 1)
798ABA341771EDB8C98E0AACA4AC396B8850C8A88D894FEDE2C84900CA3D0B0CA9B86368589E9C694821289D839106017062E7C998643BC7387EAEB755619B77
//私钥exponent2  私钥指数2  也即d mod (q - 1)
01C76DD83407D05A10EA2813471266CBA25AB84844F4B0E139BB74EB366783733491CA6A03C43EC2668CFC0448C52A5AC540AF90CB20A4AF37BA1263B5E02493
//私钥coef  私钥系数   也即(inverse of q)mod p
75FFC48AF843E37EEB84E34CA02FAC5D73F7537D608275DF2C3CCFCAC595062F8C2E5C2F7C278329B6F63409AA5CF19E8CA410953BEA1026513197086FDD8582
//私钥exp                也即d
E194121621C908B32133F19AFB8F2F4BA4B71DD3769A17E160896FD8B46426474A5C62777706B9B5C352D51E756A6FBA3E4E05A6C30CC53F5EB5F5EBAB15941DAB11A1A39B5867C98B17072226A18C8D3E7DDAAAAC9B0A58B6A197386CD6DF731F4E74C2E0FE34E206A0DAE5D773F3C48268B2881AAE7C0EDF75A82BF7C56C63
  1. #include <Windows.h>
  2. #include <WinCrypt.h>
  3. #include <stdio.h>
  4. #include <tchar.h>
  5.  
  6. #pragma comment(lib, "crypt32.lib")
  7.  
  8. #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING|X509_ASN_ENCODING)
  9.  
  10. void HandleError(char * str)
  11. {
  12. printf("%s[%x]\n",str,GetLastError());
  13. system("pause");
  14. exit();
  15. }
  16.  
  17. int main(int argc, char* argv[])
  18. {
  19. HCRYPTPROV hCryptProv = NULL; //CSP句柄
  20. LPCTSTR pszContainerName = TEXT("MyKeyContainer"); //CSP密钥容器句柄
  21. HCRYPTKEY hKey = NULL;
  22. BYTE* pbKeyBlob;
  23. DWORD dwBlobLen;
  24.  
  25. if(CryptAcquireContext(
  26. &hCryptProv,
  27. NULL,
  28. NULL,
  29. PROV_RSA_FULL,
  30. ))
  31. {
  32. printf("获取到");
  33. _tprintf(TEXT("[%s]"), pszContainerName);
  34. printf("的密钥容器\n");
  35. }
  36. else
  37. {
  38. //发生错误,如果是密钥容器不存在,则创建新的密钥容器
  39. if (GetLastError() == NTE_BAD_KEYSET)
  40. {
  41. if (CryptAcquireContext(
  42. &hCryptProv,
  43. NULL,
  44. NULL,
  45. PROV_RSA_FULL,
  46. CRYPT_NEWKEYSET))
  47. {
  48. printf("新的密钥容器已创建\n");
  49. }
  50. else
  51. {
  52. HandleError("无法创建密钥容器");
  53. }
  54. }
  55. else
  56. {
  57. HandleError("无法获取CSP句柄");
  58. }
  59. }
  60.  
  61. //获取一个加解密key句柄
  62. if (CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hKey))
  63. {
  64. printf("获取到加解密key句柄\n");
  65. }
  66. else
  67. {
  68. if (GetLastError() == NTE_NO_KEY)
  69. {
  70. //因为没有密钥对, 创建一个
  71. printf("密钥对不存在,创建一个密钥对\n");
  72. if (CryptGenKey(hCryptProv, AT_KEYEXCHANGE,CRYPT_EXPORTABLE,&hKey))
  73. {
  74. printf("创建签名验签密钥对成功\n");
  75. }
  76. else
  77. {
  78. HandleError("创建密钥对失败");
  79. }
  80. }
  81. else
  82. {
  83. HandleError("获取密钥对错误,签名验签密钥对不可用");
  84. }
  85. }
  86.  
  87. //PUBLICKEYBLOB
  88. //PRIVATEKEYBLOB
  89. if(!(CryptExportKey( hKey, NULL, PUBLICKEYBLOB,, NULL, &dwBlobLen)))
  90. {
  91. HandleError("导出公钥信息失败");
  92. }
  93.  
  94. pbKeyBlob = (BYTE*)malloc(dwBlobLen);
  95.  
  96. if(!(CryptExportKey( hKey, NULL, PUBLICKEYBLOB,, pbKeyBlob, &dwBlobLen)))
  97. {
  98. HandleError("导出公钥信息失败2;");
  99. }
  100.  
  101. printf("公钥BLOB信息如下:\n");
  102. for(int i=;i<dwBlobLen;i++)
  103. {
  104. if (i % == )
  105. {
  106. printf("\n");
  107. }
  108. printf("%02X ", pbKeyBlob[i]);
  109. }
  110. printf("\n");
  111.  
  112. BLOBHEADER blobHeader;
  113. RSAPUBKEY rsaPubkey;
  114. PBYTE p = NULL;
  115. p = pbKeyBlob;
  116. //分析得到的BLOB
  117. memcpy(&blobHeader.bType, p, );
  118. p += ;
  119. memcpy(&blobHeader.bVersion, p, );
  120. p += ;
  121. memcpy(&blobHeader.reserved, p, );
  122. p += ;
  123. memcpy(&blobHeader.aiKeyAlg, p, );
  124. p += ;
  125.  
  126. memcpy(&rsaPubkey.magic, p, );
  127. p += ;
  128. memcpy(&rsaPubkey.bitlen, p, );
  129. p += ;
  130. memcpy(&rsaPubkey.pubexp, p, );
  131. p += ;
  132. PBYTE reaMod = (PBYTE)LocalAlloc(LPTR, rsaPubkey.bitlen/);
  133. memcpy(reaMod, p, rsaPubkey.bitlen/);
  134.  
  135. //需要转换一下
  136. BYTE bTemp;
  137. for (int i=;i< rsaPubkey.bitlen//; i++)
  138. {
  139. bTemp = reaMod[i];
  140. reaMod[i] = reaMod[rsaPubkey.bitlen/ - i - ];
  141. reaMod[rsaPubkey.bitlen/- i - ] = bTemp;
  142. }
  143.  
  144. printf("BLOBHEADER.bType=[%02x]\n", blobHeader.bType);
  145. printf("BLOBHEADER.bVersion=[%02x]\n", blobHeader.bVersion);
  146. printf("BLOBHEADER.reserved=[%d]\n", blobHeader.reserved);
  147. printf("BLOBHEADER.aiKeyAlg=[%d]\n\n", blobHeader.aiKeyAlg);
  148. printf("rsaPubkey.magic=[");
  149. char* q = (char *)&rsaPubkey.magic;
  150. for (int i = ;i<;i++)
  151. {
  152. printf("%c",*q++);
  153. }
  154.  
  155. printf("]\nrsaPubkey.bitlen=[%d]\n", rsaPubkey.bitlen);
  156. printf("rsaPubkey.pubexp=[%d]\n", rsaPubkey.pubexp);
  157. printf("RSA MOD:\n");
  158. for(int i=;i<rsaPubkey.bitlen/;i++)
  159. {
  160. if (i % == )
  161. {
  162. printf("\n");
  163. }
  164. printf("%02X ", reaMod[i]);
  165. }
  166. printf("\n");
  167.  
  168. //释放
  169. LocalFree(reaMod);
  170.  
  171. free(pbKeyBlob);
  172. if (hKey)
  173. {
  174. CryptDestroyKey(hKey);
  175. }
  176.  
  177. if(hCryptProv)
  178. {
  179. CryptReleaseContext(hCryptProv, );
  180. }
  181.  
  182. if(CryptAcquireContext(
  183. &hCryptProv,
  184. NULL,
  185. NULL,
  186. PROV_RSA_FULL,
  187. CRYPT_DELETEKEYSET))
  188. {
  189. printf("删除容器成功\n");
  190. }
  191. else
  192. {
  193. HandleError("删除容器失败");
  194. }
  195. system("pause");
  196. return ;
  197. }

结果如下:

导出私钥的代码跟导出公钥类似,修改CryptExportKey函数的第3个参数为PRIVATEKEYBLOB 即可。

CSP学习之导出密钥BLOB 解析的更多相关文章

  1. CSP学习之CryptoAPI初识

    Crypto API目的就是提供开发者在windows下使用PKI的编程接口. Crypto 提供了很多的加解密相关函数,如编码.解码.加密解密,哈希,数字证书.证书管理证书存储等.       有关 ...

  2. Batik - 将svg转换成其他格式图片或PDF - [导出服务器配置] 导出服务器原理解析

    导出服务器原理解析 Highcharts图表导出(或下载)本质上是将SVG代码转换为不同文件格式的过程,用到的工具是batik,所以所谓导出服务器,只不过是调用batik,将SVG代码转换并下载.下图 ...

  3. Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition

    Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition Property animation系统还提供了对ViewGroup中的View改变 ...

  4. Android Animation学习(四) ApiDemos解析:多属性动画

    Android Animation学习(四) ApiDemos解析:多属性动画 如果想同时改变多个属性,根据前面所学的,比较显而易见的一种思路是构造多个对象Animator , ( Animator可 ...

  5. Android Animation学习(三) ApiDemos解析:XML动画文件的使用

    Android Animation学习(三) ApiDemos解析:XML动画文件的使用 可以用XML文件来定义Animation. 文件必须有一个唯一的根节点: <set>, <o ...

  6. Android Animation学习(二) ApiDemos解析:基本Animators使用

    Android Animation学习(二) ApiDemos解析:基本Animatiors使用 Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.O ...

  7. Android Animation学习(二) ApiDemos解析:基本Animatiors使用

    Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.ObjectAnimator.AnimatorSet ApiDemos中Animation部分是单独 ...

  8. Mybatis源码学习之parsing包(解析器)(二)

    简述 大家都知道mybatis中,无论是配置文件mybatis-config.xml,还是SQL语句,都是写在XML文件中的,那么mybatis是如何解析这些XML文件呢?这就是本文将要学习的就是,m ...

  9. 简单学习一下ibd数据文件解析

    来源:原创投稿 作者:花家舍 简介:数据库技术爱好者. GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 简单学习一下数据文件解析 这是尝试使用Golang语言简单解析My ...

随机推荐

  1. 跟我一起读postgresql源码(三)——Rewrite(查询重写模块)

    上一篇博文我们阅读了postgresql中查询分析模块的源码.查询分析模块对前台送来的命令进行词法分析.语法分析和语义分析后获得对应的查询树(Query).在获得查询树之后,程序开始对查询树进行查询重 ...

  2. 11、C内存四区模型

    转载于:https://blog.csdn.net/wu5215080/article/details/38899259 内存四区模型 图1.内存四区模型流程说明1.操作系统把物理硬盘代码load到内 ...

  3. iframe里面的元素触发父窗口元素事件的jquery代码 转

    例如父窗口定义了一个事件. top: $(dom1).bind('topEvent', function(){}); 那么iframe里面的元素怎样触发父窗口dom1的事件呢?这样吗? $(dom1, ...

  4. /bin/bash: sshpass: command not found

    按照如下命令进行安装即可: apt-get install sshpass

  5. ionic3 IPX留海适配

    解决:使用 safe-area-inset-top 等 ios 安全区域变量 + meta 标签中设置 viewport-fit=cover https://github.com/pengkobe/r ...

  6. php 页面压缩---

    网站优化中,页面压缩是很有效的一种方法,可以明显提升页面访问速度. 页面压缩也有很多的方法,有PHP自带的zlib的gzip压缩,还有清除html页面中不必要的字符,空格,注释,换行符等. 第一种打开 ...

  7. liunx php 安装 redis 扩展

    切换到安装目录:  cd /usr/local/ 下载php redis扩展:wget http://pecl.php.net/get/redis-2.2.8.tgz 更改名称压缩包名称: mv re ...

  8. abp架构添加实体并使用迁移功能生成表

    参考: https://aspnetboilerplate.com/Pages/Articles/Introduction-With-AspNet-Core-And-Entity-Framework- ...

  9. QQ链接病毒分析

    QQ链接病毒分析 特征 点击病毒链接后,自动会在每一时刻范围内通过所有途径群发新的病毒链接(途径包括Qzone,群聊等) 分析 首先看一下病毒链接的一个样例 http://news.soso.com/ ...

  10. 执行npm install 时会报 operation not permitted,unlink......错

    问题现象:在我这项目目录中执行这命令就会报这个错. 问题原因: 后来查了查,说是 npm 5.4.0版本确实会有这个问题. https://github.com/npm/npm/issues/1828 ...