Статус: Новичок
Группы: Участники
Зарегистрирован: 24.05.2013(UTC) Сообщений: 6 Откуда: Москва Сказал(а) «Спасибо»: 1 раз Поблагодарили: 1 раз в 1 постах
|
Коллеги! Неприятность следующая...
Мне дан внешний веб-сервис заказчика для проверки подписи xmldsig. Подпись созданная на С# известными средствами CryptoPro.Sharpei и System.Security.Cryptography.Xml.signedXml замечательно и без проблем проходит проверку на этом сервисе. Я попробовал проделать то же ..., но с Browser plug-in и методом CAdESCOM.RawSignature.SignHash для вычисления тега <ds:SignatureValue> по значению тега <ds:SignedInfo>. Значение тега <ds:DigestValue> получалось то же, что и в C#, подтверждает правильность пользования мною методом oHashedData.Hash...
К сожалению, все попытки проверить xmldsig потерпели неудачу... Есть ощущение, что неправильно обрабатываю выход oRawSignature.SignHash... Делаю простую вещь:
var s = oRawSignature.SignHash(oHashedData, oCertificate); s = hex2bin(s); s = Base64.encode(s); return s;
Очень смущает информация о том, что oRawSignature.SignHash для ключей ГОСТ Р 34.10-2001 возвращается как описано в разделе 2.2.2 RFC 4491 (http://tools.ietf.org/html/rfc4491#section-2.2.2), но в обратном порядке байт...
Короче говоря, буду признателен, если кто-нибудь поможет сократить мой долгий путь к истине... |
С ув.РСВ |
|
|
|
Статус: Сотрудник
Группы: Администраторы, Участники Зарегистрирован: 10.12.2008(UTC) Сообщений: 924 Откуда: Крипто-Про Поблагодарили: 99 раз в 95 постах
|
http://tools.ietf.org/ht...cpxmldsig-07#section-6.3 GOST R 34.10-2001 signature is a 64-octet value as described in section 2.2.2 of CPPK ( = RFC4491 ). The content of the dsig:SignatureValue element shall be the base64 encoding of this value. Перед тем, как кодировать подпись в BASE64, вам ее нужно перевернуть.
|
1 пользователь поблагодарил Новожилова Елена за этот пост.
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 24.05.2013(UTC) Сообщений: 6 Откуда: Москва Сказал(а) «Спасибо»: 1 раз Поблагодарили: 1 раз в 1 постах
|
Спасибо за рекомендацию. Я пробовал несколько вариантов "переворачивания" подписи, начиная от самого простого: oHashedData.DataEncoding = CADESCOM_BASE64_TO_BINARY; oHashedData.Hash(Base64.encode(dataToSign)); // var s = oRawSignature.SignHash(oHashedData, oCertificate); // s = reverseStr(s); s = hex2bin(s); s = Base64.encode(s, true); //s = "7Y00w/Dg0G6RThvuips/GgW8J0rXpYFLlxk17hzMiuyzSAZSqWCKZ1uGGENIWr5PTL28pX4FkpeNMe6FXlS+5A=="; //правильная подпись из C# где function reverseStr(str) { var newStr = '', i; for (i = str.length - 1; i >= 0; i--) { newStr += str.charAt(i); } return newStr; } function hex2bin(hex) { var bytes = [], str; for(var i=0; i< hex.length-1; i+=2) bytes.push(parseInt(hex.substr(i, 2), 16)); return String.fromCharCode.apply(String, bytes); } Не проходит подпись. Подставляю вместо нее подпись, получаемую в С#, все проходит на ура... К сожалению, метод oRawSignature.SignHash не байты или биты возвращает, а строку шестнадцатеричных цифр, группами по две цифры на байт... Если же обратиться к источнику http://tools.ietf.org/html/rfc4491#section-2.2.2, то можно прочитать, что "переворачиваться" должна не подпись, не байты, а биты в пределах бинарной строки... И, так тоже пробовал. Не помогает. Отредактировано пользователем 29 мая 2013 г. 14:42:36(UTC)
| Причина: Не указана |
С ув.РСВ |
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 24.05.2013(UTC) Сообщений: 6 Откуда: Москва Сказал(а) «Спасибо»: 1 раз Поблагодарили: 1 раз в 1 постах
|
Все ... вопрос снимается. Проблема была в голове, а именно - в неправильной каноникализации подписываемого сообщения |
С ув.РСВ |
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 25.06.2013(UTC) Сообщений: 2
Сказал(а) «Спасибо»: 1 раз
|
Добрый день, у меня видимо аналогичная проблема. Формирование подписи сообщение на сервере силами C# проходит успешно. Но мне необходимо организовать подпись сообщения на клиенте. Привожу сообщение к каноничному виду и расчитываю digestValue на клиенте от body сообщение - хэш совпадает с аналогичным расчитанным с помощью c#, т.е. проблем с хэш обектом нету. Далее с помощью RawSignature пытаюсь сформировать подпись хэша от элемента SignedInfo. Полученное значение подписи перевожу в бинарный вид, переворачиваю и кодирую в base64. Но подпись не проходит проверку. Соответствеено если взять аналогичную подпись сформированную на сервере с помощью c#, то сообщение проходит проверку. Подскажите пожалуйста какие именно преобразования нужно произветсти с результатом RawSignature.SignHash?
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 24.05.2013(UTC) Сообщений: 6 Откуда: Москва Сказал(а) «Спасибо»: 1 раз Поблагодарили: 1 раз в 1 постах
|
function GetSignatureValue(dataToSign) { if (oRawSignature) { try { dataToSign = Base64._utf8_encode(dataToSign); oHashedData.Hash(Base64.encode(dataToSign, false)); var hex = oRawSignature.SignHash(oHashedData, oCertificate); //возвращает подпись в виде строки шестнадцатеричных цифр группами по две цифры на байт, разделённых пробелами var bin = hex2bin(hex); bin = reverseStr(bin); s = Base64.encode(bin, false); return s; } catch (err) { alert('Не удалось создать подпись!: ' + GetErrorMessage(err)); return ""; } } else { alert("Объект RawSignature не определен!"); return ""; } }
Если проверка не проходит, то причина в коникализации (служебные символы и т.п. и т.д.) |
С ув.РСВ |
1 пользователь поблагодарил srubtsov59 за этот пост.
|
allmic оставлено 27.06.2013(UTC)
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 25.06.2013(UTC) Сообщений: 2
Сказал(а) «Спасибо»: 1 раз
|
srubtsov59 спасибо за ответ. Упоминание _utf8_encode натолкнуло меня на решение проблемы с хэшом.( у меня была ещё проблема в том что от одинаковых данных хэш c помощью плагина и на сервере с помощью c# получался разным. Но если перед вычислением хэша на клиенте закодировать данные в utf8 то проблем нет. Но мне непонятно зачем все таки это нужно т.к. сама страница в кодировке utf8. Причем если данные корректно отображаются при дебаге, то после применения _utf8_encode отображается нечитаемая таробарщина вместо русских символов но хэш от этих данных считается правильный. С подписью в итоге все таки была проблема с некорректной канонизацией. В итоге получилось сформировать корректную подпись. Спасибо.
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 07.08.2012(UTC) Сообщений: 123
Сказал(а) «Спасибо»: 4 раз Поблагодарили: 6 раз в 6 постах
|
Добрый день, Самостоятельные попытки привести подпись XML к валидному виду не увенчались успехом. Не подскажите корректен ли алгоритм: Беру шаблон подписи: Цитата:<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/> <DigestValue/> </Reference> </SignedInfo> <SignatureValue/> <KeyInfo> <X509Data/> </KeyInfo> </Signature> Функции для конвертации в javascript: Цитата: reverse: function(str) { var newStr = '', i; for (i = str.length - 1; i >= 0; i--) { newStr += str.charAt(i); } return newStr;
},
hex : { d2h : function(d) { res = d.toString(16).toUpperCase();
if (res.length == 1) { res = '0' + res; }
return res; },
h2d : function (h) { return parseInt(h, 16); },
stringToHex : function (string) { var hex = '';
for (var i = 0; i < string.length; i++) { hex += this.d2h(string.charCodeAt(i)); }
return hex; },
hexToString : function (hex) { string = '';
for (var b = 0; b < hex.length; b += 2) { string += String.fromCharCode(parseInt(hex.substr(b, 2), 16)); }
return string; } },
base64 : { _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding encode : function (input) { var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0;
do { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63;
if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; }
output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length);
return output; },
// public method for decoding decode : function (input) { var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0;
var base64test = /[^A-Za-z0-9\+\/\=]/g; if (base64test.exec(input)) { return null; }
do { enc1 = this._keyStr.indexOf(input.charAt(i++)); enc2 = this._keyStr.indexOf(input.charAt(i++)); enc3 = this._keyStr.indexOf(input.charAt(i++)); enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); }
chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output; } }
1. Беру хэш канонизированной XML. Вставляю его в шаблон в качестве DigestValue. Например: e5bsMmsv+qWG1oY3mW9vbeBp1sbAH+Z9KtRKnm10ZzI= 2. Использую полученный хеш для создания подписи (замечу что преобразований к UTF8 нигде не производится): Цитата: hashObject.SetHashValue(hex.stringToHex(base64.decode(base64Hash)); var hex = rawSignature.SignHash(hashObject, certificate);
Результат: A5BDC9CD1A50DD982725E36A8D62237712A8AECBEEF0AD0BE34BB04C50EEE0707D2EA984695FA3B45264A2BA04F2CA59501BBC23164BF4A2E2B91562A79FA589 3. Переворачиваю строку Цитата:reverse(hex.hexToString(hex)) Результат в хексе: 89A59FA76215B9E2A2F44B1623BC1B5059CAF204BAA26452B4A35F6984A92E7D70E0EE504CB04BE30BADF0EECBAEA8127723628D6AE3252798DD501ACDC9BDA5 4. Беру base64 от перевернутой строки и подставляю в SignatureValue. Base64: iaWfp2IVueKi9EsWI7wbUFnK8gS6omRStKNfaYSpLn1w4O5QTLBL4wut8O7LrqgSdyNijWrjJSeY3VAazcm9pQ== 5. Добавляю в X509Data блок <X509Certificate> с сертификатом, который использовался для подписи. 6. Проверяю полученную XML утилитой xmlsec1. В результате ошибка при проверке: EVP_VerifyFinal:error=18:data do not match:signature do not match Отредактировано пользователем 5 июля 2013 г. 9:43:07(UTC)
| Причина: Не указана
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 24.05.2013(UTC) Сообщений: 6 Откуда: Москва Сказал(а) «Спасибо»: 1 раз Поблагодарили: 1 раз в 1 постах
|
Добрый день! Во всем написанном я не разбирался, но п. 3 сразу "глаз колет". Нужно "втупую по символам" инвертировать строку, а не по байтам... Отредактировано пользователем 5 июля 2013 г. 8:21:33(UTC)
| Причина: Не указана |
С ув.РСВ |
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 07.08.2012(UTC) Сообщений: 123
Сказал(а) «Спасибо»: 4 раз Поблагодарили: 6 раз в 6 постах
|
Да, поправился - переворачиваю строку. И Base64 беру от перевернутой строки
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close