I want to use ECC (curve25519) with Diffie-Hellman Key exchange. Backend is using ECC with X9.62 and PKCS#8 encoding. I want to achieve same on iOS so that I can fetch data from backed, decrypt it and show it to user.
I tried this code but didn't work
func getPEM() -> String {
let keyPair = Curve25519.Signing.PrivateKey()
let pubKey = keyPair.publicKey
let pem = "-----BEGIN PUBLIC KEY-----\(pubKey.rawRepresentation.base64EncodedString())-----END PUBLIC KEY-----"
return pem
}
After searching on Google I found that In order to get PEM we need DER and ASN1 from my public key but they are not supported by CryptoKit.
Android is able to get right PEM using bouncycastle. Just for reference I am posting snippet from android code base.
import org.bouncycastle.asn1.x9.X9ECParameters
import org.bouncycastle.crypto.ec.CustomNamedCurves
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.*
import java.security.spec.ECParameterSpec
import java.security.spec.InvalidKeySpecException
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
object CryptoKeyGenerator {
init {
Security.removeProvider(BOUNCY_CASTLE_IDENTIFIER)
Security.addProvider(BouncyCastleProvider())
}
fun getClientKeyMaterial(): String {
val keyPair = generateEphemeralKeyPair()
val pemEncodedPublicKey = getPEMEncodedStream(keyPair.public, false)
return pemEncodedPublicKey
}
private fun getPEMEncodedStream(key: Key, privateKey: Boolean): String {
val pkcS8EncodedKeySpec = PKCS8EncodedKeySpec(key.encoded)
val stringBuilder = StringBuilder()
val keyType = if(privateKey) PRIVATE_KEY else PUBLIC_KEY
stringBuilder.append(KEY_HEADER_START + keyType + KEY_HEADER_END)
stringBuilder.append(CryptoUtils.getBase64Encoded(pkcS8EncodedKeySpec.encoded))
stringBuilder.append(KEY_FOOTER_START + keyType + KEY_HEADER_END)
return stringBuilder.toString()
}
/**
* This method generates an ECC KeyPair with Curve25519 specs
*/
private fun generateEphemeralKeyPair(): KeyPair {
val keyPairGenerator = KeyPairGenerator.getInstance(EC_ALGO_IDENTIFIER, BOUNCY_CASTLE_IDENTIFIER)
val eccParameters: X9ECParameters = CustomNamedCurves.getByName(ECC_CURVE_SPEC)
val eccSpec: ECParameterSpec = EC5Util.convertToSpec(eccParameters)
keyPairGenerator.initialize(eccSpec)
return keyPairGenerator.generateKeyPair()
}
}
Android generated PEM of public key look like this
-----BEGIN PUBLIC KEY-----MIIBMTCB6gYHKoZIzj0CATCB3gIBATArBgcqhkjOPQEBAiB/////////////////////////////////////////7TBEBCAqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqYSRShRAQge0Je0Je0Je0Je0Je0Je0Je0Je0Je0Je0JgtenHcQyGQEQQQqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0kWiCuGaG4oIa04B7dLHdI0UySPU1+bXxhsinpxaJ+ztPZAiAQAAAAAAAAAAAAAAAAAAAAFN753qL3nNZYEmMaXPXT7QIBCANCAAQwsdIRTVn2+6rlgqAhVvx7ERj/Oku0wHmZZU1OST617h95ygSP5zJOa9lNiKqZMArjtJh7yQ4rg7kUq08Nv8+Q-----END PUBLIC KEY-----
Other references: This repo has code for C, Java and nodejs https://github.com/Sahamati/rahasya