2013-05-20 130 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文件。我可能会将一些代码也纳入其中(当然,要有适当的归属)! –