CNG 關於 Key 相關的操作
章節目錄
- 簡介
- 建立 Key
- 檢視系統中的 Key
- 從 Windows Store 匯出 key
- 匯入 Key 到 Windows Store
<b>作者能力有限, 如果您在閱讀過程中發現任何錯誤, 還請您務必聯絡本人,指出錯誤, 避免後來讀者再學習錯誤的知識.謝謝!</b>
簡介
CNG 全稱 Cryptography API: Next Generation (CNG). 是 windows 平臺下一代加密相關 API 的總稱, 它是 Crypto API 的替代. 比較與 CryptoAPI, 它的功能更加強大.
本文將以例項的形式給出使用 CNG 操作 Key 的方法以及相關的 API.
請注意, 文章中我們使用 RSA key 作為示例, DSA 和 ECC key 也是同樣適用的.
建立 Key
CNG 當前版本支援了 RSA, DSA, ECC 演算法, 這裡我們來建立一個 key 長度 為 2048 bits 的 RSA key. 注意, 當你嘗試建立 2048 的 DSA key 時, 請確保你的系統是否支援, 本人的 Win7 是不支援的, 而 Win10 是支援的(親測).
這裡我們依次使用了以下API:
<code>NCryptOpenStorageProvider</code> 該方法用於載入和初始化一個已經存在 CNG Key Storage Provider. 當前 Windows 系統中內建了兩個 KSP:MS_KEY_STORAGE_PROVIDER,MS_SMART_CARD_KEY_STORAGE_PROVIDER. 我們例子中使用 MS_KEY_STORAGE_PROVIDER.
<code>NCryptCreatePersistedKey</code> 該方法用於常見一個特定演算法的 Key, 並把它存在指定的 KSP 中. 注意, 這個方法建立的 key 會以檔案形式儲存在 Windows 系統中.
<code>NCryptSetProperty</code> 該方法用於設定 key 的屬性. 例子中我們將使用它設定 key 的長度為 2048 bits.
<code>NCryptFinalizeKey</code> 該方法用於通知 Windows 我們建立 key 的操作已經完成, 呼叫該方法後, 我們建立的 Key 將可以被用於簽名加密等操作, 否則不能.
<code>NCryptFreeObject</code> 該方法用於釋放前面操作中我們所使用到系統 Handle.
int Create2048RSAKey() { int errCode = 0; NCRYPT_PROV_HANDLE prov = NULL; NCRYPT_KEY_HANDLEkey = NULL; DWORD keyLength = 2048; DWORD policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG; if (errCode = NCryptOpenStorageProvider(&prov, MS_KEY_STORAGE_PROVIDER, 0)) goto done; if (errCode = NCryptCreatePersistedKey(prov, &key, NCRYPT_RSA_ALGORITHM, L"TestRSAKey", 0, NCRYPT_OVERWRITE_KEY_FLAG)) goto done; if (errCode = NCryptSetProperty(key, NCRYPT_LENGTH_PROPERTY, (PBYTE)(&keyLength), sizeof(keyLength), NCRYPT_PERSIST_FLAG)) goto done; if (errCode = NCryptSetProperty(key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)(&policy), sizeof(policy), NCRYPT_PERSIST_FLAG)) goto done; if (errCode = NCryptFinalizeKey(key, 0)) goto done; done: if (prov) NCryptFreeObject(prov); if (key) NCryptFreeObject(key); return errCode; }
當你在你的 Windows 電腦上執行了該方法之後, 你的系統中就會存有我們剛剛建立的 Key 了.
下一節, 我們將使用 CNG API 來檢視我們建立的 Key 的資訊.
檢視系統中的 Key
這裡我們將會使用到的 CNG API 有:
<code>NCryptEnumKeys</code> 該方法用於遍歷儲存在當前 KSP 中的所有 Key.
這裡我們解釋一下它的幾個引數:
<code>NCryptKeyName **ppKeyName</code> 該引數作為方法的返回值, 其中儲存了當前 Key 的名稱, key 演算法等重要資訊. name 尤為重要, 比如我們例子中會使用 name 來獲取該 key 的 handle, 依次來使用該 key 做更多的操作.
<code>PVOID *ppEnumState</code> 該引數也作為方法的返回值. 但是它的值對於呼叫者來說是沒有任何意義的. 它儲存了遍歷 key 的中間資訊, 是我們下一次呼叫 NCryptEnumKeys 方法的入參. 如果將該引數設定為 NULL, 遍歷總是會返回當前 KSP 的第一個 Key 的資訊.
<code>return value</code> 當該方法返回值為 NTE_NO_MORE_ITEMS, 代表已經遍歷完了當前 KSP 中所有的 Key.
<code>NCryptOpenKey</code> 該方法用於獲取執行 KSP 中指定名稱的 Key Handle.
<code>NCryptGetProperty</code> 該方法用於獲取 Key 的屬性.
int ListKeys() { int errCode = 0; NCRYPT_PROV_HANDLE prov= NULL; NCRYPT_KEY_HANDLEkey= NULL; NCryptKeyName*pKeyName= NULL; PVOIDpEnumState = NULL; if (errCode = NCryptOpenStorageProvider(&prov, MS_KEY_STORAGE_PROVIDER, 0)) goto done; do { errCode = NCryptEnumKeys(prov, 0, &pKeyName, &pEnumState, 0); if (errCode == NTE_NO_MORE_ITEMS) break; // all the keys are enumerated if (!pKeyName) break; // should not happen LPCWSTR name = pKeyName->pszName; LPCWSTR alg= pKeyName->pszAlgid; // get key length property DWORD keyLength = 0,outLen = 0; if (errCode = NCryptOpenKey(prov, &key, name, 0, 0)) goto done; if (errCode = NCryptGetProperty(key, NCRYPT_LENGTH_PROPERTY, (PBYTE) (&keyLength), sizeof(keyLength), &outLen, 0)) goto done; wprintf(L"KeyName: %s, KeyAlgorithm: %s, KeyLength: %d", name, alg, keyLength); } while (!errCode); done: if (prov) NCryptFreeObject(prov); if (key) NCryptFreeObject(key); return errCode; }
如果你在你的電腦上運行了第一小節的函式, 此時執行 ListKeys 函式, 你的命令列中肯定會包含這樣的輸出:
<code>KeyName: TestRSAKey, KeyAlgorithm: RSA, KeyLength: 2048</code>
從 Windows Store 匯出 key
通過上述兩個小節的描述, 我們已經成功的在 Windows 系統中建立了 Key, 並且可以檢視 Key 的資訊, 獲取 Key handle. 使用 Key Handle 我們可以完成很多的工作.但是, 很多時候我們需要把 Key 到處到檔案, 和同伴分享.
這一小節, 我們就來嘗試把 Key 匯出來.
<code>NCryptExportKey</code> 該方法用於將系統中的 Key 匯出到 memory blob 中.
它有一個非常重要的引數:
<code>LPCWSTR pszBlobType</code> 用來控制匯出的 memory blob 的格式. 例子中我們使用 NCRYPT_PKCS8_PRIVATE_KEY_BLOB. <b>相信我,這個格式將會是最方便我們做進一步處理的格式. 其他的格式, 比如 BCRYPT_DSA_PUBLIC_BLOB, LEGACY_DSA_PRIVATE_BLOB 等格式看起來很友善, 但是並不總是像你想象的那樣工作. 他們的格式並不總是和 CryptExportKey 匯出時的一致,當 Key 的長度變為 2048 或者更大時, 而且很難找到相應的文件來描述此時它的格式到底是什麼樣的. 而 PKCS8 工作的非常好.</b>
int ExportKey() { int errCode = 0; NCRYPT_PROV_HANDLE prov = NULL; NCRYPT_KEY_HANDLEkey = NULL; BYTE blob[0x1000] = {0}; DWORD blobLen = 0x1000; if (errCode = NCryptOpenStorageProvider(&prov, MS_KEY_STORAGE_PROVIDER, 0)) goto done; if (errCode = NCryptOpenKey(prov, &key, L"TestRSAKey", 0, 0)) goto done; if (errCode = NCryptExportKey(key, NULL, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, blob, blobLen, &blobLen, 0)) goto done; done: if (prov) NCryptFreeObject(prov); if (key) NCryptFreeObject(key); return errCode; }
當你執行該函式與某個 Key Handle 時, 如果你得到錯誤碼 0x80090029, 請確認你的 Key 的 NCRYPT_EXPORT_POLICY_PROPERTY 屬性的值包含 NCRYPT_ALLOW_EXPORT_FLAG 和 NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG.(這就是為什麼, 第一節中的程式碼中, 我們明確的將建立的 Key 屬性設定為該值的原因了.)
如果你的 Key 不包含 NCRYPT_ALLOW_EXPORT_FLAG 和 NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG, 那意味著你的 Key 無法匯出, 你只能使用該 Key 的 Handle 做其他的工作.
如果你的 key 的屬性僅僅包含 NCRYPT_ALLOW_EXPORT_FLAG, 那意味著你不能將你的證書匯出為明文. 此時,你需要將 NCryptExportKey 的第二個引數設定為一個非 NULL 的值. 個人覺得很麻煩, 如果您有相應的 code, 謝謝你分享給我!
一點兒個人經驗, 如果你的 Key 是使用者通過 CryptAPI 或者手工方式匯入的 PFX, 在 Win10 平臺上, 你的 Key 很可能只有 NCRYPT_ALLOW_EXPORT_FLAG 標記, 而不支援匯出為明文. 如果我錯了, 請告訴我!
匯入 Key 到 Windows Store
很多時候, 我們不總是直接使用系統建立 Key, 而是使用我們現有的 Key. 那麼, 當你想讓你的 Key 和 CNG API 一起工作的時候, 匯入你的 Key 到系統中將是一個必須的工作. 注意, 我們這裡給出的例子會將 Key 儲存到系統中. 如果你僅僅想要獲取 Key Handle 而不將 Key 匯入到 KSP 中, 只需要不設定 Key name 就行了.
這裡我們將會將 PKCS8 格式的 Key 匯入到系統中, 如果你的 Key 是另外的格式, 你有兩個選擇: 將他轉換成 PKCS8 格式然後使用下面方法匯入 或者 尋找其他可用的方法.
這裡有兩點值得一提:
<code>NCryptBufferDesc *pParameterList</code> 該引數可以用來設定 Key 的引數資訊. 這裡我們使用該引數來指定將要匯入到系統中的 Key 的名稱. 如果專門設定 Key 名稱, 該 Key 將會是一個臨時的 Key, 就不會被儲存在 Window 中.
<code>DWORD dwFlags</code> 如果需要在匯入 Key 之後設定 Key 的屬性, 那你需要在這個引數中包含 NCRYPT_DO_NOT_FINALIZE_FLAG 標記. 例子中我們在匯入 Key 之後, 需要設定 Key 的 NCRYPT_EXPORT_POLICY_PROPERTY 屬性, 因此我們使用了 NCRYPT_DO_NOT_FINALIZE_FLAG 標記. 如果你未使用 NCRYPT_DO_NOT_FINALIZE_FLAG, 就不要額外的呼叫 NCryptFinalizeKey 方法, 否則, 請記得呼叫 NCryptFinalizeKey 方法.
int ImportKey() { BYTE blob[] = { 0x30,0x82,0x04,0xbd,0x02,0x01,0x00,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x04,0xa7,0x30,0x82,0x04,0xa3,0x02,0x01, 0x00,0x02,0x82,0x01,0x01,0x00,0xad,0xaa,0x8c,0x75,0x51,0x15,0x23,0x55,0xc7,0xec,0x7f,0x0b,0x85,0xf9,0x4b,0x18,0x10,0x60,0xdb,0x3d,0xc2,0xd2,0xcf,0xa6,0x8d,0x09, 0x8a,0xc9,0x7a,0x0e,0x80,0xb8,0x60,0x5a,0x20,0xe7,0xcb,0x52,0x33,0xc0,0xa3,0xc8,0x33,0x05,0xb0,0x45,0x34,0x49,0x59,0x0d,0xff,0xed,0xe5,0xe9,0x42,0xc4,0x05,0x82, 0x1a,0x92,0x67,0x24,0xea,0xc6,0x2a,0x07,0x67,0x07,0x65,0xa9,0xb8,0xe8,0x25,0xa2,0x16,0xe5,0x47,0xf2,0x79,0x98,0xcd,0x7c,0xce,0xbc,0x28,0x95,0x5f,0x9a,0xcd,0x70, 0x30,0xbb,0x7c,0xc9,0xc1,0x55,0xac,0x06,0x42,0xa8,0x86,0x78,0x47,0x69,0xa0,0xfb,0x5e,0x10,0x01,0xe4,0x3a,0xbc,0x09,0xb3,0xfd,0x3f,0x3d,0x3c,0x47,0xe7,0xd2,0x8f, 0xaf,0x2f,0x04,0x38,0x74,0xdc,0x3b,0x74,0x31,0xfb,0x55,0x39,0x94,0xeb,0xe3,0x7c,0x17,0x8d,0x51,0x50,0xa2,0x25,0x87,0x4b,0xfb,0xd2,0x3c,0xb6,0x70,0x45,0xd1,0x55, 0xb0,0x8e,0x9d,0x24,0xcb,0xd7,0xa0,0xc2,0xdd,0xfa,0x7b,0xa4,0x3f,0xd3,0xbe,0x7e,0x09,0x87,0x46,0x37,0xda,0x29,0x7c,0x95,0x85,0x0d,0x6d,0xfc,0xbf,0xbf,0x41,0xbe, 0x79,0x2c,0x83,0x87,0x1b,0x6f,0x24,0x8a,0x60,0x85,0x36,0xf6,0xcb,0x63,0x0c,0x66,0x16,0x0b,0x97,0x4a,0xdc,0xdb,0x91,0x0d,0xf9,0x1d,0x7e,0xae,0xbc,0xd9,0x77,0x39, 0x38,0x3e,0x7b,0x04,0x92,0x71,0x94,0x18,0x66,0xc8,0x77,0x5e,0x5c,0x42,0x16,0xc7,0x18,0x61,0x5a,0xdd,0x4f,0xaf,0x77,0x9a,0x14,0xba,0x39,0x98,0x22,0x73,0x49,0xfa, 0x73,0x2b,0x6d,0x0c,0x3b,0x27,0x02,0x03,0x01,0x00,0x01,0x02,0x82,0x01,0x00,0x2b,0xd2,0xef,0xe2,0xe2,0xf5,0x2c,0x97,0x86,0xfd,0xdd,0x09,0x71,0x63,0x79,0x59,0xb7, 0x38,0x59,0xda,0xfa,0x00,0xec,0xb9,0xa0,0xb9,0x99,0xb6,0x42,0x00,0xca,0xe6,0xbc,0x19,0xc2,0x57,0xfb,0xec,0xe0,0x76,0x6a,0x5e,0x28,0xd1,0xf4,0xab,0x62,0x08,0x68, 0x5a,0xaa,0x0c,0xc4,0x89,0xda,0x79,0x50,0xd2,0x86,0x16,0x0f,0xc5,0x37,0x21,0x8e,0x95,0x93,0xa0,0x40,0x3d,0x56,0x15,0xee,0xf9,0x3a,0x41,0xdd,0xa8,0x08,0x9b,0x50, 0xaf,0x80,0x13,0xe7,0x41,0xda,0x80,0x5b,0xfb,0x45,0xb0,0xea,0x4a,0x97,0x69,0x21,0x21,0xeb,0x4c,0x4f,0xb2,0xa6,0x82,0xb7,0x46,0xf7,0x73,0x9e,0xa6,0x93,0x53,0xc4, 0x37,0x11,0x5f,0x15,0xfa,0xd2,0x42,0x63,0xd6,0x32,0x64,0xf0,0xf1,0xb6,0x3b,0x3a,0xb2,0xc8,0x25,0xc3,0x80,0xa1,0xa3,0xe7,0xb4,0x35,0xab,0x13,0xa9,0x3a,0x40,0xd1, 0x16,0xf6,0x63,0x62,0x62,0xeb,0x7c,0x58,0x4f,0x56,0x94,0xde,0x28,0x8a,0x48,0xc6,0xf0,0x3b,0x88,0x01,0xd3,0x8b,0xc6,0x0b,0x17,0x01,0x10,0x28,0x00,0x9c,0xd0,0x80, 0xc2,0xe8,0x00,0xdc,0x6b,0x37,0x39,0x1c,0xef,0x78,0x34,0x1d,0x49,0x12,0xd4,0x66,0x88,0x20,0x87,0xe2,0x1e,0x2b,0x05,0x26,0x8a,0xa7,0xd0,0x3d,0xe7,0xd0,0x47,0xed, 0xbe,0x1f,0xec,0xd6,0xa1,0xd3,0xe2,0x0e,0xb5,0xe5,0x3c,0xc2,0x83,0x69,0x77,0x36,0x9d,0x80,0x2b,0xe9,0xe1,0x14,0xe0,0xd5,0x27,0x62,0x35,0xc1,0x40,0xc6,0xf2,0x6e, 0xdb,0xc1,0x58,0xb8,0x9c,0xbc,0x83,0x36,0x81,0xfb,0x70,0xae,0x0c,0x5c,0xc1,0x02,0x81,0x81,0x00,0xd2,0x5f,0x19,0x94,0x11,0xb8,0xdc,0x77,0x2e,0x93,0x15,0x50,0x09, 0xa9,0x20,0xf0,0x1b,0xd1,0x3d,0x4a,0x1d,0x2c,0xb6,0x98,0xec,0x11,0xf1,0xe8,0xa0,0x85,0x4c,0xf8,0x14,0x27,0x80,0x26,0xff,0x78,0xa1,0x17,0x52,0xa3,0xbf,0xf6,0xc6, 0x86,0xab,0xca,0x5f,0x1e,0x5e,0x8f,0x78,0x5e,0x71,0x7d,0x2c,0x57,0xbe,0xda,0x80,0xa2,0x8b,0x6a,0x88,0xab,0xcd,0x78,0xc3,0x67,0xf6,0xb5,0x60,0x96,0x5c,0x24,0xac, 0x8c,0x4b,0x77,0x36,0xe2,0x97,0x16,0x87,0x6a,0x03,0xa7,0x36,0x4a,0xdf,0x5d,0xc3,0x6f,0x1f,0x60,0xfd,0x40,0x60,0x0e,0xca,0xb9,0x25,0x37,0xfa,0x50,0xc3,0x82,0x2f, 0x3a,0xeb,0x1b,0xd5,0xe0,0x6f,0x13,0x17,0x7d,0xa4,0xd2,0x97,0xe7,0xd7,0xbb,0x32,0x84,0x1e,0x77,0x02,0x81,0x81,0x00,0xd3,0x55,0x62,0x53,0x35,0x29,0xa5,0x68,0x65, 0x28,0x74,0x16,0x30,0x66,0x3e,0x95,0x8e,0xc6,0xb1,0xdd,0x37,0xae,0x69,0xe7,0xc8,0x62,0x81,0x11,0x57,0x57,0x92,0x2b,0xd8,0x21,0x98,0xf4,0x3f,0xe6,0x6e,0xd1,0x5d, 0xff,0x6f,0x90,0x6b,0x9e,0x68,0x47,0x50,0x6e,0xdf,0x5a,0x12,0x49,0x04,0xe9,0x42,0x7f,0xe1,0x3e,0x05,0x0a,0xa3,0xee,0xca,0xeb,0x40,0x4b,0x89,0x2a,0xa1,0x3c,0x2e, 0xa5,0xad,0xa8,0xc9,0x5e,0xa7,0x70,0x55,0x3f,0x04,0x1d,0x17,0xcb,0xca,0x21,0xf5,0xc3,0x68,0x68,0xb9,0x50,0x98,0xd3,0x3a,0x2c,0x29,0x21,0x3b,0x42,0x12,0x92,0x34, 0xda,0xc5,0xbb,0x0c,0xb2,0xb4,0x86,0x6a,0x4e,0x3f,0x43,0x99,0xc4,0xb7,0x85,0x97,0x36,0x75,0x61,0x28,0xd6,0x84,0xd1,0x02,0x81,0x80,0x36,0x9b,0xa1,0x14,0x22,0x95, 0x8e,0x05,0x11,0xfd,0xf4,0x26,0x56,0x9b,0xa4,0x85,0x2f,0x73,0x5d,0x29,0x83,0xf1,0x3b,0x64,0xee,0xc2,0xa9,0xbc,0xed,0x0e,0x2d,0x30,0xa8,0x6a,0xa8,0x85,0x77,0x03, 0x65,0x2d,0x9c,0xb2,0x0c,0xfe,0x8e,0x02,0x1f,0x4d,0xe4,0xeb,0x09,0x38,0xcc,0xd2,0x17,0x3b,0x9a,0xeb,0x1c,0x0b,0xb4,0x20,0x7d,0x78,0x26,0x0a,0x12,0xc8,0x2a,0x51, 0x2e,0x65,0x5e,0xb1,0x29,0x32,0x0b,0xe8,0x4f,0x1e,0x9f,0x0c,0xaa,0x93,0x9a,0x8b,0x16,0x6f,0xad,0x54,0x3a,0x2f,0x28,0xb0,0x0b,0xc1,0x2d,0x7c,0x2c,0x73,0x2a,0x84, 0x6c,0xf8,0xde,0xed,0x60,0x12,0xc7,0x17,0xd0,0x37,0xe5,0x88,0xe0,0xcc,0x5f,0xe8,0xa9,0x84,0x51,0x12,0x49,0x99,0xba,0x3f,0x39,0x79,0x02,0x81,0x80,0x74,0x65,0x92, 0xc2,0x41,0x85,0xae,0x94,0xd1,0x22,0x76,0xcd,0xc1,0xda,0x8e,0x9d,0xd1,0x05,0x9e,0xf1,0x38,0xb9,0xd7,0x9a,0xd1,0xc3,0x6f,0x53,0x1d,0xc8,0x1d,0xba,0x08,0x50,0x78, 0xee,0x0e,0x43,0xdc,0xc5,0x74,0x00,0x3c,0x72,0x4e,0xd3,0xf0,0x9b,0x56,0xb1,0xba,0x52,0xe1,0xbf,0x55,0xf5,0x23,0xab,0x4b,0x63,0xdd,0x62,0xfe,0xe7,0x86,0xdc,0x0b, 0x8d,0x8e,0xfe,0xeb,0xcf,0x39,0xe2,0x06,0xc3,0xf0,0x25,0x32,0x13,0xac,0xe0,0x08,0x63,0xfd,0xb7,0x40,0x9d,0x73,0xbf,0x2c,0xc2,0x81,0x4e,0xe2,0xdd,0x74,0x2c,0xde, 0x7a,0x6f,0x28,0xf5,0x11,0x92,0x0a,0xec,0xdd,0x19,0x21,0x54,0x4c,0xb4,0x40,0x64,0x97,0xd7,0x19,0x81,0xfb,0x12,0x4d,0xec,0x58,0x97,0x25,0x90,0x01,0x02,0x81,0x81, 0x00,0x9d,0xf3,0x78,0x3e,0x39,0xb6,0x45,0x97,0x2d,0xb2,0xf2,0xdb,0xe3,0xa8,0xe9,0x8e,0x58,0xd7,0x6b,0xfb,0x11,0x25,0x77,0x6b,0xd5,0xd6,0x61,0x39,0xbb,0x04,0x15, 0xc2,0x7d,0xf9,0xc7,0xf1,0x1a,0xce,0xe5,0x40,0x84,0x26,0x83,0x13,0xb4,0x41,0x49,0xa2,0x42,0x71,0x3c,0xed,0x72,0x17,0xa9,0x2a,0x85,0x25,0xea,0x5b,0xf3,0x6e,0xd6, 0x5b,0x49,0xc8,0xda,0xe4,0xaa,0xa4,0xa5,0x96,0x31,0xaa,0x7e,0x10,0xd7,0x8a,0xf8,0x16,0xe0,0xe0,0x21,0x64,0x22,0xfb,0x1c,0x74,0x27,0xbe,0xf7,0x0f,0x0c,0x94,0x4b, 0x47,0xf4,0xfe,0x58,0xe1,0x72,0xb1,0x08,0xac,0x93,0xb5,0x06,0x29,0x78,0xb8,0xb3,0xf8,0xd4,0x2f,0x4e,0x43,0x3a,0x0c,0x14,0x8b,0x00,0xd2,0xd5,0x21,0x93,0x8c,0x5d, 0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; DWORD blobLen = 0x4c1; int errCode = 0; NCRYPT_PROV_HANDLE prov = NULL; NCRYPT_KEY_HANDLEkey = NULL; DWORD policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG; LPCWSTR name = L"ImportedKey"; BCryptBuffer cb[1]; cb[0].BufferType = NCRYPTBUFFER_PKCS_KEY_NAME; cb[0].pvBuffer = (void*)name; cb[0].cbBuffer = lstrlenW(name) * 2 + 2; NCryptBufferDesc desc; desc.ulVersion = 0; desc.pBuffers = cb; desc.cBuffers = 1; if (errCode = NCryptOpenStorageProvider(&prov, MS_KEY_STORAGE_PROVIDER, 0)) goto done; if (errCode = NCryptImportKey(prov, NULL, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, &desc, &key, blob, blobLen, NCRYPT_DO_NOT_FINALIZE_FLAG)) goto done; if (errCode = NCryptSetProperty(key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)(&policy), sizeof(policy), NCRYPT_PERSIST_FLAG)) goto done; if (errCode = NCryptFinalizeKey(key, 0)) goto done; done: if (prov) NCryptFreeObject(prov); if (key) NCryptFreeObject(key); return errCode; }
匯入完成之後, 可以使用 ListKeys 檢查你的匯入是否成功了.
END!