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 key look like this
MIIBMTCB6gYHKoZIzj0CATCB3gIBATArBgcqhkjOPQEBAiB/////////////////////////////////////////7TBEBCAqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqYSRShRAQge0Je0Je0Je0Je0Je0Je0Je0Je0Je0Je0JgtenHcQyGQEQQQqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0kWiCuGaG4oIa04B7dLHdI0UySPU1+bXxhsinpxaJ+ztPZAiAQAAAAAAAAAAAAAAAAAAAAFN753qL3nNZYEmMaXPXT7QIBCANCAAQwsdIRTVn2+6rlgqAhVvx7ERj/Oku0wHmZZU1OST617h95ygSP5zJOa9lNiKqZMArjtJh7yQ4rg7kUq08Nv8+Q
This repo has samples for java, c and Nodejs https://github.com/Sahamati/rahasya
With CryptoKit you won't be able to do this. You will need to use SwiftECC library(https://github.com/leif-ibsen/SwiftECC).
Step 1 - Create a
Domainspecifically for Curve25519Step 2 - Generate Public Key
Step 3 - Encapsulate the public key in PEM format -
I have also posted a detailed solution in a medium article, which also includes decryption - https://medium.com/@k.mohsin11/decrypting-financial-data-in-account-aggregator-ios-app-30d672ad4426
Let me know if you are still stuck.