簡體   English   中英

從編碼私鑰的字節中提取算法ID

[英]Extracting algorithm ID from bytes of encoded private key

是否可以單獨從編碼的字節數組創建PrivateKey而不事先知道算法

所以在某種程度上,這是一個扭曲的問題 ,在答案中沒有得到解決。

假設我有這樣生成的一對密鑰:

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

要從base64編碼的字節獲取PrivateKey ,我可以這樣做,但我必須提前知道算法系列:

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

不幸的是, encodedKeySpec.getAlgorithm()返回null

我很確定算法ID實際上是在PKCS#8格式的那些字節中指定的,但我不確定如何讀取ASN.1編碼。

我可以從這些字節中以可靠的方式“嗅探”算法ID嗎?

只支持RSA和EC(JRE支持的算法,沒有其他提供商)是可以的。

為了了解我所追求的目標,這是一種似乎在經驗上有效的嘗試:

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

但我不知道這是否安全。 也許ID並不總是在那些偏移處。 也許他們可以用其他方式編碼......

正如詹姆斯在評論中所建議的那樣,嘗試每種支持的算法都會以更加安全的方式運行。

可以動態獲取此類算法的列表:

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

然后,只需嘗試全部生成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");
} 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM