В Windows Phone 7 было свойство идентификатора анонимного пользователя ANID. Windows Phone 8 заменил это на ANID2. Разница в том, что ANID2 зависит от идентификатора издателя приложения.
Есть возможность конвертировать ANID в ANID2 как следующий пример кода на MSDN показывает. Единственное, что вам нужно, это оригинальный WP7 ANID и идентификатор издателя (guid). Проблема в том, что пример на C ++. Я пытался перенести его на C #, но безуспешно.
Сам алгоритм довольно прост:
var data = HMAC(ANID, publisherId) // Uses SHA-256
var result = ToBase64(data)
Проблема в том, что я не могу получить результаты матча. Я убедился, что C ++ работает правильно, создав два приложения (WP7 и WP8), запустив их на одних и тех же устройствах, а затем преобразовав ANID из приложения WP7 с помощью GUID издателя. На 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 #) и pPublisherId (C ++) (идентификатор издателя как 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 ++:
Убедитесь, что вы разрезали байтовый массив ANID пополам, прежде чем использовать его в качестве секретного ключа для HMACSHA256. Алгоритму преобразования нужны только первые 44 байта, а не все 88. Не спрашивайте меня, почему, но AFAIK, это ошибка в коде C ++, который они используют при преобразовании ANID в ANID2, если вы посмотрите на пример кода на http://code.msdn.microsoft.com/wpapps/ANID-to-ANID2-Converter-cc428038 — Должно быть, они приняли Wchar за символ!
В 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%, что делает установщик свойств, но это стоит попробовать).
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);
}