ios SecKeyCopyKeyExchangeResult sharedInfo parameters

418 views Asked by At

Im trying to use the SecKeyCopyKeyExchangeResult function to obtain the shared secret from my local private key and received public key of server. Shared key is generated successfully and I able to decrypt incomming message with AES encryption Not so long time ago server devs decided to add KDF to key generation flow. I started investigate how I can do it on iOS side and find out that there is a special param static let sharedInfo: SecKeyKeyExchangeParameter To say that documentation is poor its to say nothing... Only what I did found is this description in header

@constant kSecKeyKeyExchangeParameterSharedInfo Contains CFDataRef with additional shared info for KDF (key derivation function).

If somebody have worked with this please help. Server use this params to generate KDF on scala

private def concatWithKdf(secretKey: SecretKey) = {
    val bytes = new Array[Byte](SECRET_KEY_LENGTH)
    val digest = new SHA256Digest();
    val kdf1BytesGenerator = new KDF1BytesGenerator(digest)
    kdf1BytesGenerator.init(new KDFParameters(secretKey.getEncoded, null))
    kdf1BytesGenerator.generateBytes(bytes, 0, bytes.length)
    new SecretKeySpec(bytes, secretKey.getAlgorithm)
}

Code on iOS side

var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
        SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
    let secret = SecKeyCopyKeyExchangeResult(privateOwn,
            SecKeyAlgorithm.ecdhKeyExchangeStandard,
            publicTheir,
            dict as CFDictionary,
            &keyExchangeError)
1

There are 1 answers

1
Woodstock On

You are totally right my friend, the documentation around the Security Framework is abysmal.

Indeed CryptoKit is Apple's attempt to modernise things here in a libsodium style providing simple interfaces to carefully selected primitives, such as elliptic curve Diffie-Hellman over safe curves.

So I sympathise, and suggest generally just use libsodium when you need crypto on iOS/macOS.

Anyway, to hopefully answer your question, I found a mention in the SecKit lib that matches what you seem to use in Scala, after the Diffie-Hellman process you are running the key material through SHA256 on the server side, so iOS needs to match this HBKDF.

 @constant kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256
    Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys
    and apply ANSI X9.63 KDF with SHA256 as hashing function.  Requires kSecKeyKeyExchangeParameterRequestedSize and allows
    kSecKeyKeyExchangeParameterSharedInfo parameters to be used.

so I think you just need to change this:

var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
        SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
    let secret = SecKeyCopyKeyExchangeResult(privateOwn,
            SecKeyAlgorithm.ecdhKeyExchangeStandard,
            publicTheir,
            dict as CFDictionary,
            &keyExchangeError)

to this:

var keyExchangeError: Unmanaged<CFError>?
let dict = [SecKeyKeyExchangeParameter.requestedSize.rawValue : 32,
        SecKeyKeyExchangeParameter.sharedInfo.rawValue : ???]
    let secret = SecKeyCopyKeyExchangeResult(privateOwn,
            SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256,
            publicTheir,
            dict as CFDictionary,
            &keyExchangeError)

I haven't tested the above as I'm on a Linux machine atm, but hopefully it helps, it should add SHA256 based KDF onto the ECDH process. But yeah, what a mess of an API. I just can't work with it.