Я не знаком с криптографией или протоколом PKCS, но мне нужно успешно выполнить crypto.verify в NodeJS, используя подпись, сгенерированную в MSSQL Signbycert.
используя это в качестве ссылки: https://stackoverflow.com/a/77519242/19991312 со следующим значением:
DECLARE @PlainText as varchar(max) = 'Hello World';
DECLARE @Signature as varbinary(max);
SET @Signature = SignByCert(Cert_ID('MyTestCertificate'), @PlainText);
SELECT @Signature as SIG, CERTENCODED(Cert_ID('MyTestCertificate')) as PBK;
простой текст
Hello World
Подпись
01000502040000002B0DFBF8B0EB048B18BA30A7A9AC3C63C18D8F932DC974178C61F810758A3FB81F14247AA338E6DBABAE265A8D8077C689901E33B016379685F7A0D27429DCB78F438201F5C04827F2F2B816BF5EFD569FA2AD7EEECC69621AF5F7C39893F0001FC22EAA74DB0F5026CDB38F5BFF3A3D208196C75E7A7A9556050459C826194E460D4C5AB1F30ACFF8594E4E99BC8FD5C8675E79EC54AC9EB017FA112C1759BF387C248869C461677E1CF711860618BFCAC1332C879C01D88C0EBFD584BCF4B358D5D47618A7367DE3A1943AB18454D1B8C423437661120EEE2225A35F763002E9AC80B23B5F03F1EA4C16422BEA8C51032AA0C16B73C7AC5583496EDFD6AA21
открытый ключ
3082036B30820253A00302010202146472932AE654353AF660E02361C2062FC040FEE6300D06092A864886F70D01010B05003045310B30090603550406130241553113301106035504080C0A536F6D652D53746174653121301F060355040A0C18496E7465726E6574205769646769747320507479204C7464301E170D3233313132303137303835375A170D3234313131393137303835375A3045310B30090603550406130241553113301106035504080C0A536F6D652D53746174653121301F060355040A0C18496E7465726E6574205769646769747320507479204C746430820122300D06092A864886F70D01010105000382010F003082010A0282010100CF9CCF5AF133484FC7DC8FF41C1B9010FC7821B373D0352A57E76A0FA0456AE1F35FDCED60343551594FC0E636727AF868EC237978BBBAE8C366B955A507CB942A3380755F6565F1811BF4476948008F18F3BEBE852540C660A781B362DAD21E70567CE70363EB4DE0F281DB239381308C2A8664B066F7F3331038E62465FC837AF170346AB63D1D18CA0400A6FC41EEE87FEFFB80C01D2FF7B86A1E48F299FA4BECA495C8B33CCB3A9603731AC9CE6B6F55EA1EB91DD919DCCBB17833CB1FB67C97891AF9FAC34EFDB2E7777DF5DFD7E4172638ED65ECBAE08AB5E17EB7EA81937DAAA79F9B041BE3C05488423BB3EF1B26C91D91CF7FD9D7A42E8E5582DA5F0203010001A3533051301D0603551D0E041604145F7A25691BA68CF1D6B59AD50E8F2CA6D0403018301F0603551D230418301680145F7A25691BA68CF1D6B59AD50E8F2CA6D0403018300F0603551D130101FF040530030101FF300D06092A864886F70D01010B0500038201010064E1E3CB35A81CB136B599134D0F536A4D1776CE26B2822B33C415C8E65EE4A8A5E185668455DDF326A4219CAB87D12ED59E85BDA31521201998165F41979CA0DB6608AF2A5D5A3A7566082B6E7B1204666233312E0FFABFF427DDB8E37415559CD8B5405F13425078ACDC1C02AECD3DE372FDC9DE0DCE9A74F3716AF2D0D2ACD06F6070AB620A5E6A5575CA760AED728AAD8549B047345D4F286EA51CB005719B2396F5C0340FB94162EE9E7EAC247CE402169FC754EACAC818C08DAD0A796D336F4437D665CD7ABAB1ED9E30D6213ED2328859709884C35BE1143861429A84FA2CE530F95434554B33131AA66EC6ABC22091E91072242B466877ED6D82C137
Основываясь на моем приблизительном понимании после прочтения этого: https://stackoverflow.com/a/77519242/19991312, подпись MSSQL отличается от стандартного протокола PKCS и не может быть напрямую использована в crypto.verify.
поэтому я сделал некоторые грубые преобразования значения подписи, но все еще не смог проверить подпись, возможно, из-за моего непонимания или отсутствия знаний в области криптографии. Моя текущая проверка в nodeJS выглядит следующим образом:
const plainText = 'Hello World';
const textDigest = crypto.hash('sha256', plainText, 'hex');
const sqlSignature = '...';
const pbk = '...';
const x509Cert = new crypto.X509Certificate(Buffer.from(pbk, 'hex'))
const signatureTransform = Buffer.from(sqlSignature.slice(16), 'hex').reverse()
const isSignatureValid = crypto.verify(null, Buffer.from(textDigest, 'hex'), x509Cert.publicKey, signatureTransform)
console.info('isSignatureValid', isSignatureValid ) // false Q^Q
🤔 А знаете ли вы, что...
Node.js обеспечивает высокую скорость обработки ввода-вывода (I/O), благодаря асинхронной модели.
Как уже описано в связанном посте, signatureTransform
не совместим со схемой подписи PKCS#1 v1.5 (точнее со схемой подписи RSASSA-PKCS1-v1_5 ), поскольку применяемая кодировка отличается от EMSA-PKCS1. -v1_5 в том смысле, что использовались только хешированные данные, а не кодировка DER значения DigestInfo.
По этой причине crypto.verify()
нельзя применять, так как при этом проверяется, строго ли расшифрованные данные соответствуют кодировке EMSA-PKCS1-v1_5 и, в частности, соответствует ли хеш-часть хешированному сообщению.
Вместо этого следует использовать crypto.publicDecrypt(). Эта реализация выполняет чистое дешифрование с помощью открытого ключа и распаковку статической части (0x0001FF...FF00) без дальнейшей проверки результирующих данных и, следовательно, возвращает сюда хеш сообщения.
Таким образом, проверка просто состоит из проверки идентичности хэшей:
...
const decrypted = crypto.publicDecrypt(x509Cert.publicKey, signatureTransform).toString('hex')
const verified = (decrypted === textDigest)
console.info("Verified:" , verified) // Verified: true