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:
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:
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 -
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 -
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: UnmanagedCFError?
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
}
Post
Replies
Boosts
Views
Activity
I'm trying to generate a JWK from an EC public key that I want to send to my server. The issue I'm running into is that the base64 URL Encoded string representation of the x and y coordinates from the external representation of the EC public key seems to be invalid on the server and I get an error saying that the points are not on the curve.
Here's what I'm doing to generate the base64 URL encoded string from the x and y coords:
(NSArray<NSString *> *)getBase64EncodedCoordinatesFromECPublicKey:(SecKeyRef)publicKey error:(out NSError **)error{
CFErrorRef copyPublicKeyError = NULL;
NSData* keyData = (NSData*)CFBridgingRelease(
SecKeyCopyExternalRepresentation(publicKey, &copyPublicKeyError)
);
if (!keyData) {
NSError *err = CFBridgingRelease(copyPublicKeyError);
NSLog(@"%@", err);
return nil;
}
NSString *xbytes;
NSString *ybytes;
CFByteOrder byteOrder = CFByteOrderGetCurrent();
NSLog(@"%ld",(long)byteOrder);
NSData *xData = [keyData subdataWithRange:NSMakeRange(1, 32)];
NSData *xDataRev = [self reverseData:xData];
NSString *xEncoded = [OIDTokenUtilities encodeBase64urlNoPadding:xDataRev];
NSData *yData = [keyData subdataWithRange:NSMakeRange(33, 32)];
NSData *yDataRev = [self reverseData:yData];
NSString *yEncoded = [OIDTokenUtilities encodeBase64urlNoPadding:yDataRev];
xbytes = [OIDTokenUtilities encodeBase64urlNoPadding:xData];
ybytes = [OIDTokenUtilities encodeBase64urlNoPadding:yData];
NSArray *coordinates = @[xbytes, ybytes];
return coordinates;
}
The byte order on iOS seems to be little-endian (byteOrder above is 1 == CFByteOrderLittleEndian) and the JWK RFC 7517 Appendix A says it expects the big-endian values for x and y. So, I tried swapping the bytes to create a big-endian representation of the data. But, neither works.
I'd appreciate any insight or help with this.