#c# #cryptography #uwp #hololens
#c# #криптография #uwp #hololens
Вопрос:
Я портирую некоторый крипто-код на UWP для HoloLens. AFAIK, я реализовал его идеально в соответствии с требованиями UWP, но я получаю загадочное исключение InvalidCastException из следующего кода:
public override byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV)
IBuffer dataBuffer = WindowsRuntimeBuffer.Create(clearData, 0, clearData.Length, clearData.Length);
IBuffer keyBuffer = WindowsRuntimeBuffer.Create(Key, 0, Key.Length, Key.Length);
IBuffer ivBuffer = WindowsRuntimeBuffer.Create(IV, 0, IV.Length, IV.Length);
string strAlgName = KeyDerivationAlgorithmNames.Pbkdf2Sha256;
// Open the specified algorithm.
KeyDerivationAlgorithmProvider objAlgProv = KeyDerivationAlgorithmProvider.OpenAlgorithm(strAlgName);
// Create a key by using the passed buffer.
CryptographicKey key = objAlgProv.CreateKey(keyBuffer);
IBuffer encryptedData = CryptographicEngine.Encrypt(key, dataBuffer, ivBuffer); // throws System.InvalidCastException
return (byte[])encryptedData.ToArray();
Я не совсем уверен, в чем проблема. Я проверил, что типы всех параметров передаются в CryptographicEngine.Шифрование — правильный тип. Ранее я попробовал метод расширения AsBuffer для своих байтовых массивов; я переключился на WindowsRuntimeBuffer.Создайте мышление, которое могло бы сработать, но это не имеет никакого значения. DataBuffer и ivBuffer имеют тип WindowsRuntimeBuffer, который реализует IBuffer, и оба имеют длину, кратную 8 (32 и 16 соответственно). Я попробовал кастинг в качестве IBuffer, но это не сработало. Я даже попытался сгенерировать 3 случайных IBUFFER, все длиной 32, чтобы посмотреть, сработает ли это хотя бы; это не работает. Это ошибка, или я упускаю что-то действительно очевидное? Более того, исключение InvalidCastException является полностью универсальным и дает мне только трассировку стека из моего собственного приложения, что мне абсолютно ничего не говорит.
FWIW, вот вся трассировка стека:
at Windows.Security.Cryptography.Core.CryptographicEngine.Encrypt(CryptographicKey key, IBuffer data, IBuffer iv)
at dk.UWP.Crypto.UWPSimpleEncryption.Encrypt(Byte[] clearData, Byte[] Key, Byte[] IV)
at dk.UWP.Crypto.UWPSimpleEncryption.Encrypt(String clearText, String Password)
at dk.Crypto.SimpleEncryption.Encrypt(String clearText, String Password)
at bbtb.Scene.BBTBInitialization.<DeferSplashForInitialization>d__19.MoveNext()
at UnityEngine.SetupCoroutine.InvokeMoveNext(IEnumerator enumerator, IntPtr returnValueAddress)
at UnityEngine.SetupCoroutine.$Invoke1InvokeMoveNext(Int64 instance, Int64* args)
at UnityEngine.Internal.$MethodUtility.InvokeMethod(Int64 instance, Int64* args, IntPtr method)
Комментарии:
1. Вы пытаетесь зашифровать что-то с помощью «ключа» PBKDF2, которого не существует. Что именно должен делать код? Можете ли вы показать нам существующий код, из которого вы его переносили?
2. @ArtjomB., приведенный выше код основан на шаблонном коде из примеров MSDN: msdn.microsoft.com/en-us/library/windows/apps /… … насколько я понимаю из документации, ключом является не PBKDF2, а скорее алгоритм. Затем ключ генерируется из алгоритма с использованием предоставленного буфера. Если я ошибаюсь в этом, пожалуйста, дайте мне знать. Должен ли я использовать другой алгоритм? Они не предоставляют много информации в MSDN о различиях между ними, и я не уверен, как это может вызвать исключение InvalidCastException.
3. Вот старый код, но поймите, что старый код не имеет никакого отношения к вопросу, который я задал, поскольку он полностью не поддерживается в UWP / Holographic:
MemoryStream ms = new MemoryStream(); Rijndael alg = Rijndael.Create(); alg.Key = Key; alg.IV = IV; CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); cs.Write(clearData, 0, clearData.Length); cs.Close(); byte[] encryptedData = ms.ToArray(); return encryptedData;
4.
IBuffer dataBuffer = CryptographicBuffer.GenerateRandom(1); string strAlgName = KeyDerivationAlgorithmNames.Pbkdf2Sha256; KeyDerivationAlgorithmProvider objKdfProv = KeyDerivationAlgorithmProvider.OpenAlgorithm(strAlgName); IBuffer secret = CryptographicBuffer.GenerateRandom(32); CryptographicKey key = objKdfProv.CreateKey(secret); CryptographicEngine.Encrypt(key, dataBuffer, null); // Still throws System.InvalidCastException
5. PBKDF2 — это алгоритм получения ключа. Это не алгоритм шифрования. Если вы хотите зашифровать с помощью AES (Rijndael — это надмножество AES), вам следует использовать PBKDF2 в качестве функции обмена ключами, чтобы получить ключ и впоследствии использовать его для шифрования чего-либо. Это не ошибка, потому что вы не указали шифр. Посмотрите на пример в документации к первой части: msdn.microsoft.com/en-us/library/windows/apps /…
Ответ №1:
Похоже, что по какой-то причине примеры, которые MSDN предоставляет с KeyDerivationAlgorithmProvider и KeyDerivationAlgorithmNames, не работают. Если вместо этого использовать SymmetricAlgorithmNames и SymmetricAlgorithmProvider, кажется, все работает нормально. Я не уверен, что это сделано специально; если да, то это полностью недокументировано. Я опубликую дополнительную информацию, если обнаружу ее.
Комментарии:
1. Если примеры неверны, есть ли у вас какой-нибудь пример кода?
2. Этот выпуск от 2012 года полностью объясняет и устраняет проблему: answers.flyppdevportal.com/MVC/Post/Thread /…
3. Хотя это четко не задокументировано, для получения ключа и шифрования используются разные поставщики алгоритмов. Похоже на то, что вы говорили ранее, @ArtjomB., разница в том, что я правильно вывел ключ, но передача этого ключа в Encrypt() неверна. Вам нужны два ключа — один для генерации iv-буфера для шифрования, а другой, симметричный ключ, также для шифрования. Буфер ключей из первого ключа также передается в процесс создания симметричного ключа. Примеры на странице для CryptographicEngine, к сожалению, являются общими и плохо отражают эти детали.