keyblob解析 文章参考:https://www.cnblogs.com/dspeeding/p/3338082.html
通过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的数据排列和其他不用,因此需要将获取到的后边的模作一次颠倒处理。既将最后一个字节和第一个字节对调,依次类推。
参考信息:http://blog.163.com/luckydogs_168/blog/static/53984651200751154259718/
通过函数
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 即可。