Calculating VS_KEY container name

我的梦境 提交于 2019-12-03 08:58:18

We stepped upon this question while trying to automatically register the key on an integration server. Having to run Visual Studio or MSBuild to extract the VS_KEY was unacceptable. Then by investigating the logs of MSBuild with the maximal verbosity, I came upon the following.

This key is generated via Microsoft.Build.Tasks.v4.0.dll (present in GAC). There's a class called "ResolveKeySource" within this DLL. By looking at the code with ILSpy or Reflector, you will see an Execute method calling ResolveAssemblyKey. This method is the heart of the VS_KEY_xxxxxx mystery.

The VS_KEY_xxxxx value is generated by hashing the content of the key with Environment.UserDomainName and Environment.UserName.

First solution: you create an ResolveKeySource instance and call the appropriate method. As you don't provide a password and other information, it will raise an exception whose message contains the mighty VS_KEY thing.

var key = new ResolveKeySource();
key.KeyFile = path_to_key_file;
try {
   key.Execute();
} catch (Exception e) {
  var match = Regex.Match(e.Message, "VS_KEY_[A-F0-9]+");
   if (match.Success) {
       return match.Value;
   }
}

Second solution: grab the code that is generating this hashcode and use it to directly get the value without exceptions. This is more or less an extract from the DLL.

    public static string GetLocalUserKeyContainerByGeneration(string keyFile) {

        string localName = Environment.UserDomainName + "\\" + Environment.UserName;

        FileStream keyFileStream = null;

        try {
            keyFileStream = File.OpenRead(keyFile);

            int num = (int)keyFileStream.Length;
            byte[] array = new byte[num];

            keyFileStream.Read(array, 0, num);

            ulong hash1 = HashFromBlob(array);
            byte[] bytes = Encoding.Unicode.GetBytes(localName.ToLower(CultureInfo.InvariantCulture));

            return "VS_KEY_" + (hash1 ^ HashFromBlob(bytes)).ToString("X016", CultureInfo.InvariantCulture);
        }
        finally {
            if (keyFileStream != null) {
                keyFileStream.Close();
            }
        }
    }

    private static ulong HashFromBlob(byte[] data) {

        uint num = 17339221u;
        uint num2 = 19619429u;
        uint num3 = 10803503u;

        for (int i = 0; i < data.Length; i++) {
            byte b = data[i];
            uint num4 = (uint)b ^ num3;
            num3 *= 10803503u;
            num += (num4 ^ num2) * 15816943u + 17368321u;
            num2 ^= ((num4 + num) * 14984549u ^ 11746499u);
        }

        ulong num5 = (ulong)num;
        num5 <<= 32;

        return num5 | (ulong)num2;
    }

This answer goes along with @kdrapel's, but I couldn't put it in a comment. I had to hack it for a bit to figure out how to actually use it in an inline task, so I figured I'd share.

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Test" ToolsVersion="4.0" >

  <Target Name="Test">
    <CalcKey InputKey="c:\path\to\your\key.pfx">
      <Output PropertyName="VSKEY" TaskParameter="VSKEY"/>
    </CalcKey>
    <Message Text="VSKey = $(VSKEY)"/>
  </Target>

  <UsingTask
      TaskName="CalcKey"
      TaskFactory="CodeTaskFactory"
      AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
    <ParameterGroup>
      <InputKey ParameterType="System.String" Required="true"/>
      <VSKEY ParameterType="System.String" Output="true"/>
    </ParameterGroup>
    <Task>
      <Reference Include="$(MSBuildBinPath)\Microsoft.Build.Framework.dll"/>
      <Reference Include="$(MSBuildBinPath)\Microsoft.Build.Utilities.v12.0.dll"/>
      <Reference Include="$(MSBuildBinPath)\Microsoft.Build.Tasks.v12.0.dll"/>
      <Using Namespace="System.Text.RegularExpressions"/>
      <Using Namespace="Microsoft.Build.Tasks"/>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            var key = new ResolveKeySource();
            key.KeyFile = InputKey;
            try
            {
                key.Execute();
            }
            catch (Exception e)
            {
                var match = Regex.Match(e.Message, "VS_KEY_[A-F0-9]+");
                if (match.Success)
                {
                    this.VSKEY = match.Value;
                }
            }
]]>
      </Code>
    </Task>
  </UsingTask>

</Project>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!