Last active
February 14, 2023 15:10
-
-
Save mhewedy/3a421ef4e73de7a8888c7cded8807fbf to your computer and use it in GitHub Desktop.
Kotlin X509 certificate + PEM private key : encryption and decryption
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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