<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Форум Рутокен &mdash; Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
	<link rel="self" href="https://forum.rutoken.ru/feed/atom/topic/1917/" />
	<updated>2013-06-07T06:54:27Z</updated>
	<generator>PunBB</generator>
	<id>https://forum.rutoken.ru/topic/1917/</id>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6302/#p6302" />
			<content type="html"><![CDATA[<p>Проблема решилась.<br />Дела были следующие:<br />1. Bouncy Castle создает и считывает публичный ключ в порядке &quot;sr&quot;, а не &quot;rs&quot;: </p><div class="codebox"><pre><code>...
if (s[0] != 0)
{
    System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
}
else
{
    System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
}

if (r[0] != 0)
{
    System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
}
else
{
    System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
}
...</code></pre></div><p>2. Перед процессами подписи и проверки подписываемые и проверяемые данные шифруются по стандарту ГОСТ 28147-89: </p><div class="codebox"><pre><code>... 
// Encrypt gost28147-ECB
E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
...</code></pre></div><p>Поэтому-то проверки подписей созданных рутокеном не проходили.</p><p>Убрал из последовательности проверки подписи шифрование и инвертирование публичного ключа - заработало.</p><p>Если кому интересно, то вот код работающей программы:</p><div class="codebox"><pre><code>import java.math.BigInteger;
import java.security.Security;

import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;

public class RuTokenVerificationTest {
    public static void main(final String[] args) {

        final String publicKey = &quot;16E3585053A4BE8546FB3475F1CBDD7FF1A2C9BC886BD8C1E9214C2C2A4681226BFBA33C9F50F8F952091306C5BE17E5447D82F8EFBC0784E10234E7D7CA71A0&quot;;
        final String hash = &quot;5D5FE1DD044A577C8B6580F49394CF4B4EF2D617C60C9AB6CDF2AC14BAB359C7&quot;;
        final String sign = &quot;1B432A390D2871EEF2A4F4A5A607938DC4EBE6D2871A18133578F701851F37C22BE1AFE68F9FE586F36C626FABF9DFC316491742EC793388EFADDE81FE34F3DC&quot;;

        final BigInteger x = new BigInteger(publicKey.substring(0, 64), 16);
        final BigInteger y = new BigInteger(publicKey.substring(64), 16);
        final BigInteger r = new BigInteger(sign.substring(0, 64), 16);
        final BigInteger s = new BigInteger(sign.substring(64), 16);

        Security.addProvider(new BouncyCastleProvider());

        final ECDomainParameters parameters = ECGOST3410NamedCurves.getByOID(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A);
        final ECCurve curve = parameters.getCurve();

        final ECParameterSpec spec = new ECParameterSpec(curve, parameters.getG(), parameters.getN());
        final ECPublicKeySpec pubKey = new ECPublicKeySpec(curve.createPoint(x, y, false), spec);
        final BigInteger n = parameters.getN();
        final BigInteger aprE = new BigInteger(hash, 16).mod(n);
        final BigInteger e = aprE.compareTo(ECConstants.ZERO) == -1 ? aprE.add(n) : aprE;

        if (r.compareTo(ECConstants.ONE) &lt; 0 || r.compareTo(n) &gt;= 0) {
            System.out.println(false);
            return;
        }

        if (s.compareTo(ECConstants.ONE) &lt; 0 || s.compareTo(n) &gt;= 0) {
            System.out.println(false);
            return;
        }

        final BigInteger v = e.modInverse(n);
        final BigInteger z1 = s.multiply(v).mod(n);
        final BigInteger z2 = (n.subtract(r)).multiply(v).mod(n);
        final ECPoint G = parameters.getG();
        final ECPoint Q = pubKey.getQ();
        final ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, z1, Q, z2);

        if (point.isInfinity()) {
            System.out.println(false);
            return;
        }

        final BigInteger R = point.getX().toBigInteger().mod(n);

        System.out.println(r.equals(R));
    }
}</code></pre></div><p>Спасибо за ответы.</p>]]></content>
			<author>
				<name><![CDATA[Dzhinn]]></name>
				<uri>https://forum.rutoken.ru/user/8964/</uri>
			</author>
			<updated>2013-06-07T06:54:27Z</updated>
			<id>https://forum.rutoken.ru/post/6302/#p6302</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6301/#p6301" />
			<content type="html"><![CDATA[<p>Поскольку байт кодируется, вообще говоря, двумя шестнадцатиричными цифрами, то подпись с инвертированным порядоком байт должна иметь вид DCF334...2A431B.<br />Не могли бы Вы прислать пример данных (хэш, публичный ключ и подпись), для которых успешно проходит проверка подписи в используемой Вами библиотеке?</p>]]></content>
			<author>
				<name><![CDATA[Алексей Караваев]]></name>
				<uri>https://forum.rutoken.ru/user/7758/</uri>
			</author>
			<updated>2013-06-06T14:08:31Z</updated>
			<id>https://forum.rutoken.ru/post/6301/#p6301</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6298/#p6298" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Алексей Караваев пишет:</cite><blockquote><p>То есть Вы пробовали передавать в качестве подписи&nbsp; </p><div class="codebox"><pre><code>final String sign = &quot;DCF334FE81DEADEF883379EC42174916C3DFF9AB6F626CF386E59F8FE6AFE12BC2371F8501F7783513181A87D2E6EBC48D9307A6A5F4A4F2EE71280D392A431B&quot;</code></pre></div><p>, и проверка подписи не прошла?</p></blockquote></div><p>Нет, я просто инвертировал последовательность байтов, проверка не прошла.<br />Данное значение </p><div class="codebox"><pre><code>final String sign = &quot;DCF334FE81DEADEF883379EC42174916C3DFF9AB6F626CF386E59F8FE6AFE12BC2371F8501F7783513181A87D2E6EBC48D9307A6A5F4A4F2EE71280D392A431B&quot;</code></pre></div><p> тоже не проходит проверку.</p>]]></content>
			<author>
				<name><![CDATA[Dzhinn]]></name>
				<uri>https://forum.rutoken.ru/user/8964/</uri>
			</author>
			<updated>2013-06-05T16:14:08Z</updated>
			<id>https://forum.rutoken.ru/post/6298/#p6298</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6297/#p6297" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Dzhinn пишет:</cite><blockquote><p>Не помогло.</p></blockquote></div><p>То есть Вы пробовали передавать в качестве подписи&nbsp; </p><div class="codebox"><pre><code>final String sign = &quot;DCF334FE81DEADEF883379EC42174916C3DFF9AB6F626CF386E59F8FE6AFE12BC2371F8501F7783513181A87D2E6EBC48D9307A6A5F4A4F2EE71280D392A431B&quot;</code></pre></div><p>, и проверка подписи не прошла?</p>]]></content>
			<author>
				<name><![CDATA[Алексей Караваев]]></name>
				<uri>https://forum.rutoken.ru/user/7758/</uri>
			</author>
			<updated>2013-06-05T14:25:22Z</updated>
			<id>https://forum.rutoken.ru/post/6297/#p6297</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6296/#p6296" />
			<content type="html"><![CDATA[<p>Те данные, что указаны в коде в первом сообщении темы - это данные из исходников тестовой площадки на PHP, файл token.php, в частности:<br /></p><div class="codebox"><pre><code>function token_test() {
        $Hash = &#039;5D5FE1DD044A577C8B6580F49394CF4B4EF2D617C60C9AB6CDF2AC14BAB359C7&#039;;
        $Qx = &#039;16E3585053A4BE8546FB3475F1CBDD7FF1A2C9BC886BD8C1E9214C2C2A468122&#039;;
        $Qy = &#039;6BFBA33C9F50F8F952091306C5BE17E5447D82F8EFBC0784E10234E7D7CA71A0&#039;;
        $R = &#039;1B432A390D2871EEF2A4F4A5A607938DC4EBE6D2871A18133578F701851F37C2&#039;;
        $S = &#039;2BE1AFE68F9FE586F36C626FABF9DFC316491742EC793388EFADDE81FE34F3DC&#039;;
        if (token_verify($Hash, $Qx, $Qy, $R, $S)){
            echo &quot;Sign valid\n&quot;;
        }else{
            echo &quot;Sign not valid\n&quot;;
        }
}</code></pre></div><p>Так же пробовал с данными, которые можно сгенерировать на тестовой площадке рутокен web, тут: <a href="http://php.rutokenweb.ru/api.php">http://php.rutokenweb.ru/api.php</a><br />Результат одинаков.</p><p>P.s. Если ренерить ключи с помощью того же Bouncy Castle для кривой gostR3410_2001_CryptoPro_A и работать с ними, то все хорошо, подпись и проверка проходят.</p>]]></content>
			<author>
				<name><![CDATA[Dzhinn]]></name>
				<uri>https://forum.rutoken.ru/user/8964/</uri>
			</author>
			<updated>2013-06-05T12:03:22Z</updated>
			<id>https://forum.rutoken.ru/post/6296/#p6296</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6295/#p6295" />
			<content type="html"><![CDATA[<p>Подскажите, с помощью какого ПО сгенерирован и прочитан ключ, а также вычислены хэш и подпись?</p>]]></content>
			<author>
				<name><![CDATA[Алексей Караваев]]></name>
				<uri>https://forum.rutoken.ru/user/7758/</uri>
			</author>
			<updated>2013-06-05T11:51:07Z</updated>
			<id>https://forum.rutoken.ru/post/6295/#p6295</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6294/#p6294" />
			<content type="html"><![CDATA[<p>Не помогло.</p>]]></content>
			<author>
				<name><![CDATA[Dzhinn]]></name>
				<uri>https://forum.rutoken.ru/user/8964/</uri>
			</author>
			<updated>2013-06-05T11:26:16Z</updated>
			<id>https://forum.rutoken.ru/post/6294/#p6294</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6293/#p6293" />
			<content type="html"><![CDATA[<p>Добрый день! Попробуйте перед проверкой изменить порядок байт подписи на обратный.</p>]]></content>
			<author>
				<name><![CDATA[Алексей Караваев]]></name>
				<uri>https://forum.rutoken.ru/user/7758/</uri>
			</author>
			<updated>2013-06-05T10:16:34Z</updated>
			<id>https://forum.rutoken.ru/post/6293/#p6293</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Проверка подписи по ГОСТ Р 34.10-2001. Java.]]></title>
			<link rel="alternate" href="https://forum.rutoken.ru/post/6292/#p6292" />
			<content type="html"><![CDATA[<p>Добрый день!</p><p>Имеется - ЭЦП по ГОСТ Р 34.10-2001 созданной &quot;Рутокеном ЭЦП&quot;, открытый ключ, подписываемый хеш.<br />Требутеся - Исходя из имеющихся данных проверить ЭЦП.&nbsp; Платформа Java.</p><p>Для реализации задачи использовалась библиотека Bouncy Castle. Данные для создания нужной элиптической кривой взяты из примеров, написанных на php и c#, Bouncy Castle предоставляет нужную кривую - &quot;gostR3410_2001_CryptoPro_A&quot;. Данные для примера работы проверки подписи взяты из примера написанного на php.<br />Сам код:<br /></p><div class="codebox"><pre><code>import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECCurve;

public class RuTokenVerificationTest {
    public static void main(final String[] args) throws NoSuchProviderException, NoSuchAlgorithmException,
            InvalidKeySpecException, InvalidKeyException, SignatureException, DecoderException {

        final String publicKey = &quot;16E3585053A4BE8546FB3475F1CBDD7FF1A2C9BC886BD8C1E9214C2C2A4681226BFBA33C9F50F8F952091306C5BE17E5447D82F8EFBC0784E10234E7D7CA71A0&quot;;
        final String hash = &quot;5D5FE1DD044A577C8B6580F49394CF4B4EF2D617C60C9AB6CDF2AC14BAB359C7&quot;;
        final String sign = &quot;1B432A390D2871EEF2A4F4A5A607938DC4EBE6D2871A18133578F701851F37C22BE1AFE68F9FE586F36C626FABF9DFC316491742EC793388EFADDE81FE34F3DC&quot;;

        final BigInteger x = new BigInteger(publicKey.substring(0, 64), 16);
        final BigInteger y = new BigInteger(publicKey.substring(64), 16);

        Security.addProvider(new BouncyCastleProvider());

        final Signature sgr = Signature.getInstance(&quot;ECGOST3410&quot;, &quot;BC&quot;);
        final KeyFactory f = KeyFactory.getInstance(&quot;ECGOST3410&quot;, &quot;BC&quot;);

        final ECDomainParameters parameters = ECGOST3410NamedCurves.getByOID(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A);
        final ECCurve curve = parameters.getCurve();

        final ECParameterSpec spec = new ECParameterSpec(curve, parameters.getG(), parameters.getN());
        final ECPublicKeySpec pubKey = new ECPublicKeySpec(curve.createPoint(x, y, false), spec);
        final PublicKey pk = f.generatePublic(pubKey);

        sgr.initVerify(pk);

        sgr.update(hash.getBytes());

        System.out.println(sgr.verify(Hex.decodeHex(sign.toCharArray())));
    }
}</code></pre></div><p>Результат работы - false. Т.е. проверка не проходит. Никак не могу разобраться почему... Пробовал и реальные данные, созданные рутокеном, - тот же результат.<br />Может быть что-то в форматах данных, в частности, хеша, я верно делаю когда просто беру байтовый массив хеша и передаю его на проверку? Может его нужно представить в каком-то другом виде? Тоже самое с подписью. Помогите понять в чем ошибка.</p>]]></content>
			<author>
				<name><![CDATA[Dzhinn]]></name>
				<uri>https://forum.rutoken.ru/user/8964/</uri>
			</author>
			<updated>2013-06-05T09:24:16Z</updated>
			<id>https://forum.rutoken.ru/post/6292/#p6292</id>
		</entry>
</feed>
