【问题标题】:Windows Phone ANID to ANID2 conversion on C#?C# 上的 Windows Phone ANID 到 ANID2 转换?
【发布时间】:2015-06-29 09:33:35
【问题描述】:

Windows Phone 7 有一个名为 ANID 的匿名用户 ID 属性。 Windows Phone 8 已将其替换为 ANID2。不同之处在于 ANID2 取决于应用的发布者 ID。

可以在 MSDN 节目中将 ANID 转换为 ANID2 as the following code sample。您只需要原始 WP7 ANID 和发布者 ID (guid)。问题是该示例是用 C++ 编写的。我一直在尝试将其移植到 C# 但没有成功。

算法本身很简单:

var data = HMAC(ANID, publisherId) // Uses SHA-256
var result = ToBase64(data)

问题是我无法获得匹配的结果。我通过创建两个应用程序(WP7 和 WP8),在相同的设备上运行它们,然后使用发布者 GUID 从 WP7 应用程序转换 ANID 来确保 C++ 正常工作。在 C++ 上,转换后的 ANID2 和设备中的 ANID2 匹配。在 C# 上,转换后的 ANID2 是另一回事。

C#代码很简单:

        var anidBytes = System.Text.Encoding.UTF8.GetBytes(this.anidBox.Text);
        var publisherGuid = Guid.Parse(this.publisherBox.Text.ToUpper());

        var macObject = new HMACSHA256(anidBytes);
        var hashed = macObject.ComputeHash(publisherGuid.ToByteArray());

        var result = Convert.ToBase64String(hashed);

C++ 版本使用一种称为 CNG(加密 API:下一代)的东西。这是其中的一些代码:

BCryptOpenAlgorithmProvider(&Algorithm, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
BCryptGetProperty(Algorithm,BCRYPT_OBJECT_LENGTH,reinterpret_cast<BYTE*>(&HashObjectLength),PropertyLength,&PropertyLength,0);
BCryptCreateHash(Algorithm, &Hash, HashObject, HashObjectLength, pAnidId, dwAnidLength, 0);
BCryptHashData(Hash, const_cast<BYTE*>(pPublisherId), dwPublisherIdLength, 0);
BCryptFinishHash(Hash, pUniqueId, GETDEVICEUNIQUEID_V1_OUTPUT, 0);

之后,“pUniqueId”使用一些自定义构建函数转换为 Base64。

感谢任何帮助。

更新: Visual Studio 报告 anidBytes (C#) 和 pAnidId (C++)(这是转换为字节的 ANID 字符串)的长度均为 44。这是 C# 调试器报告字节数组的方式:

这是 C++ 调试器:

我不懂 C++,所以我不确定这两者是否相同。它们是,但是 C++ 在每个字符之后都有这些 '\0' 字符,我不确定这是否可以。我认为是,因为两种情况下的长度都报告为 44。

另一个字节数组比较是publisherGuid (C#) vs pPublisherId (C++)(publisher id as GUID)。我认为他们再次匹配。 C#:

C++:

如果我在值被加密后查看输出,我可以看到不同:

在 C# 上,我从这段代码中得到输出:

        var macObject = new HMACSHA256(anidBytes);
        var hashed = macObject.ComputeHash(publisherBytes);

字节数组如下所示:

在 C++ 代码中,如果我检查 pUniqueId(BCryptFinishHash 的结果),我会看到:

这两种情况的长度似乎相同,但结果却不同。

在 C# 上,如果我将编码类型从 UTF8 更改为 Unicode,则 anidBytes 字节数组将更改为:

所以它与 C++ 调试器显示的相同。结果也发生了变化,但它仍然与 C++ 不同。这是新的 C# 结果:

这是 C++ 的正确结果:

【问题讨论】:

  • 第一件事:您检查过anidBytespublisherGuid.ToByteArray() 在二进制级别上是否与您在C++ 中使用的值相同?
  • 我添加了一些截图,似乎表明它们是相同的。
  • 看起来该值在 C++ 版本中以 UTF-16 编码(因此每个字符有两个字节)。在 C# 中使用 System.Text.Encoding.Unicode 而不是 System.Text.Encoding.UTF8
  • 感谢您的建议。不幸的是,结果仍然不同。我已经更新了帖子以反映这一点。
  • 我还检查了所有的编码选项。 ASCII 和 UTF8 给出相同的结果,其他则不同。仍然没有一个匹配 C++ 输出。

标签: c# c++ windows-phone-8 cng


【解决方案1】:

确保将 ANID 字节数组切成两半,然后再将其用作 HMACSHA256 的密钥。转换算法只需要前 44 个字节而不是整个 88 个字节。不要问我为什么,但是 AFAIK,如果您查看 http://code.msdn.microsoft.com/wpapps/ANID-to-ANID2-Converter-cc428038 的示例代码,这是他们在将 ANID 转换为 ANID2 时使用的 C++ 代码中的一个错误- 他们一定把 wchar 误认为 char 了!

【讨论】:

    【解决方案2】:

    在 C# 中,对于您的 HMACSHA256 对象,请尝试设置 Key 属性,而不是在构造函数中对其进行初始化。

    var anidBytes = System.Text.Encoding.Unicode.GetBytes(this.anidBox.Text);
    var macObject = new HMACSHA256();
    macObject.Key = anidBytes;
    

    http://msdn.microsoft.com/en-us/library/9c9tf8wc.aspx 表示构造函数将密钥填充到 64 个字节。

    (我不能 100% 确定属性设置器的作用,但值得一试)。

    【讨论】:

      【解决方案3】:
      public string Convert(string winPhone7Anid)
      {
          var anidAsBytes = System.Text.Encoding.Unicode.GetBytes("A=" + winPhone7Anid + "&E=f48&W=3");
          var macObject = new HMACSHA256(anidAsBytes.Take(anidAsBytes.Length / 2).ToArray());
          var hashedBytes = macObject.ComputeHash(new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX").ToByteArray());
          return System.Convert.ToBase64String(hashedBytes);
      }
      

      【讨论】:

      • 我有一个 Windows Phone 7.5 应用程序,我升级到了 Windows Phone 8,这最终对我有用。我记得以前在某个地方读过这个,但不记得确切的位置。您可以使用示例应用程序对此进行测试,您会发现它确实有效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-23
      • 2013-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多