Cómo cargar la clave pública RSA de cadena para la verificación de firmas en Java?

Peter:

Tengo la siguiente clave pública, que se almacena en la base de datos (PostgreSQL) como texto. Es una cadena, en 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-----

No sé cómo se ha generado esta clave, lo siento. Se me ha dicho que tome esta clave y verificar la firma de otra cadena que voy a llamar "objeto". Me han dicho que el algoritmo que tengo que usar para verificar "objeto" es SHA256withRSA.

Por lo tanto, he escrito el siguiente método Java para leer la clave

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;
}

El punto es que tengo la siguiente excepción:

java.security.InvalidKeyException: IOException: error de análisis álgido, no una secuencia

Tengo un montón de lectura de qustions como la mía en stackoverflow. El código escrito por otros usuarios es bastante similar (a veces idénticos) a la mía. Por lo que definitivamente no entiendo por qué no funciona para mí. Otros desarrolladores (compañeros de trabajo) están haciendo lo mismo en php y funciona muy bien, por lo que descartaría la hipótesis de la clave pública equivocada. Tal vez no he entendido claramente el proceso? ¿Tiene alguna idea, por favor?

También he tratado de hacer frente al problema usando la biblioteca BouncyCastle, como se sugiere aquí , pero tengo la misma excepción. El siguiente es el código que he escrito:

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);
}
Robert:

No se puede cargar esa llave utilizando un X509EncodedKeySpec. De acuerdo con ella de documentación Javadoc que espera el siguiente formato:

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

En cambio su clave se ve diferente. He utilizado los datos de su puesto, convertí a datos hexadecimales y lo publicó en línea en el decodificador ASN.1 .

La salida es la siguiente:

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

Como se puede reconocer su clave no contiene una AlgorithmIdentifierpor lo tanto, no se puede cargar utilizando X509EncodedKeySpec.

Mi sugerencia sería utilizar la biblioteca BouncyCastle y de PEMParserclase para cargar esta clave:

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);
}

O convertir manualmente la clave de formato PKCS # 8 a través de OpenSSL.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=211212&siteId=1
Recomendado
Clasificación