Skip to content

Instantly share code, notes, and snippets.

@mhewedy
Last active February 14, 2023 15:10
Show Gist options
  • Save mhewedy/3a421ef4e73de7a8888c7cded8807fbf to your computer and use it in GitHub Desktop.
Save mhewedy/3a421ef4e73de7a8888c7cded8807fbf to your computer and use it in GitHub Desktop.
Kotlin X509 certificate + PEM private key : encryption and decryption
/**
depends on config from https://www.baeldung.com/java-bouncy-castle
*/
import org.bouncycastle.cms.*
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.bouncycastle.util.encoders.Base64
import java.io.FileInputStream
import java.io.InputStreamReader
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.Security
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.spec.PKCS8EncodedKeySpec
const val keyFilename = "/path/to/pem/file/in/src/main/resource"
const val cerFilename = "/path/to/cer/file/in/src/main/resource"
fun main() {
Security.addProvider(BouncyCastleProvider())
val certificate = loadPublicKey()
val privateKey = loadPrivateKey()
val cipherText = encrypt("Hello World".toByteArray(), certificate)
println("cipherText: $cipherText")
val plainText = decrypt(cipherText, privateKey)
println("plainText: ${String(plainText)}")
}
private fun encrypt(data: ByteArray, certificate: X509Certificate): ByteArray {
val cmsEnvelopedDataGenerator = CMSEnvelopedDataGenerator()
cmsEnvelopedDataGenerator.addRecipientInfoGenerator(
JceKeyTransRecipientInfoGenerator(certificate)
)
val msg = CMSProcessableByteArray(data)
val encryptor = JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC)
.setProvider("BC").build()
val cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(msg, encryptor)
return cmsEnvelopedData.encoded
}
private fun decrypt(data: ByteArray, privateKey: PrivateKey): ByteArray {
val cmsEnvelopedData = CMSEnvelopedData(data)
val recipients: MutableCollection<RecipientInformation> = cmsEnvelopedData.recipientInfos.recipients
val recipientInfo = recipients.iterator().next()
return recipientInfo
.getContent(JceKeyTransEnvelopedRecipient(privateKey))
}
private fun loadPublicKey(): X509Certificate {
val certFactory = CertificateFactory.getInstance("X.509", "BC")
return FileInputStream("src/main/resources/$cerFilename").use {
certFactory.generateCertificate(it) as X509Certificate
}
}
private fun loadPrivateKey(): PrivateKey {
val keyText = InputStreamReader(
FileInputStream("src/main/resources/$keyFilename")
).use {
it.readText()
.replace("-----BEGIN RSA PRIVATE KEY-----\n", "")
.replace("-----END RSA PRIVATE KEY-----", "")
}
val encoded = Base64.decode(keyText)
return KeyFactory.getInstance("RSA")
.generatePrivate(PKCS8EncodedKeySpec(encoded))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment