(2015-07-09 14:10:57 отредактировано ConstantineOupirum)

Использование rtPKCS11ECP.dll из Java через SunPKCS11

Здравствуйте.
Пытаюсь верифицировать подписанные рутокеном данные на Java.
В качестве провайдера пытаюсь использовать SunPKCS11.
Сделал конфиг:

name = Rutoken
library = E:\\Temp\\rtPKCS11ECP.dll

Этот конфиг даю конструктору SunPKCS11:

String config = "E:\\Temp\\pkcs11.cfg";
Provider p = new SunPKCS11(config);
Security.addProvider(p);

Но, при попытке использовать этот провайдер я получаю только NoSuchAlgorithmException, как для KeyFactory.RSA, так и для Signature.SHA1withRSA:

KeyFactory.getInstance("RSA", "SunPKCS11-Rutoken");                 // NoSuchAlgorithmException
Signature.getInstance("SHA1withRSA", "SunPKCS11-Rutoken");     // NoSuchAlgorithmException
Cipher.getInstance("RSA", "SunPKCS11-Rutoken");                        // NoSuchAlgorithmException

Что я делаю не так?

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

ConstantineOupirum пишет:

Signature.SHA1withRSA:
Signature.getInstance("SHA1withRSA", "SunPKCS11-Rutoken");   // NoSuchAlgorithmException

Этот комбинированный алгоритм действительно не поддерживается.
Используйте отдельно SHA1 и RSA.

(2015-07-09 14:02:35 отредактировано ConstantineOupirum)

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Кирилл Мещеряков пишет:
ConstantineOupirum пишет:

Signature.SHA1withRSA:
Signature.getInstance("SHA1withRSA", "SunPKCS11-Rutoken");   // NoSuchAlgorithmException

Этот комбинированный алгоритм действительно не поддерживается.
Используйте отдельно SHA1 и RSA.

Проблема в том, что и

KeyFactory.getInstance("RSA", "SunPKCS11-Rutoken");

ругается с NoSuchAlgorithm, т.о. я даже public ключ из модуля и экспоненты собрать не могу.

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

RSA работать должен.
А какая модель рутокена у вас?

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Кирилл Мещеряков пишет:

RSA работать должен.
А какая модель рутокена у вас?

Рутокен ЭЦП

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Возможно, что то в коде у вас не так

package ru.rutoken.Samples.sunJCA;

import java.security.*;
import javax.crypto.*;
import java.security.cert.*;
import java.util.Enumeration;

public class RSA {

    static byte[] message = {
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };

    public static void main(String[] args) {
        try {

            String userPin = "12345678";
            int keySize = 512;

            System.out.println("Example of working with RSA algorithm using SunRsaSign Provider via JCA");

            String config = "cfg/pkcs11.cfg";
            Provider sunPKCS11 = new sun.security.pkcs11.SunPKCS11(config);
            int pos = Security.addProvider(sunPKCS11);
            System.out.println("Provider Level: " + pos);

            // Авторизация на токен
            char[] pin = userPin.toCharArray();
            KeyStore ks = KeyStore.getInstance("PKCS11", sunPKCS11);
            ks.load(null, pin);

            // Генерация ключевой пары
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", sunPKCS11);
            generator.initialize(keySize);
            KeyPair pair = generator.generateKeyPair();
            PrivateKey privKey = pair.getPrivate();
            PublicKey pubKey = pair.getPublic();

            // Поиск ключевой пары на токене (только если присутствует сертификат)
            Enumeration aliases = ks.aliases();
            String alias = null;
            while (aliases.hasMoreElements()) {
                alias = aliases.nextElement().toString();
            }
            if (alias != null) {
                X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
                System.out.println("Certificate:\n " + cert);
                pubKey = cert.getPublicKey();
                privKey = (PrivateKey) ks.getKey(alias, null);
            }

            System.out.println("Public key:\n " + pubKey);
            System.out.println("Private key:\n " + privKey);

            // Шифрование по алгоритму RSA
            Cipher rsaEncrypt = Cipher.getInstance("RSA/ECB/NoPadding", sunPKCS11);
            rsaEncrypt.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] encryptedMessage = rsaEncrypt.doFinal(message);

            System.out.println("Encrypted data:");
            for (int i = 0; i < encryptedMessage.length; i++) {
                System.out.printf(" %02X", encryptedMessage[i]);
                if ((i + 1) % 8 == 0)
                    System.out.printf("\n");
            }
            System.out.println("Data has been encrypted successfully.");

            // Расшифрование по алгоритму RSA
            Cipher rsaDecrypt = Cipher.getInstance("RSA/ECB/NoPadding", sunPKCS11);
            rsaDecrypt.init(Cipher.DECRYPT_MODE, privKey);
            byte[] decryptedMessage = rsaDecrypt.doFinal(encryptedMessage);

            System.out.println("Decrypted data:");
            for (int i = 0; i < decryptedMessage.length; i++) {
                System.out.printf(" %02X", decryptedMessage[i]);
                if ((i + 1) % 8 == 0)
                    System.out.printf("\n");
            }
            System.out.println("Data has been decrypted successfully.");

            // Подпись по алгоритму RSA
            String dataToSign = "Aktiv Co., Ltd.";
            System.out.println("Data for signature: " + dataToSign);

            Signature rsaSign = Signature.getInstance("SHA1withRSA", sunPKCS11);
            rsaSign.initSign(privKey);
            rsaSign.update(dataToSign.getBytes());
            byte[] signedData = rsaSign.sign();

            System.out.println("Signed data:");
            for (int i = 0; i < signedData.length; i++) {
                System.out.printf(" %02X", signedData[i]);
                if ((i + 1) % 8 == 0)
                    System.out.printf("\n");
            }
            System.out.println("Data has been signed successfully.");

            // Проверка подписи по алгоритму RSA
            Signature rsaVerify = Signature.getInstance("SHA1withRSA", sunPKCS11);
            rsaVerify.initVerify(pubKey);
            rsaVerify.update(dataToSign.getBytes());
            if (rsaVerify.verify(signedData)) {
                System.out.println("Signature has been verified successfully.");
            } else {
                System.out.println("Signature verification failed!");
            }
        } catch (Exception e) {
            System.out.printf("Some error occurred. Error code: " + e.getMessage());
        }
    }
}

(2015-07-09 14:18:16 отредактировано ConstantineOupirum)

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Кирилл Мещеряков пишет:

Возможно, что то в коде у вас не так

Похоже на то.
А как у Вас выглядит файл pkcs11.cfg ?

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

ConstantineOupirum пишет:
Кирилл Мещеряков пишет:

Возможно, что то в коде у вас не так

Похоже на то.
А как у Вас выглядит файл pkcs11.cfg ?

name = provider
library = C:\Windows\System32\rtPKCS11ECP.dll
showInfo = true
slot = 0
attributes(generate, CKO_PUBLIC_KEY,  CKK_RSA) = {
  CKA_LABEL = 0h53616d706c6520525341205075626c6963204b6579
  CKA_ID = 0h525341
  CKA_ENCRYPT = true
  CKA_TOKEN = true
  CKA_PRIVATE = false
  CKA_MODULUS_BITS = 512
}

attributes(generate, CKO_PRIVATE_KEY,  CKK_RSA) = {
  CKA_LABEL = 0h53616d706c65205253412050726976617465204b6579
  CKA_ID = 0h525341
  CKA_DECRYPT = true
  CKA_TOKEN = true
  CKA_PRIVATE = true
}

(2015-07-09 15:06:24 отредактировано ConstantineOupirum)

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Кирилл Мещеряков пишет:
ConstantineOupirum пишет:
Кирилл Мещеряков пишет:

Возможно, что то в коде у вас не так

Похоже на то.
А как у Вас выглядит файл pkcs11.cfg ?

name = provider
library = C:\Windows\System32\rtPKCS11ECP.dll
showInfo = true
slot = 0
attributes(generate, CKO_PUBLIC_KEY,  CKK_RSA) = {
  CKA_LABEL = 0h53616d706c6520525341205075626c6963204b6579
  CKA_ID = 0h525341
  CKA_ENCRYPT = true
  CKA_TOKEN = true
  CKA_PRIVATE = false
  CKA_MODULUS_BITS = 512
}

attributes(generate, CKO_PRIVATE_KEY,  CKK_RSA) = {
  CKA_LABEL = 0h53616d706c65205253412050726976617465204b6579
  CKA_ID = 0h525341
  CKA_DECRYPT = true
  CKA_TOKEN = true
  CKA_PRIVATE = true
}

А не подскажете, что мне из этого нужно добавить к моему, помимо name и library?
(учитывая,что мне нужно только верифицировать подпись, с самим рутокеном не взаимодействую)
Я предполагаю, что проблема в неправильном конфиге, ибо я не вижу ошибки в коде:

String config = "E:\\Temp\\pkcs11.cfg";
PROVIDER = new SunPKCS11(config);
Security.addProvider(PROVIDER);
Signature signature = Signature.getInstance("SHA1withRSA", PROVIDER);

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

ConstantineOupirum пишет:

А не подскажете, что мне из этого нужно добавить к моему, помимо name и library?
(учитывая,что мне нужно только верифицировать подпись, с самим рутокеном не взаимодействую)

В таком случае вопрос, зачем Вам вообще PKCS#11 провайдер, если только проверка подписи программным способом нужна?

(2015-07-09 15:43:30 отредактировано ConstantineOupirum)

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Vladimir Ivanov пишет:
ConstantineOupirum пишет:

А не подскажете, что мне из этого нужно добавить к моему, помимо name и library?
(учитывая,что мне нужно только верифицировать подпись, с самим рутокеном не взаимодействую)

В таком случае вопрос, зачем Вам вообще PKCS#11 провайдер, если только проверка подписи программным способом нужна?

Просто, насколько я знаю, рутокен подписывает по стандарту #11.
Я изначально пытался верифицировать подпись c BouncyCastle, но результат всегда false. Подумал, что проблема в несоответствии стандарта.
Вот мой код варианта с BouncyCastle: http://stackoverflow.com/questions/3128 … fy-by-java
(может Вы укажите на ошибку в том варианте).
Если возможно верифицировать подпись без sunpkcs11, я только за, но как заставить это работать?

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

ConstantineOupirum пишет:

Я изначально пытался верифицировать подпись c BouncyCastle, но результат всегда false. Подумал, что проблема в несоответствии стандарта.

Так часто бывает, если в разных реализациях используется разный порядок байтов, разные кодировки и т.п. вещи.

ConstantineOupirum пишет:

Если возможно верифицировать подпись без sunpkcs11, я только за, но как заставить это работать?


Можно использовать другой провайдер, JCE, например:

https://docs.oracle.com/javase/7/docs/t … CEProvider

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Vladimir Ivanov пишет:

Можно использовать другой провайдер, JCE, например:
https://docs.oracle.com/javase/7/docs/t … CEProvider

Но SunJCE не имеет SHA1withRSA.
Или с SunJCE нужно не верифицировать, а дешифровать+сравнивать, используя Cipher? Я правильно понял?

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

Vladimir Ivanov пишет:

Можно использовать другой провайдер, JCE, например:
https://docs.oracle.com/javase/7/docs/t … CEProvider

С SunJCE ничего не вышло, но проблема решилась тупым перебором всех встроенных провайдеров. Удалось верифицировать с SunMSCAPI.
Благодарю за помощь.

Re: Использование rtPKCS11ECP.dll из Java через SunPKCS11

ConstantineOupirum пишет:
Vladimir Ivanov пишет:

Можно использовать другой провайдер, JCE, например:
https://docs.oracle.com/javase/7/docs/t … CEProvider

Но SunJCE не имеет SHA1withRSA.
Или с SunJCE нужно не верифицировать, а дешифровать+сравнивать, используя Cipher? Я правильно понял?

Прошу прощения, плохо посмотрел. По ссылке есть и другие провайдеры, которые поддерживают SHA1withRSA.
Вы сертификаты используете или просто сырую подпись?