2013-05-20 43 views
11

我試圖找到有關如何(如果可能)枚舉強名稱CSP(加密服務提供程序)中的所有容器名稱的一些信息。枚舉強名稱的容器名稱CSP

本質上,當您輸入sn.exe -i key.snk MyContainerName時,公鑰和私鑰對存儲到所謂的「容器」中。後來,你的代碼中,你可以在AssemblyKeyNameAttribute指定容器名稱,例如:

[assembly: AssemblyKeyName("MyContainerName")] 

這將導致組件在編譯時簽署。

我想知道是否有可能枚舉所有的容器名稱。我正在編寫一個plugin for ReSharper,它爲InternalsVisibleTo屬性提供代碼完成。我還想爲AssemblyKeyName屬性提供代碼完成,我將使用已知的容器名稱預先填充列表。

該信息是否可訪問?

編輯:從IT安全StackExchange上this question評論,有一個小鏈接UTIL稱爲KeyPal。與LM運行此工具將轉儲本地計算機密鑰存儲:

--------- KeyPal: MACHINE store: 3 keycontainers --------- 
[0] VS_KEY_F726FDF898BC4CB8 
    Signature 1024 
[1] IIS Express Development Certificate Container 
    Exchange 1024 
    CertE: CN=localhost 
[2] MyContainerName 
    Signature 1024 
------------------------------------------------- 

我在哪裏可以看到,無論[0]和[2]是有效的容器名稱與AssemblyKeyName使用。但是,有一個 - 「IIS Express ...」,它不是一個有效的容器。我如何區分它們?

+1

不解決實際的問題,但萬一它有幫助......你知道通常通過屬性指定已被棄用(因爲你會很難看到它在V1.1代碼庫以外)贊成VS管理安裝到商店,並通過它們到CSC任務? (http://stackoverflow.com/a/16464894/11635) –

+0

@RubenBartelink有趣,謝謝。我承擔了很多,因爲幾乎沒有關於這些事情的最新信息。我只是出於興趣,因爲我的ReSharper插件的用戶報告了一個錯誤,在他的情況下,他們仍然在使用這些屬性。所以我想知道「協助」它們有多困難。但是,它看起來像任何人幾乎不再使用它。 –

回答

4

下面是示例代碼,有點與那個keypal工具做同樣的事情。它枚舉所有容器(用於本地機器),然後從那裏獲得可以變爲StrongNameKeyPairs的容器。通常情況下,強名稱密鑰具有160字節長度的公鑰(SHA1):

foreach (var kc in KeyUtilities.EnumerateKeyContainers("Microsoft Strong Cryptographic Provider")) 
{ 
    CspParameters cspParams = new CspParameters(); 
    cspParams.KeyContainerName = kc; 
    cspParams.Flags = CspProviderFlags.UseMachineKeyStore; 
    using (RSACryptoServiceProvider prov = new RSACryptoServiceProvider(cspParams)) 
    { 
     if (prov.CspKeyContainerInfo.Exportable) 
     { 
      var blob = prov.ExportCspBlob(true); 
      StrongNameKeyPair kp = new StrongNameKeyPair(prov.ExportCspBlob(false)); 
      Console.WriteLine(kc + " pk length:" + kp.PublicKey.Length); 
     } 
    } 
    Console.WriteLine(); 
} 

...

public static class KeyUtilities 
{ 
    public static IList<string> EnumerateKeyContainers(string provider) 
    { 
     ProvHandle prov; 
     if (!CryptAcquireContext(out prov, null, provider, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT)) 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 

     List<string> list = new List<string>(); 
     IntPtr data = IntPtr.Zero; 
     try 
     { 
      int flag = CRYPT_FIRST; 
      int len = 0; 
      if (!CryptGetProvParam(prov, PP_ENUMCONTAINERS, IntPtr.Zero, ref len, flag)) 
      { 
       if (Marshal.GetLastWin32Error() != ERROR_MORE_DATA) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 
      } 

      data = Marshal.AllocHGlobal(len); 
      do 
      { 
       if (!CryptGetProvParam(prov, PP_ENUMCONTAINERS, data, ref len, flag)) 
       { 
        if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS) 
         break; 

        throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 

       list.Add(Marshal.PtrToStringAnsi(data)); 
       flag = CRYPT_NEXT; 
      } 
      while (true); 
     } 
     finally 
     { 
      if (data != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(data); 
      } 

      prov.Dispose(); 
     } 
     return list; 
    } 

    private sealed class ProvHandle : SafeHandleZeroOrMinusOneIsInvalid 
    { 
     public ProvHandle() 
      : base(true) 
     { 
     } 

     protected override bool ReleaseHandle() 
     { 
      return CryptReleaseContext(handle, 0); 
     } 

     [DllImport("advapi32.dll")] 
     private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags); 

    } 

    const int PP_ENUMCONTAINERS = 2; 
    const int PROV_RSA_FULL = 1; 
    const int ERROR_MORE_DATA = 234; 
    const int ERROR_NO_MORE_ITEMS = 259; 
    const int CRYPT_FIRST = 1; 
    const int CRYPT_NEXT = 2; 
    const int CRYPT_MACHINE_KEYSET = 0x20; 
    const int CRYPT_VERIFYCONTEXT = unchecked((int)0xF0000000); 

    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
    private static extern bool CryptAcquireContext(out ProvHandle phProv, string pszContainer, string pszProvider, int dwProvType, int dwFlags); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool CryptGetProvParam(ProvHandle hProv, int dwParam, IntPtr pbData, ref int pdwDataLen, int dwFlags); 
} 

以下命名空間被引用:

using Microsoft.Win32.SafeHandles; 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Reflection; 
using System.Runtime.InteropServices; 
using System.Security.Cryptography; 
+1

這很好,謝謝!我最近修改了我的小插件,使用Roslyn的一些utils直接讀取snk文件。我可能會將一些代碼也納入其中(當然,要有適當的歸屬)! –