如何将包含 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
}
}
由于 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'