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 ++调试器:
我不懂C ++,所以我不确定这两者是否相同。它们是,但C ++在每个之后都有这些'\ 0'字符,我不确定这是否正常。我认为是,因为两种情况下的长度都报告为44。
另一个字节数组比较是publisherGuid(C#)vs pPublisherId(C ++)(发布者ID为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 ++的正确结果:
答案 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);
}