How do I decrypt my iOS CryptoKit encrypted value on the web service side?

Similar to this SO question: CryptoKit in Java

Or this SO question

Can I create my own SymmetricKey that we both know the string of? How can my value be decrypted in Java PhP or .NET? (I understand all these languages and can translate, the app is currently in php)

Apple's code from their playground:

let key = SymmetricKey(size: .bits256)     //<--- how to share with web service???
let themeSongPath = Bundle.main.path(forResource: "ThemeSong", ofType: "aif")!
let themeSong = FileManager.default.contents(atPath: themeSongPath)!


// below code is from Apple Playground
let encryptedContentAES = try! AES.GCM.seal(themeSong, using: key).combined
/*:
 The client decrypts using the same key, assumed to have been obtained out-of-band.
 */
let sealedBoxAES = try! AES.GCM.SealedBox(combined: encryptedContentAES!)

//HOW DO I DO THIS ON WEB SERVICE SIDE??? either in java or php or .net
let decryptedThemeSongAES = try! AES.GCM.open(sealedBoxAES, using: key)

assert(decryptedThemeSongAES == themeSong)
/*:
 You use a sealed box to hold the three outputs of the encryption operation: a nonce, the ciphertext, and a tag.
 */
// The nonce should be unique per encryption operation.
// Some protocols require specific values to be used, such as monotonically increasing counters.
// If none is passed during the during the encryption, CryptoKit randomly generates a safe value for you.

let nonceAES = sealedBoxAES.nonce

// The ciphertext is the encrypted plaintext, and is the same size as the original data.
let ciphertextAES = sealedBoxAES.ciphertext

// The tag provides authentication.
let tagAES = sealedBoxAES.tag

// The combined property holds the collected nonce, ciphertext and tag.
assert(sealedBoxAES.combined == nonceAES + ciphertextAES + tagAES)

Link to Playground

3

There are 3 best solutions below

0
On

After watching the WWDC video: WWDC Cryptokit 2019 video

At around 29 min 20 seconds they advise you to get the key data from the server initially. So you can just create the key by doing this:

Key Creation code

This way the server and the app have the same key. Or if you have control of both sides, you can know what your server key is and create the key with data from a string that you both know.

0
On

So I guess my real questions was how do I encrypt with cryptokit and decrypt with php (web app.

These 2 links helped me:

Swift CryptoKit and Browser

iOS CryptoKit in Java

SwiftCode:

func encryptAES_GCMCryptoKit()->String {
    let newkeyString1 = "I9GiP/cK4YKko8CeNF5F8X6/E6jt0QnV" //has to be 32 bytes for a 256 bit encryption or you will get the error key wrong size
    let newKey = SymmetricKey(data: newkeyString1.data(using: .utf8)!)
    let mySealedBox = try AES.GCM.seal(userString, using: newKey, nonce: iv)
    let iv = AES.GCM.Nonce()

do{
        let mySealedBox = try AES.GCM.seal(userString, using: newKey, nonce: iv)
        let dataToShare = mySealedBox.combined?.base64EncodedData()      
    
      // The combined property holds the collected nonce, ciphertext and tag.
        assert(mySealedBox.combined == nonceAES + ciphertextAES + tagAES)
}catch {
        print("error \(error)")
       
    }
}

Php code:

function decryptStringAES_GCM($combinedInput='')  //64 base encoded combine string
{
    $key = "I9GiP/cK4YKko8CeNF5F8X6/E6jt0QnV"; // <- 256 bit key - same key is on the swift side
    
    $combined = base64_decode($combinedInput);  //<- $combinedInput will be different every time even for the same value
    $tag = substr($combined, -16);
    $nonce = substr($combined, 0, 12);
    $length = strlen($combined)-16-12;      //take out tag and nonce (iv) lengths
    $cipherText = substr($combined, 12, $length);
    
    $res_non = openssl_decrypt($cipherText, 'aes-256-gcm', $key, OPENSSL_RAW_DATA| OPENSSL_NO_PADDING, $nonce, $tag); 
    
    return $res_non //decrypted string

You can also pass the key back to the server in a separate call like the first link does.

0
On

To correct this "full working code" from above:

I use a 32 character key. Take care your files are in UTF8.

Swift using CryptoKit

func encryptStringAES(_ string: String, key: String) throws -> String? {
        let keyData = SymmetricKey(data: Data(key.utf8))
        let encryptedData = try AES.GCM.seal(string.data(using: .utf8)!, using: keyData).combined
        return encryptedData?.base64EncodedString()
    }

PHP counterpart

function decryptStringAES($encryptedString, $key){

$combined = base64_decode($encryptedString);
$tag = substr($combined, -16);
$nonce = substr($combined, 0, 12);
$length = strlen($combined)-16-12;      
$cipherText = substr($combined, 12, $length);

$decryptedData = openssl_decrypt($cipherText, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $tag);
return $decryptedData;

}

The trick is, to rip apart the combined value coming from CryptoKit.