CSP學習之導出密鑰BLOB 解析

經過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 便可。ui

相關文章
相關標籤/搜索