EC Key Decryption Fails with error "ECpriv sharedsecret: bad public key"

I'm using an EC public key generated on iOS to encrypt some text on our server. The encryption works fine and I'm using the base64 encoded cipher text on the device to decrypt it using the private key. However, the decryption fails with this error:

Code Block language
"algid:encrypt:ECIES:ECDHC:KDFX963:SHA256:AESGCM-KDFIV: algorithm not supported by the key <SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPrivateKey, version: 4, block size: 256 bits, addr: 0x7f9d1f108270>" UserInfo={numberOfErrorsDeep=1, NSDescription=algid:encrypt:ECIES:ECDHC:KDFX963:SHA256:AESGCM-KDFIV: algorithm not supported by the key <SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPrivateKey, version: 4, block size: 256 bits, addr: 0x7f9d1f108270>, NSUnderlyingError=0x60000072dec0 {Error Domain=NSOSStatusErrorDomain Code=-50 "ECpriv sharedsecret: bad public key (err -7)" UserInfo={numberOfErrorsDeep=0, NSDescription=ECpriv sharedsecret: bad public key (err -7)}}}


The code to encrypt on the server is:

Code Block java
private static String encrypt(String plaintext, PublicKey publicKey, String curveName)
throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] inputBytes = plaintext.getBytes();
org.bouncycastle.jce.spec.IESParameterSpec params = new IESParameterSpec(null, null, 128, 128, null);
IESCipherGCM cipher = new IESCipherGCM(
new IESEngineGCM(
new ECDHBasicAgreement(),
new KDF2BytesGenerator(new SHA256Digest()),
new AESGCMBlockCipher()), 16);
cipher.engineInit(Cipher.ENCRYPT_MODE, publicKey, params, new SecureRandom());
byte[] cipherResult = cipher.engineDoFinal(inputBytes, 0, inputBytes.length);
return Base64.getUrlEncoder().encodeToString(cipherResult);
}


The following method takes the base64 encoded string returned by the server and calls the decryption method using the private key -

Code Block Swift
   func handleDecrypt() -> Void {
    let data = textField.text?.data(using: .utf8)
    let clearText = encryptionManager.decryptData(cipherTextData: data, key: aliceKey)
    print(clearText!)
  }


Here's the decrypt method -

Code Block Swift
public func decryptData(cipherTextData: Data!, key: SecKey!) -> String? {
    let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
    guard SecKeyIsAlgorithmSupported(key!, .decrypt, algorithm) else {
      print("algorithm not supported")
      return nil
    }
    var error: Unmanaged<CFError>?
    let clearTextData = SecKeyCreateDecryptedData(key!,
                           algorithm,
                           cipherTextData! as CFData,
                           &error) as Data?
    guard clearTextData != nil else {
      print("decryption failed")
      return nil
    }
       
    let clearText = String(decoding: clearTextData!, as: UTF8.self)
    return clearText
  }

Replies

eskimo1@apple.com do you have any idea about this?
I’m not super familiar with the Java side of this but looking at your Java code it seems to be using KDF2 as the key derivation function (KDF) but .eciesEncryptionCofactorVariableIVX963SHA256AESGCM expects ANSI X9.63 KDF. Specifically, the doc comment for kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in <Security/SecKey.h> says:

with key negotiated by
kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256

and the doc comment for kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256 says:

and apply ANSI X9.63 KDF

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"