通过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
 #include <Windows.h>
#include <WinCrypt.h>
#include <stdio.h>
#include <tchar.h> #pragma comment(lib, "crypt32.lib") #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING|X509_ASN_ENCODING) void HandleError(char * str)
{
printf("%s[%x]\n",str,GetLastError());
system("pause");
exit();
} int main(int argc, char* argv[])
{
HCRYPTPROV hCryptProv = NULL; //CSP句柄
LPCTSTR pszContainerName = TEXT("MyKeyContainer"); //CSP密钥容器句柄
HCRYPTKEY hKey = NULL;
BYTE* pbKeyBlob;
DWORD dwBlobLen; if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
))
{
printf("获取到");
_tprintf(TEXT("[%s]"), pszContainerName);
printf("的密钥容器\n");
}
else
{
//发生错误,如果是密钥容器不存在,则创建新的密钥容器
if (GetLastError() == NTE_BAD_KEYSET)
{
if (CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
printf("新的密钥容器已创建\n");
}
else
{
HandleError("无法创建密钥容器");
}
}
else
{
HandleError("无法获取CSP句柄");
}
} //获取一个加解密key句柄
if (CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hKey))
{
printf("获取到加解密key句柄\n");
}
else
{
if (GetLastError() == NTE_NO_KEY)
{
//因为没有密钥对, 创建一个
printf("密钥对不存在,创建一个密钥对\n");
if (CryptGenKey(hCryptProv, AT_KEYEXCHANGE,CRYPT_EXPORTABLE,&hKey))
{
printf("创建签名验签密钥对成功\n");
}
else
{
HandleError("创建密钥对失败");
}
}
else
{
HandleError("获取密钥对错误,签名验签密钥对不可用");
}
} //PUBLICKEYBLOB
//PRIVATEKEYBLOB
if(!(CryptExportKey( hKey, NULL, PUBLICKEYBLOB,, NULL, &dwBlobLen)))
{
HandleError("导出公钥信息失败");
} pbKeyBlob = (BYTE*)malloc(dwBlobLen); if(!(CryptExportKey( hKey, NULL, PUBLICKEYBLOB,, pbKeyBlob, &dwBlobLen)))
{
HandleError("导出公钥信息失败2;");
} printf("公钥BLOB信息如下:\n");
for(int i=;i<dwBlobLen;i++)
{
if (i % == )
{
printf("\n");
}
printf("%02X ", pbKeyBlob[i]);
}
printf("\n"); BLOBHEADER blobHeader;
RSAPUBKEY rsaPubkey;
PBYTE p = NULL;
p = pbKeyBlob;
//分析得到的BLOB
memcpy(&blobHeader.bType, p, );
p += ;
memcpy(&blobHeader.bVersion, p, );
p += ;
memcpy(&blobHeader.reserved, p, );
p += ;
memcpy(&blobHeader.aiKeyAlg, p, );
p += ; memcpy(&rsaPubkey.magic, p, );
p += ;
memcpy(&rsaPubkey.bitlen, p, );
p += ;
memcpy(&rsaPubkey.pubexp, p, );
p += ;
PBYTE reaMod = (PBYTE)LocalAlloc(LPTR, rsaPubkey.bitlen/);
memcpy(reaMod, p, rsaPubkey.bitlen/); //需要转换一下
BYTE bTemp;
for (int i=;i< rsaPubkey.bitlen//; i++)
{
bTemp = reaMod[i];
reaMod[i] = reaMod[rsaPubkey.bitlen/ - i - ];
reaMod[rsaPubkey.bitlen/- i - ] = bTemp;
} printf("BLOBHEADER.bType=[%02x]\n", blobHeader.bType);
printf("BLOBHEADER.bVersion=[%02x]\n", blobHeader.bVersion);
printf("BLOBHEADER.reserved=[%d]\n", blobHeader.reserved);
printf("BLOBHEADER.aiKeyAlg=[%d]\n\n", blobHeader.aiKeyAlg);
printf("rsaPubkey.magic=[");
char* q = (char *)&rsaPubkey.magic;
for (int i = ;i<;i++)
{
printf("%c",*q++);
} printf("]\nrsaPubkey.bitlen=[%d]\n", rsaPubkey.bitlen);
printf("rsaPubkey.pubexp=[%d]\n", rsaPubkey.pubexp);
printf("RSA MOD:\n");
for(int i=;i<rsaPubkey.bitlen/;i++)
{
if (i % == )
{
printf("\n");
}
printf("%02X ", reaMod[i]);
}
printf("\n"); //释放
LocalFree(reaMod); free(pbKeyBlob);
if (hKey)
{
CryptDestroyKey(hKey);
} if(hCryptProv)
{
CryptReleaseContext(hCryptProv, );
} if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_DELETEKEYSET))
{
printf("删除容器成功\n");
}
else
{
HandleError("删除容器失败");
}
system("pause");
return ;
}

结果如下:

导出私钥的代码跟导出公钥类似,修改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. Django 使用第三方服务发送电子邮件

    在 Django 网站中使用 mailgun 的邮件收发服务. 1.在 mailgun 官网上注册个账号(免费,免费账号每个月有10000条收发邮件的服务,对我来说已经完全够用了),注册完成后界面如图 ...

  2. MySQL 学习笔记(三):完整性和触发器设计

    (一)完整性设计 方法一.在设计表时定义约束 删除数据库school,建立新数据库school1 drop database school; create database school; use s ...

  3. loj#6437. 「PKUSC2018」PKUSC(计算几何)

    题面 传送门 题解 计算几何的东西我好像都已经忘光了-- 首先我们可以把原问题转化为另一个等价的问题:对于每一个敌人,我们以原点为圆心,画一个经过该点的圆,把这个圆在多边形内部的圆弧的度数加入答案.求 ...

  4. mysql主从复制数据库

    mysql主从复制相信已经用得很多了,但是由于工作原因一直没怎么用过.趁着这段时间相对空闲,也就自己实现一遍.尽管互联网上已有大把类似的文章,但是自身实现的仍然值得记录. 环境: 主服务器:cento ...

  5. DataRow[]转DataTable

    DataRow[]有个扩展方法CopyToDataTable()

  6. bzoj3196 二逼平衡树 树状数组套线段树

    题目传送门 思路:树状数组套线段树模板题. 什么是树状数组套线段树,普通的树状数组每个点都是一个权值,而这里的树状数组每个点都是一颗权值线段树,我们用前缀差分的方法求得每个区间的各种信息, 其实关键就 ...

  7. HDU2588

    结论:如果p是n的约数,那么满足gcd(i,n)==p的i的个数是Φ(n/p) #include<bits/stdc++.h> using namespace std; const int ...

  8. filezilla绑定编辑器

    编辑  - >设置 ->文件格式关联 ->输入需要关联的编辑器的路径

  9. PHPExcel 读取的几个例子

    1.使用 PHPExcel_IOFactory 读取文件 $objPHPExcel = PHPExcel_IOFactory::load($inputFileName); 2.使用一个特定的读取类,读 ...

  10. Q859 亲密字符串

    给定两个由小写字母构成的字符串 A 和 B ,只要我们可以通过交换 A 中的两个字母得到与 B 相等的结果,就返回 true :否则返回 false . 示例 1: 输入: A = "ab& ...