Мне нужно проверить подпись веб-перехватчика JSON. В документации есть только JavaScript-пример того, как это сделать:
const crypto = require("crypto");
const fs = require('fs');
const publicKey = fs.readFileSync('publicKey.pem', 'utf-8');
const payload = fs.readFileSync('payload.json', 'utf-8');
const signature = fs.readFileSync('signature.txt', 'utf-8');
function verify(publicKey, signature, payload) {
const verifier = crypto.createVerify("RSA-SHA256");
verifier.update(payload);
return verifier.verify(
{ key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING },
Buffer.from(signature, 'base64')
);
}
const verified = verify(publicKey, signature, payload);
console.info('Signature Verified: ', verified);
Приведенный выше код печатает «истину» в журнале консоли. Я пытаюсь смоделировать то же самое на С#, и он всегда возвращает false:
private static bool VerifySignature(string publicKeyPath, string payload, string signature)
{
byte[] byteToSign = Encoding.UTF8.GetBytes(payload);
byte[] bsign = Convert.FromBase64String(signature);
string pemText = File.ReadAllText(publicKeyPath);
PemReader pr = new PemReader(new StringReader(pemText));
AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey);
RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider();
cryptoServiceProvider.ImportParameters(rsaParams);
bool result = cryptoServiceProvider.VerifyData(byteToSign, bsign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
return result;
}
Я пробовал разные подходы на C#, приведенный выше выглядит чище и короче остальных. Что я делаю не так? Обратите внимание, что я использую .NET 4.8, поэтому у меня нет таких методов, как RSACryptoServiceProvider.ImportFromPem
, доступных только с версии 5. Спасибо.
ОБНОВЛЕНИЕ. Этот код работает правильно:
private static bool VerifySignature(string publicKeyPath, string payload, string signature)
{
byte[] byteToSign = Encoding.UTF8.GetBytes(payload);
byte[] bsign = Convert.FromBase64String(signature);
string pemText = File.ReadAllText(publicKeyPath);
PemReader pr = new PemReader(new StringReader(pemText));
AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
PssSigner pssSigner = new PssSigner(new RsaEngine(), new Sha256Digest(), bsign.Length - 32 - 2);
pssSigner.Init(false, publicKey);
pssSigner.BlockUpdate(byteToSign, 0, byteToSign.Length);
bool result = pssSigner.VerifySignature(bsign);
return result;
}
@Topaco Когда я использую RSASignaturePadding.Pss, cryptoServiceProvider.VerifyData возвращает ошибку: «Указанный режим заполнения недействителен для этого алгоритма»
Примените RSACng
(или используйте BouncyCastle на платформах/средах, где нет провайдера, поддерживающего PSS).
@Topaco RSACng
тоже не сработало. Это не произошло через исключение, как в случае с RSACryptoServiceProvider
, а вернуло false. Я обновил свой первоначальный вопрос, добавив рабочий код, используя PssSigner
- см. выше.
Если вы нашли решение - похоже, это подход БК - его следует публиковать не в вопросе, а в ответе!
Несовместимость собственной реализации C# (с RSACng
), вероятно, связана с тем, что, согласно документации, NodeJS по умолчанию использует максимальную длину соли для PSS, тогда как C# использует выходной размер дайджеста, что более распространено. Поскольку длина соли не настраивается в собственном C#, но есть в NodeJS, эту несовместимость можно устранить только путем адаптации кода NodeJS (или с помощью BC, который позволяет настраивать длину соли).
Этот код работает правильно:
private static bool VerifySignature(string publicKeyPath, string payload, string signature)
{
byte[] byteToSign = Encoding.UTF8.GetBytes(payload);
byte[] bsign = Convert.FromBase64String(signature);
string pemText = File.ReadAllText(publicKeyPath);
PemReader pr = new PemReader(new StringReader(pemText));
AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
PssSigner pssSigner = new PssSigner(new RsaEngine(), new Sha256Digest(), bsign.Length - 32 - 2);
pssSigner.Init(false, publicKey);
pssSigner.BlockUpdate(byteToSign, 0, byteToSign.Length);
bool result = pssSigner.VerifySignature(bsign);
return result;
}
Ваш ответ можно улучшить, добавив дополнительную вспомогательную информацию. Пожалуйста, отредактируйте , добавив дополнительную информацию, например цитаты или документацию, чтобы другие могли подтвердить правильность вашего ответа. Более подробную информацию о том, как писать хорошие ответы, вы можете найти в справочном центре.
Вы используете разные отступы: PSS в коде NodeJS и PKCS#1 v1.5 в коде C#. Для совместимости прокладки должны быть идентичными. В коде C# попробуйте RSASignaturePadding.Pss.