Windows Phone ANID到CID上的ANID2转换?

时间:2013-08-01 07:18:21

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

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(Cryptography API:Next Generation)的东西。以下是一些代码:

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# Byte array

这是C ++调试器: C++ version

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

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

C# byte array

C ++:

C++ byte array

如果我在加密值之后查看输出,我可以看到差异:

在C#上我得到了这段代码的输出:

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

字节数组如下所示:

C# crypt result

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

C++ hash result

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

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

Unicode

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

C# unicode results

这是C ++的正确结果:

Correct result

3 个答案:

答案 0 :(得分: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%确定属性设定者做了什么,但值得一试)。

答案 1 :(得分:1)

确保在将ANID字节数组用作HMACSHA256的密钥之前将其剪切为一半。转换算法只需要前44个字节,而不是整个88个。不要问我为什么,但AFAIK,如果你看{{3的示例代码',它将ANID转换为ANID2时使用的C ++代码中的错误 - 他们必须把错误的wchar用于char!

答案 2 :(得分: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);
}