Разница между реализацией криптографии .NET 3.5 и реализацией Mono 2.x?

У меня есть идентичный код, который компилируется и запускается под Mono (Unity 4.5) и MS .NET:

DSAParameters privateKey;
...
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(csp);
dsa.PersistKeyInCsp = false;
dsa.ImportParameters(privateKey);

Закрытый ключ загружается с диска, а загружаемые байты и устанавливаемые целые числа в «privateKey» идентичны в версиях Mono и MS .NET.

В версии .NET dsa.ImportParameters создает исключение «Неверные данные».

я пытался

  • разные настройки .NET (минимум 3.5, AnyCPU/x86/x64)
  • разные ключи (некоторые выбрасывают, некоторые нет, но подписи .NET всегда (?) недействительны, когда я их проверяю, тогда как сгенерированные с теми же ключами и для одного и того же сообщения в Mono работают нормально.)

Есть ли какое-то фундаментальное различие между реализацией MS DSA и реализацией Mono под капотом, что может вызвать это...?

Приветствуется любой пролитый свет... это что-то вроде головной боли...

Дополнительная информация:

  • Ключ генерируется на Java и экспортируется после преобразования из формата DER для работы с .NET (P1363; только большие целые числа одно за другим)
  • Ключ загружается с диска с помощью BinaryReader, а целочисленные значения загружаются как byte[] в DSAParameters (P, Q, G и X).
  • Открытый ключ загружается в приложение Java, которое использует реализацию Oracle для проверки подписи.
  • Весь код C# является «симметричным», т. е. используется как есть как в приложениях Mono, так и в приложениях MS .NET.

Обновление 2

Хорошо, я не схожу с ума; сегодня утром я попробовал снова; одно и то же приложение .NET запускается на Mac (с использованием Mono Develop, простая ваниль) и одно на Windows (Visual Studio 2010). Загружены одни и те же байты закрытого ключа, тот же путь кода (по крайней мере, что касается С#) - такое же исключение «плохих данных» только в Windows. Вот ключ:

P: 17801190547854226652823756245015999014523215636912067427327445031444286578873
70207706126952521234630795671567847784664499706507709207278570500096683881440341
29745221171818506047231150039301079959358067395348717066319802262019714966524135
060945913707594956514672855690606794135837542707371727429551343320695239

Q: 864205495604807476120572616017955259175325408501

G: 17406820753240209518581198012352343653860449079456135097849583104059995348845
58231478515974089409507253077970949157594923683005742524387610370844734671801488
76118103083043754985190983472601550494691329488083395492313850000361646482644608
492304078721818959999056496097769368017749273708962006689187956744210730

X: 3505625379966178555918512548923624458026758122

...


person SonarJetLens    schedule 13.03.2015    source источник
comment
Несколько быстрых проверок работоспособности, которые я провел с .NET и mono, не выявили никаких проблем. Я отмечаю, что недопустимое свойство Seed может привести к ошибке Bad Data, но я ожидаю, что и с моно. Может помочь дополнительная информация: (1) Как вы генерируете закрытый ключ (например, в том или ином .NET или моно DSACryptoServiceProvider)? (2) Можете ли вы предоставить еще немного кода (например, для загрузки DSAParameters, возможно, проблема в нем). (3) Вы говорите, что подписи .NET всегда недействительны, как вы их проверяете?   -  person softwariness    schedule 13.03.2015
comment
@softwareness Я обновил свой вопрос, добавив дополнительную информацию. Итак, конкретно; 1) ключ генерируется не в .NET, а в Java 2) код загрузки точно такой же, и когда я выполнил побайтовое сравнение полученных необработанных байтов закрытого ключа, они точно одинаковы до того, как я загрузите их с помощью ImportParameters   -  person SonarJetLens    schedule 13.03.2015
comment
На какой ОС и архитектуре работает код Java и моно? Интересно, проблема в неправильном порядке байтов?   -  person softwariness    schedule 13.03.2015
comment
Код Java работает в Linux и Windows (оба протестированы) - код .NET (Mono и MS) работает на ПК (и Mac, для части Mono), поэтому, учитывая, что путь Mono-Java работает независимо от платформы, он не это похоже на проблему с порядком байтов. В частности, поскольку необработанные байты идентичны до загрузки. Я начинаю задаваться вопросом, есть ли в MS .NET какие-то правила для целых чисел, которые он позволяет использовать для DSA, которые где-то спрятаны... Есть ли в этом смысл?   -  person SonarJetLens    schedule 13.03.2015
comment
На самом деле я имел в виду порядок байтов в реализации Mono vs .NET DSACryptoServiceProvider, а не в загрузке параметров из файла (т.е. байты идентичны в ImportParameters, но по-разному интерпретируются этим методом), но, вероятно, это не так. не то. Re .NET ограничивает значения, это возможно, или это может быть ошибка. Можете ли вы предоставить шестнадцатеричный или base64 некоторые примеры параметров, которые не могут быть импортированы в .NET, чтобы я мог попытаться воспроизвести их?   -  person softwariness    schedule 13.03.2015
comment
@softwareness Я сделаю это, когда вернусь в офис в понедельник, хороший план   -  person SonarJetLens    schedule 14.03.2015


Ответы (2)


.NET Framework ожидает, что некоторые отношения размеров будут поддерживаться:

  • Вопрос: 20 байт
  • G: той же длины, что и P
  • Y, если присутствует: той же длины, что и P
  • seed, если есть: 20 байт
  • X, если присутствует: 20 байт

Это просто сквозные требования базового поставщика криптографии: https://msdn.microsoft.com/en-us/library/windows/desktop/aa381987(v=vs.85).aspx#PRIVK_BLOB.

Основываясь на длине ваших значений выше, вам, вероятно, нужно дополнить X нулями слева.

person bartonjs    schedule 01.08.2016
comment
Прошло некоторое время с тех пор, как эта проблема и проект с тех пор двигались в совершенно другом направлении, но ваше предложение кажется разумным. Если мне удастся снова откопать проект, я попробую это подтвердить. - person SonarJetLens; 07.08.2016

краткий ответ заключается в том, что хэш-коды могут различаться между версиями и платформами .NET Framework, такими как 32-разрядные и 64-разрядные платформы; или между Microsoft и Mono.

Это можно прочитать здесь: Object.GetHashCode , прочтите примечания.

Я уже сталкивался с такой ситуацией при разработке кроссплатформенных многопользовательских игр в Unity3D. Поэтому вам нужно будет использовать свою собственную хэш-функцию или использовать симметричный алгоритм для шифрования ваших данных.

Из документации я прочитал, что DSACryptoServiceProvider имеет асимметричный характер и использует хэши для создания цифровых подписей. Вот ссылка: DSACryptoServiceProvider Класс , прочитайте примечания.

person Baltico    schedule 28.03.2015
comment
Но используемый алгоритм хеширования будет SHA1, который не зависит от хэш-кодов объекта (которые в любом случае не используются, поскольку это хэш последовательности байтов, а не объекта)... верно? - person SonarJetLens; 30.03.2015