SharedSecret when used inside my JWE object creates a pad block corrupted error while decrypt

Hi All


I am generating a sharedSecret using apples API. When i use the same shared key inside my JWE object and send it to server, the server throws a pad block corrupted error / exception. I am pretty sure that the error is happening due to the way i have created the shared key. This is because when i flip that implementation of shareSecret using a 3rd party library it works fine. I am trying to get rid of this 3rd party implementation and trying to write my own implemenation. Can anyone suggest / spot any issues with my sharedSecret function below. If not can anyone let me know how to generate a shared secret ( 32 bytes ) out of a private and public EC key ?


Below Implementation which generates pad block corrupted exception.


let sharedZ = try! ecdhDeriveBits(ecPrivJwk: keyPair.getPrivate(),
                                                    ecPubJwk: publicKey,
                                                    bitLen: 256)

func ecdhDeriveBits(ecPrivJwk: ECPrivateKey, ecPubJwk: ECPublicKey, bitLen: Int = 0) throws -> Data {

        if ecPrivJwk.crv != ecPubJwk.crv {
            throw NSError(domain: "key derive fail", code: 10, userInfo: nil)
        }
        let pubKey = try ecPubJwk.converted(to: SecKey.self)
        let eprivKey = try ecPrivJwk.converted(to: SecKey.self)
        let parameters = [String: Any]()
        var error: Unmanaged?

        guard let derivedData = SecKeyCopyKeyExchangeResult(
            eprivKey,
            SecKeyAlgorithm.ecdhKeyExchangeStandard,
            pubKey,
            parameters as CFDictionary,
            &error)
            else {
                let errStr = error?.takeRetainedValue().localizedDescription ?? "Derive Key Fail"
                throw NSError(domain: "key derive fail", code: 10, userInfo: nil)
        }

     
        return bitLen > 0 ? truncateBitLen(from: (derivedData as Data), bitLen: bitLen) : (derivedData as Data) as Data
    }


Implemention of sharedSecret which works fine using a 3rd party library called chilkat.


let sdkPrivateKey: CkoPrivateKey = loadPrivateKey(privateKeyPkcs1Enc: sdkPrivateKey)!
let sharedKey: Data = getSharedSecretKey(clientPrivateKey: sdkPrivateKey, serverPublicKey: acsPublicKey1)!

func loadPrivateKey(privateKeyPkcs1Enc: String) -> CkoPrivateKey? {
        let success: Bool
        let privateKey = CkoPrivateKey()
        success = privateKey!.loadPkcs1(Data(base64Encoded: privateKeyPkcs1Enc))
        if success != true {
            print("\(privateKey!.lastErrorText ?? "no key")")
            return nil
        }
        return privateKey
    }

func getSharedSecretKey(clientPrivateKey: CkoPrivateKey, serverPublicKey: CkoPublicKey) -> Data? {
        JweHelper.unlockLibrary()
        let eccClient = CkoEcc()
        let sharedSecret: String? = eccClient!.sharedSecretENC(clientPrivateKey, pubKey: serverPublicKey, encoding: "base64")
        return Data(base64Encoded: sharedSecret!)
    }

Replies

The code snippets you posted rely on a whole bunch of other code that you’ve not shown. However, it’s easy to demonstrate ECDH in action with code as follows:

let localPrivateKey = SecKeyCreateRandomKey([
    kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeySizeInBits: 256,
] as NSDictionary, nil)!
let localPublicKey = SecKeyCopyPublicKey(localPrivateKey)!

let remotePrivateKey = SecKeyCreateRandomKey([
    kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeySizeInBits: 256,
] as NSDictionary, nil)!
let remotePublicKey = SecKeyCopyPublicKey(remotePrivateKey)!

let localShareSecret = SecKeyCopyKeyExchangeResult(localPrivateKey, .ecdhKeyExchangeStandard, remotePublicKey, [:] as NSDictionary, nil)! as Data
let remoteShareSecret = SecKeyCopyKeyExchangeResult(remotePrivateKey, .ecdhKeyExchangeStandard, localPublicKey, [:] as NSDictionary, nil)! as Data
print(localShareSecret == remoteShareSecret)
// printed: true
print(localShareSecret.count)
// printed: 32

This simulates ECDH by having the ‘local’ and ‘remote’ peers both generate key pairs and their using the opposite combinations to build shared secrets. As you can see, the shared secrets match and has the expected size.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the reply. You are absolutely right the code I have shared is not full implementation but just a snippet. The point being I was trying to find out if my logic of generating the shared secret is the right way. Currently i am generating a private key using 3rd party library https://github.com/104corp/JOSE-ECDH-ES-Swift


In my case I am generating a local key pair using below


let publicKey = ECPublicKey(crv: .P256,
                                            x: xPubvalue,
                                            y: yPubvalue)

let keyPair = try! generateECKeyPair(curveType: .P256)
let sharedZ = try! JweHelper.ecdhDeriveBits(ecPrivJwk: keyPair.getPrivate(),
                                                    ecPubJwk: publicKey,
                                                    bitLen: 256)


and the public key being created using x and y of stand EC public key. The reason for using this 3rd pary library is to save time converting the objects which is used inside the ecdhDeriveBits to generate shared secret.


Questions

1. Do you think the above approach is any different or wrong,

2. Looking at your implementation how can I use a public key x and y instead of using SecKeyCopyPublicKey to generate a public key ?


Also the implemettion which is working fine with chilkat, I can share the code but its too large to share the implementaion as the code is part of the project and other dependencies, Is there any other means I can share or speak directly to a Apple Developer if needed to get assitance on this ?


Thanks

1. Do you think the above approach is any different or wrong,

I’m not really in a position to comment on your use of third-party libraries.

2. Looking at your implementation how can I use a public key x and y instead of using

SecKeyCopyPublicKey
to generate a public key ?

It’s hard to say given the limited details you’ve provided. Are

xPubvalue
and
yPubvalue
arrays of bytes? Or
Data
values? If so, you may be able to concatenate them with an 0x04 to generate an external representation that you can pass to
SecKeyCreateWithData
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"