通过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. 【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理

    Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两 ...

  2. Python——requests的安装及入门-贴吧爬虫

    一.windows平台下requests的安装 1.win+R,输入cmd,打开命令行窗口,输入命令:pip install requests ,即可自动安装库成功 2.输入命令:pip list,即 ...

  3. Application received signal SIGABRT

    Application received signal SIGABRT (null) (( 0 CoreFoundation 0x0000000182bbadc8 <redacted> + ...

  4. TX2 默认root用户启动

    Jetpack3.1 修改方式 修改1 gedit /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf 修改后: 修改2 gedit /root/.pro ...

  5. x-boot

    https://github.com/Exrick/x-boot-front https://gitee.com/Exrick/x-boot

  6. 使用octave符号运算求解不定积分、微分方程等(兼容matlab)

    1.求解1/(1+cos(x))^2的不定积分. 在和学生讨论一道物理竞赛题的时候,出现了这个函数的积分求解需求.查积分表也可写出答案.但是可以使用octave的符号运算工具箱来做. syms x; ...

  7. tar命令加密压缩/解密解压

    在tar解压文件时发生下面错误信息 gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error is not rec ...

  8. n阶幻方

    前序 最近在学习一些经典的算法,搞得头昏脑涨,就想换换脑子.在家里的旧书堆里面乱翻,无意中将一本具有十多年历史的小学数学奥林匹克竞赛的书发掘了出来,能放到现在挺不容易的,就拿起来随便翻翻.看了看目录, ...

  9. LeetCode8. 字符串转整数 (atoi)

    8. 字符串转整数 (atoi) 描述 实现 atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连 ...

  10. c#工具类之Bitmap缩放帮忙类

    using System.Drawing; using System.Drawing.Drawing2D; /// <summary> /// BitmapHelper /// </ ...