Ошибка HSM | Закрытый ключ должен быть экземпляром ключа RSAPrivate(Crt) или иметь PKCS#8

Ошибка при расшифровке данных при получении закрытого ключа из HSM.

Я добавил провайдера sunpkcs11 в java.security. Следовательно, НЕ добавляя провайдера через код. Текст успешно шифруется. Однако, расшифровывая зашифрованный текст, я получаю ошибку ниже в строке ниже:

cipher.init(Cipher.DECRYPT_MODE, privateKey);

Что мне здесь не хватает?

Ошибка:

    Caused by: java.security.InvalidKeyException: Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding
        at sun.security.pkcs11.P11RSAKeyFactory.implTranslatePrivateKey(P11RSAKeyFactory.java:101) [sunpkcs11.jar:1.7.0_85]
        at sun.security.pkcs11.P11KeyFactory.engineTranslateKey(P11KeyFactory.java:132) [sunpkcs11.jar:1.7.0_85]
        at sun.security.pkcs11.P11KeyFactory.convertKey(P11KeyFactory.java:65) [sunpkcs11.jar:1.7.0_85]
        at sun.security.pkcs11.P11RSACipher.implInit(P11RSACipher.java:199) [sunpkcs11.jar:1.7.0_85]
        at sun.security.pkcs11.P11RSACipher.engineInit(P11RSACipher.java:168) [sunpkcs11.jar:1.7.0_85]
        at javax.crypto.Cipher.init(Cipher.java:1068) [jce.jar:1.7.0_85]
        at javax.crypto.Cipher.init(Cipher.java:1012) [jce.jar:1.7.0_85]enter code here

Ниже приведен код:

import java.io.ByteArrayOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;

import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;

import sun.security.pkcs11.SunPKCS11;

public class App {

    public static void main(String[] args) throws Exception {

        try {
            String passphrase = "mysecretkey";
            SunPKCS11 provider = new SunPKCS11("/home/user/pkcs11.cfg");
            KeyStore keystore = KeyStore.getInstance("PKCS11", provider);
            keystore.load(null, passphrase.toCharArray());
            String textToEncrypt = "this is my text";
            Certificate cert = keystore.getCertificate("my-SHA1WITHRSA-2048-bits-key");
            PublicKey publicKey = cert.getPublicKey();
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            String encryptedData = DatatypeConverter.printBase64Binary(cipher.doFinal(textToEncrypt.getBytes()));

            PrivateKey privateKey = (PrivateKey) keystore.getKey("my-SHA1WITHRSA-2048-bits-key",
                    passphrase.toCharArray());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decodedEncryptedData = DatatypeConverter.parseBase64Binary(encryptedData);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            int blocks = decodedEncryptedData.length / 256;
            int offset = 0;
            for (int blockIndex = 0; blockIndex < blocks; blockIndex++) {
                byte[] nextBlock = getNextBlock(decodedEncryptedData, offset);
                stream.write(cipher.doFinal(nextBlock));
                offset += 256;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static byte[] getNextBlock(byte[] cipherText, int offset) {
        byte[] block = new byte[256];
        System.arraycopy(cipherText, offset, block, 0, 256);
        return block;
    }

}

3 ответа

Как я решил:

Основной причиной этой проблемы было то, что поставщик sunpkcs11 загружался как статически, так и динамически.

то есть в java.security, запись провайдера вместе с путем cfg уже была добавлена.

Кроме того, в коде провайдер снова был инициализирован с помощью файла cfg.

Это было причиной проблемы.

После смены:

SunPKCS11 provider = new SunPKCS11("/home/user/pkcs11.cfg");

TO:

SunPKCS11 sunPKCS11Provider = (SunPKCS11) Security.getProvider("SunPKCS11");

проблема решена

Я использовал следующий код, и проблема была решена

    SunPKCS11 provider = new SunPKCS11("/home/user/pkcs11.cfg");
    Security.addProvider(provider);
    KeyStore keystore = KeyStore.getInstance("PKCS11");
    keystore.load(null, passphrase.toCharArray());

Я получал ту же ошибку при попытке получить ContentSigner с SHA1, используя Linux и Jdk 1.8u202. Я не нашел отчета, но подозреваю, что в этом JDK есть ошибка, потому что он работал на более новых JDK (1.8u322), JDK11, JDK17 в Linux и на 1.8u202 в Windows.

Другие вопросы по тегам