Как загрузить открытый ключ RSA из String для проверки подписи в Java? - PullRequest
0 голосов
/ 02 марта 2019

У меня есть следующий открытый ключ, который хранится в БД (PostgresSQL) в виде текста.Это строка, в Java:

-----BEGIN RSA PUBLIC KEY-----     
MIICCgKCAgEA1ht0OqZpP7d/05373OE7pB7yCVGNGzkUEuCneyfOzps6iA03NbvI
1ZL0Jpp/N3AW73lGdhaoa3X3JE4GsI/bsToVLQwTKmIOC4yjTvBctmFEoyhhTfxW
s1UHZKl4XZ/7THbRlKHhRaTKyfDAbikkMAxNT/qutLAPjnN1qOwjb1oRq52NP6FJ
KWTTikz4UeOHroX+Xthn2fJSJDlQ4YMdBbgrZVx5JcHKNuPTKRf5gI8QQKMSA9Q9
QJRE5OGp7b6dG14ZmOUnUxb00Mp20LgcaGPcuWU+oFsbQaF6W4G4bdkSZRJJXhSg
d4Q7mahpar94/gnztJmth0GzqTWUYyZIWNqIFoMwuOgeaiDV43zb3uLsRVpRKYYy
esmzcOy/jTScVLRCD8QRyu9B2wgCkNAVztQOXPCOOa4O1LlVQWaecIs4WPhOqDhi
KTBhyVkpC1TrrBkp+QMqMqWll1OyVb6k/7uV0qE/i6rHJtjo5v9bcIgYzswyx9CD
9PKl2Q0L0Jg7TMG+yLDIrLfGeuSeEc4XYJzN7bJcCeiizzu5iU9dQUkrncOrq9jn
Ub2pM/+A+JqIsoPK3IY/pJKqH4JYpGKhO1iPQF6iXIZT1r3ZgJUSQtzSeyYqhkla
2uR2BsbPbDqebCuXm3lAsY5w+dujijcn96PKwYha1LsK5sACHuJ79AMCAwEAAQ==
-----END RSA PUBLIC KEY-----

Я не знаю, как этот ключ был сгенерирован, извините.Мне сказали взять этот ключ и проверить подпись другой строки, которую я назову «объект».Мне сказали, что алгоритм, который я должен использовать для проверки «объекта», это SHA256 с RSA.

Итак, я написал следующий Java-метод для чтения ключа

private PublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
    publicKey = publicKey.replaceAll("\\n", "");
    publicKey = publicKey.replace("-----BEGIN RSA PUBLIC KEY-----", "");
    publicKey = publicKey.replace("-----END RSA PUBLIC KEY-----", "");
    publicKey = publicKey.trim();
    byte[] keyDecoded = Base64.getDecoder().decode(publicKey.getBytes());
    X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(keyDecoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey pubKey = kf.generatePublic(publicSpec);
    return pubKey;
}

Точкаявляется то, что я получаю следующее исключение:

java.security.InvalidKeyException: IOException: ошибка разбора algid, а не последовательность

Я прочитал множество предложений, как мой впереполнение стека.Код, написанный другими пользователями, очень похож (иногда идентичен) моему.Так что я точно не понимаю, почему это не работает для меня.Другие разработчики (коллеги) делают то же самое в php, и это прекрасно работает, поэтому я бы отверг гипотезу неправильного открытого ключа.Может быть, я не понял процесс ясно?У вас есть какие-либо подсказки, пожалуйста?

Я также пытался справиться с проблемой, используя библиотеку BouncyCastle, как предложено здесь , но я получаю то же исключение.Вот код, который я написал:

private static PublicKey getPublicKey(String publicKey)
        throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
    Security.addProvider(new BouncyCastleProvider());
    PemReader pp = new PemReader(new StringReader(publicKey));
    PemObject pem = pp.readPemObject();
    byte[] content = pem.getContent();
    pp.close();

    X509EncodedKeySpec spec = new X509EncodedKeySpec(content);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePublic(spec);
}

1 Ответ

0 голосов
/ 02 марта 2019

Вы не можете загрузить этот ключ, используя X509EncodedKeySpec.Согласно документации JavaDoc ожидается следующий формат:

SubjectPublicKeyInfo ::= SEQUENCE {
   algorithm AlgorithmIdentifier,
   subjectPublicKey BIT STRING }

Вместо этого ваш ключ выглядит иначе.Я использовал данные из вашего поста, преобразовал их в шестнадцатеричные данные и отправил в онлайн ASN.1 декодер .

Вывод такой:

SEQUENCE (2 elem)
  INTEGER (4096 bit) 873481340827968071893572683200799871431146795599597693981565010037737…
  INTEGER 65537

Как вы можете заметить, ваш ключ не содержит AlgorithmIdentifier, поэтому его нельзя загрузить с помощью X509EncodedKeySpec.

Я бы предложил использовать библиотеку BouncyCastle и класс PEMParser для загрузки этого ключа:

File pemFile = new File("test.pem");
try (PEMParser pp = new PEMParser(new InputStreamReader(new FileInputStream(pemFile)))) {
    SubjectPublicKeyInfo subjPubKeyInfo = (SubjectPublicKeyInfo) pp.readObject();
    RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(subjPubKeyInfo);

    RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
    KeyFactory kf = KeyFactory.getInstance("RSA");
    java.security.PublicKey publicKey = kf.generatePublic(rsaSpec);
    System.out.println(publicKey);
}

Или вы вручную конвертируете ключ в формат PKCS # 8 через openssl.

...