如何将包含 PEM `PKCS#1` 格式的公钥的字符串转换为 Android 应用程序中的 PublicKey 对象?

问题描述 投票:0回答:1

如何将包含 PEM

PKCS#1
格式的公钥的字符串转换为 PublicKey 对象?

目前,我的代码只能成功转换

PKCS#8
格式的字符串。

const val PKCS1PublicHeader = "-----BEGIN RSA PUBLIC KEY-----"
const val PKCS1PublicFooter = "-----END RSA PUBLIC KEY-----"
const val PKCS8PublicHeader = "-----BEGIN PUBLIC KEY-----"
const val PKCS8PublicFooter = "-----END PUBLIC KEY-----"
fun String.pemToPublicKey(algorithm: String): PublicKey? {
    return try {
        val isRSAPublicKey = this.contains(PKCS1PublicHeader)
        val cleanedKeyContent = this
            .replace("\\r\\n", "")
            .replace("\\n", "").let {
                if (isRSAPublicKey) {
                    it.replace(PKCS1PublicHeader, "").replace(PKCS1PublicFooter, "")
                } else {
                    it.replace(PKCS8PublicHeader, "").replace(PKCS8PublicFooter, "")
                }
            }

        val keyBytes = Base64.decode(cleanedKeyContent, Base64.NO_WRAP)

        println("Cleaned Key Content: $cleanedKeyContent")
        println("Is RSA Public Key: $isRSAPublicKey")

        val keySpec: KeySpec = if (isRSAPublicKey) {
            val modulus = BigInteger(1, keyBytes)
            val exponent = BigInteger.valueOf(65537)
            RSAPublicKeySpec(modulus, exponent)
        } else {
            X509EncodedKeySpec(keyBytes)
        }

        val keyFactory = KeyFactory.getInstance(algorithm)
        val publicKey = keyFactory.generatePublic(keySpec)
//            as RSAPublicKey

        println("Generated Public Key: $publicKey")

        publicKey

//        KeyFactory.getInstance(algorithm).generatePublic(keySpec)
    } catch (e: Exception) {
        Timber.e(e, "Invalid PEM key: $this")
        null
    }
}
android kotlin cryptography pkcs#1
1个回答
0
投票

由于 PKCS#1 和 X.509/SPKI 之间的区别只是前导

AlgorithmIdentifier
,因此可以添加它以获得 X.509/SPKI 格式,这可以使用 BouncyCastle 方便地完成。然后可以像往常一样通过
X509EncodedKeySpec()
:

导入 X.509/SPKI 格式
import org.bouncycastle.asn1.ASN1Sequence
import org.bouncycastle.asn1.DERNull
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo

...
val keySpec: KeySpec = if (isRSAPublicKey) {
     val algId = AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE)
     val publicKeyInfo = SubjectPublicKeyInfo(algId, ASN1Sequence.getInstance(keyBytes))
     X509EncodedKeySpec(publicKeyInfo.encoded)
} else {
...

需要相应的依赖,例如:

implementation 'org.bouncycastle:bcprov-jdk18on:1.77'

请注意,BouncyCastle 还允许导入 PEM 密钥,这将显着简化您的代码。以下代码导入两种格式的 PEM 编码密钥,即 PKCS#1 格式和 X.509/SPKI 格式:

import org.bouncycastle.openssl.PEMParser
...
fun String.pemImport(algorithm: String): PublicKey? {
    val pemParser = PEMParser(StringReader(this))
    val subjectPublicKeyInfo = pemParser.readObject() as SubjectPublicKeyInfo;
    val keySpec = X509EncodedKeySpec(subjectPublicKeyInfo.encoded);
    val keyFactory = KeyFactory.getInstance(algorithm);
    val publicKey = keyFactory.generatePublic(keySpec);
    return publicKey;
}

除了上述依赖之外,还需要

PEMParser
的以下依赖:

implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
© www.soinside.com 2019 - 2024. All rights reserved.