I am trying to use RSA to encrypt some data on MacOS using SecKeyCreateEncryptedData() and then Decrypt the data on Linux using OpenSSL.
When I call SecKeyCreateEncryptedData I am returned "the RSA encrypted session key, the AES encrypted data, and a 16-byte AES-GCM tag into a block of data" as described in:
To decrypt the data using OpenSSL I require those 3 parts plus the IV(AKA, nonce value):
https://shanetully.com/2012/06/openssl-rsa-aes-and-c/
For that example there is a further call to:
```
EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, 16, ref_TAG);
```
To generate the GCM tag.
My question is how do i get the IV that was used in SecKeyCreateEncryptedData to create the AES encrypted data so that i can pass it to openSSL to decrypt the data?
This is being done on MacOS using Swift 4.2. Below is a short code example demonstrating what I am trying to do:
```
import OpenSSL
// encrypt using security
var response: Unmanaged<CFError>? = nil
let encryptedData = SecKeyCreateEncryptedData(<SecPublicKey>, SecKeyAlgorithm.rsaEncryptionOAEPSHA256AESGCM, <data> as CFData, &response)
if response != nil {
print(response?.takeRetainedValue())
}
// decrypt using OpenSSL
var evp_key = EVP_PKEY_new()
let _ = EVP_PKEY_set1_RSA(evp_key, <PrivateKeyPointer>)
let rsaDecryptCtx = EVP_CIPHER_CTX_new_wrapper()
let encKeyLength = Int(EVP_PKEY_size(evp_key))
// iv is the only missing value for decoding.
// encryptedKey used here
let _ = EVP_OpenInit(rsaDecryptCtx, EVP_aes_128_gcm(), <encryptedKey>, <encryptedKeyLength>, <iv>, evp_key)
// encryptedData used here
let _ = EVP_DecryptUpdate(rsaDecryptCtx, decrypted, &processedLen, encryptedData, Int32(encryptedData.count)
var decMsgLen = processedLen
// gcm tag used here
EVP_CIPHER_CTX_ctrl(rsaDecryptCtx, EVP_CTRL_GCM_SET_TAG, 16, <gcm tag>)
let _EVP_OpenFinal(rsaDecryptCtx, decrypted.advanced(by: Int(decMsgLen)), &processedLen)
decMsgLen += processedLen
let decryptedData = Data(bytes: decrypted, count: Int(decMsgLen))
```
Any help in understanding how I can get the IV value would be greatly appreciated.
Generally, the authentication data is required during decryption.
To summarize:
You create an RSA key pair (< 4096 bits for AES128, >= 4096 for AES256) and have some data you want to encrypt.
You pass your data and the public key to the SecKeyCreateEncryptedData function. The output of the function is some data.
Internally, the function uses a 0 IV (as the AES key is randomly generated) and this is regarded secure. Also internally, the random AES key is encrypted with the provided public key using OAEP SHA-256. The hashing function is required for the padding. Also internally, the public key DER data (the output from SecKeyCopyExternalRepresentation) is used as authentication data for the AES GCM operation.
The output data is build up as follows:
[256 or 512 bytes encrypted key data][ 256 or 512 ..< output.count - 16][output.count - 16 ..< output.count]
I'm unsure if the tag is 16 bytes for AES256, but I believe it is (don't quote me on that though).
In order to decrypt, follow these steps:
- Decrypt the first portion of the SecKeyCreateEncryptedData (either 256/512 bytes depending on RSA key size) with the private key and OAEP SHA-256 padding. You now have the bytes that make up the key.
- Export the public key to DER format.
- Create a nonce/IV of 16 '0' bytes.
- Use your requested OpenSSL implementation
So something like:
d = OpenSSL(nonce, output[256 or 512 ..< output.count], authentication data)
d = OpenSSL('0' iv, output message without the encrypted key, public key DER data)
This should provide you with the decrypted data. Hope this helps!