通过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(1);
 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         0))
 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 
 62     //获取一个加解密key句柄
 63     if (CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hKey))
 64     {
 65         printf("获取到加解密key句柄\n");
 66     }
 67     else
 68     {
 69         if (GetLastError() == NTE_NO_KEY)
 70         {
 71             //因为没有密钥对, 创建一个
 72             printf("密钥对不存在,创建一个密钥对\n");
 73             if (CryptGenKey(hCryptProv, AT_KEYEXCHANGE,CRYPT_EXPORTABLE,&hKey))
 74             {
 75                 printf("创建签名验签密钥对成功\n");
 76             }
 77             else
 78             {
 79                 HandleError("创建密钥对失败");
 80             }
 81         }
 82         else
 83         {
 84             HandleError("获取密钥对错误,签名验签密钥对不可用");
 85         }
 86     }
 87 
 88     //PUBLICKEYBLOB
 89     //PRIVATEKEYBLOB
 90     if(!(CryptExportKey( hKey, NULL, PUBLICKEYBLOB,0, NULL, &dwBlobLen))) 
 91     {
 92         HandleError("导出公钥信息失败");
 93     }
 94     
 95     pbKeyBlob = (BYTE*)malloc(dwBlobLen);
 96 
 97     if(!(CryptExportKey( hKey, NULL, PUBLICKEYBLOB,0, pbKeyBlob, &dwBlobLen))) 
 98     {
 99         HandleError("导出公钥信息失败2;");
100     }
101 
102 
103     printf("公钥BLOB信息如下:\n");
104     for(int i=0;i<dwBlobLen;i++)
105     {
106         if (i % 10 == 0)
107         {
108             printf("\n");
109         }
110         printf("%02X ", pbKeyBlob[i]);
111     }
112     printf("\n");
113 
114     BLOBHEADER blobHeader;
115     RSAPUBKEY    rsaPubkey;
116     PBYTE p = NULL;
117     p = pbKeyBlob;
118     //分析得到的BLOB
119     memcpy(&blobHeader.bType, p, 1);
120     p += 1;
121     memcpy(&blobHeader.bVersion, p, 1);
122     p += 1;
123     memcpy(&blobHeader.reserved, p, 2);
124     p += 2;
125     memcpy(&blobHeader.aiKeyAlg, p, 4);
126     p += 4;
127 
128     memcpy(&rsaPubkey.magic, p, 4);
129     p += 4;
130     memcpy(&rsaPubkey.bitlen, p, 4);
131     p += 4;
132     memcpy(&rsaPubkey.pubexp, p, 4);
133     p += 4;
134     PBYTE    reaMod = (PBYTE)LocalAlloc(LPTR, rsaPubkey.bitlen/8);
135     memcpy(reaMod, p, rsaPubkey.bitlen/8);
136 
137     //需要转换一下
138     BYTE bTemp;
139     for (int i=0;i< rsaPubkey.bitlen/8/2; i++)
140     {
141         bTemp = reaMod[i];
142         reaMod[i] = reaMod[rsaPubkey.bitlen/8 - i - 1];
143         reaMod[rsaPubkey.bitlen/8- i - 1] = bTemp;
144     }
145 
146     printf("BLOBHEADER.bType=[%02x]\n", blobHeader.bType);
147     printf("BLOBHEADER.bVersion=[%02x]\n", blobHeader.bVersion);
148     printf("BLOBHEADER.reserved=[%d]\n", blobHeader.reserved);
149     printf("BLOBHEADER.aiKeyAlg=[%d]\n\n", blobHeader.aiKeyAlg);
150     printf("rsaPubkey.magic=[");
151     char* q = (char *)&rsaPubkey.magic;
152     for (int i = 0;i<4;i++)
153     {
154         printf("%c",*q++);
155     }
156     
157     printf("]\nrsaPubkey.bitlen=[%d]\n", rsaPubkey.bitlen);
158     printf("rsaPubkey.pubexp=[%d]\n", rsaPubkey.pubexp);
159     printf("RSA MOD:\n");
160     for(int i=0;i<rsaPubkey.bitlen/8;i++)
161     {
162         if (i % 10 == 0)
163         {
164             printf("\n");
165         }
166         printf("%02X ", reaMod[i]);
167     }
168     printf("\n");
169 
170     //释放
171     LocalFree(reaMod);
172 
173 
174     free(pbKeyBlob);
175     if (hKey)
176     {
177         CryptDestroyKey(hKey);
178     }
179 
180     if(hCryptProv)
181     {
182         CryptReleaseContext(hCryptProv, 0);
183     }
184 
185     if(CryptAcquireContext(
186         &hCryptProv, 
187         NULL, 
188         NULL, 
189         PROV_RSA_FULL,
190         CRYPT_DELETEKEYSET))
191     {
192         printf("删除容器成功\n");
193     }
194     else
195     {
196         HandleError("删除容器失败");
197     }
198     system("pause");
199     return 0;
200 }

结果如下:



 

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

来自为知笔记(Wiz)



posted on 2013-09-25 09:25  dspeeding  阅读(5200)  评论(2编辑  收藏  举报