La extracción de identificación del algoritmo de bytes de la clave privada codificada

Hugues M.:

¿Es posible crear una PrivateKeya partir de una matriz de bytes codificada solo, sin conocer el algoritmo de antemano ?

Así pues, en cierto modo, es una vuelta de tuerca a esa pregunta , que no es destinataria de las respuestas.

Decir que tengo un par de claves generadas de esta manera:

KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); // Could be "EC" instead of "RSA"
String privateKeyB64 = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
writePrivateKeyToSafeLocation(privateKeyB64);

Para obtener una PrivateKeyde los bytes codificados en base64, puedo hacer esto, pero tengo que conocer a la familia algoritmo de antemano:

String privateKeyB64 = readPrivateKeyFromSafeLocation();
EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyB64));
byte[] encodedKeyBytes = encodedKeySpec.getEncoded();
String algorithmFamily = "RSA"; // Can this be deduced from encodedKeyBytes?
PrivateKey key = KeyFactory.getInstance(algorithmFamily).generatePrivate(encodedKeySpec);

Desafortunadamente encodedKeySpec.getAlgorithm()devuelve null.

Estoy bastante seguro de que el ID de algoritmo es en realidad se especifican en esas bytes en formato PKCS # 8, pero no estoy seguro de cómo leer la codificación ASN.1.

Puedo "oler" la identificación del algoritmo de una manera fiable de esos bytes?

OK Es sólo un apoyo a RSA y CE (algoritmos soportados por el JRE, sin proveedores adicionales).

Para tener una idea de lo que busco, aquí es un intento que parece funcionar empíricamente:

private static final byte[] EC_ASN1_ID = {42, -122, 72, -50, 61, 2, 1};
private static final byte[] RSA_ASN1_ID = {42, -122, 72, -122, -9, 13, 1, 1, 1};
private static final int EC_ID_OFFSET = 9;
private static final int RSA_ID_OFFSET = 11;

private static String sniffAlgorithmFamily(byte[] keyBytes) {
    if (Arrays.equals(Arrays.copyOfRange(keyBytes, EC_ID_OFFSET, EC_ID_OFFSET + EC_ASN1_ID.length), EC_ASN1_ID)) {
        return "EC";
    }
    if (Arrays.equals(Arrays.copyOfRange(keyBytes, RSA_ID_OFFSET, RSA_ID_OFFSET + RSA_ASN1_ID.length), RSA_ASN1_ID)) {
        return "RSA";
    }
    throw new RuntimeException("Illegal key, this thingy requires either RSA or EC private key");
}

Pero no tengo ni idea de si es seguro de usar. Tal vez los IDs no están siempre a esas compensaciones. Tal vez puedan ser codificados en algunas otras maneras ...

Hugues M.:

Según lo sugerido por James en los comentarios, que intenta cada algoritmo apoyado funcionaría, de una manera mucho más segura.

Es posible obtener dinámicamente la lista de este tipo de algoritmos:

Set<String> supportedKeyPairAlgorithms() {
    Set<String> algos = new HashSet<>();
    for (Provider provider : Security.getProviders()) {
        for (Provider.Service service : provider.getServices()) {
            if ("KeyPairGenerator".equals(service.getType())) {
                algos.add(service.getAlgorithm());
            }
        }
    }
    return algos;
}

Y con eso, simplemente probarlos todos para generar el KeyPair:

PrivateKey generatePrivateKey(String b64) {
    byte[] bytes = Base64.getDecoder().decode(b64);
    for (String algorithm : supportedKeyPairAlgorithms()) {
        try {
            LOGGER.debug("Attempting to decode key as " + algorithm);
            return KeyFactory.getInstance(algorithm).generatePrivate(new PKCS8EncodedKeySpec(bytes));
        } catch (NoSuchAlgorithmException e) {
            LOGGER.warn("Standard algorithm " + algorithm + " not known by this Java runtime from outer space", e);
        } catch (InvalidKeySpecException e) {
            LOGGER.debug("So that key is not " + algorithm + ", nevermind", e);
        }
    }
    throw new RuntimeException("No standard KeyFactory algorithm could decode your key");
} 

Supongo que te gusta

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