2

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

可以将 ANID 转换为 ANID2 ,如 MSDN 上的以下代码示例所示。您只需要原始 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++ 版本

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

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

C#字节数组

C++:

C++ 字节数组

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

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

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

字节数组如下所示:

C# 加密结果

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

C++ 哈希结果

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

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

统一码

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

C# unicode 结果

这是 C++ 的正确结果:

结果正确

4

3 回答 3

1

在 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% 确定属性设置器的作用,但值得一试)。

于 2013-08-01T11:07:01.570 回答
1

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

于 2013-08-02T15:30:50.980 回答
0
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);
}
于 2015-06-29T01:33:35.823 回答