skip to Main Content

I am trying to decrypt data with Swift CryptoKit that I have encrypted with php using openssl_encrypt() chacha20-poly1305. Encrypting works, but when decrypting I get the error: incorrectParameterSize (Swift: error 1, line 10).

PHP encryption using openssl_encrypt:

<?php
$plaintext = "Hello World";
$key = base64_decode("O7IaTssF6RKgc84b8daAHojiveFY4vyQ4zKRZv3APKc=");
$nonce = base64_decode("MmTNTi+MmTNTi+fB");
$encrypted = 
openssl_encrypt(
    $plaintext,
    'chacha20-poly1305',
    $key,
    0,
    $nonce
);

echo $encrypted;

Swift decryption using CryptoKit

import CryptoKit
import Foundation
let encoded_data = "OG54KzRFKytSSmQ5d0M4PQ=="
let encoded_nonce = "MmTNTi+MmTNTi+fB"
let encoded_key = "O7IaTssF6RKgc84b8daAHojiveFY4vyQ4zKRZv3APKc="
let data = Data(base64Encoded: encoded_data)!
let nonce = Data(base64Encoded: encoded_nonce)!
let key = SymmetricKey(data: Data(base64Encoded: encoded_key)!)
do{
    let box = try ChaChaPoly.SealedBox(combined: data.base64EncodedData())
    do{
        let decryptedData = try ChaChaPoly.open(box,using: key)
        let decryptedString = String(decoding: decryptedData, as: UTF8.self)
        print("Decrypted string: (decryptedString)")
    }catch{
        print("error 2: (error)")
    }
}catch{
    print("error 1: (error)")
}

I also tried using sodium_crypto_aead_chacha20poly1305_encrypt() to encrypt, which resulted in the error "authenticationFailure" (Swift: error 2, line 12).

PHP encryption using sodium_crypto_aead_chacha20poly1305_encrypt:

<?php

$plaintext = "Hello World";
$key = base64_decode("O7IaTssF6RKgc84b8daAHojiveFY4vyQ4zKRZv3APKc=");
$nonce = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES);
$encrypted = sodium_crypto_aead_chacha20poly1305_encrypt($plaintext,"",$nonce, $key);

echo "Data:" . base64_encode($encrypted) . "n";
echo "Nonce:" . base64_encode($nonce);

2

Answers


  1. In a real-world scenario, you would need to validate the data, nonce, and key before attempting to decrypt the data to ensure that they have not been modified or corrupted.

    import CryptoKit
    import Foundation
    
    let encodedData = "OG54KzRFKytSSmQ5d0M4PQ=="
    let encodedNonce = "MmTNTi+MmTNTi+fB"
    let encodedKey = "O7IaTssF6RKgc84b8daAHojiveFY4vyQ4zKRZv3APKc="
    
    guard let data = Data(base64Encoded: encodedData),
          let nonce = Data(base64Encoded: encodedNonce),
          let key = SymmetricKey(data: Data(base64Encoded: encodedKey)) else {
        print("Invalid data, nonce, or key")
        return
    }
    
    do {
        let box = try ChaChaPoly.SealedBox(combined: data)
        let decryptedData = try ChaChaPoly.open(box, using: key)
        let decryptedString = String(decoding: decryptedData, as: UTF8.self)
        print("Decrypted string: (decryptedString)")
    } catch {
        print("Decryption failed: (error)")
    }
    
    Login or Signup to reply.
  2. ChaCha20-Poly1305 is authenticated encryption, i.e. during encryption a tag is generated in addition to the ciphertext, which is required for authentication during decryption.
    The PHP/OpenSSL code does not generate this tag due to a bug, which is therefore missing when decrypting with the Swift code, so decryption fails (PHP/OpenSSL internally decryption works). More details about the bug are described in #76935.


    PHP/Sodium, on the other hand, works:

    $plaintext = 'secret message';
    $key = base64_decode('XohImNooBHFR0OVvjcYpJ3NgPQ1qq73WKhHvch0VQtg=');
    $nonce = base64_decode('F6u88lkmmz8Rrjvf'); // for testing only, otherwise: random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES);
    $nonceCtTag = $nonce . sodium_crypto_aead_chacha20poly1305_ietf_encrypt($plaintext, '', $nonce, $key);
    print(base64_encode($nonceCtTag) . PHP_EOL); // F6u88lkmmz8RrjvfJ22r4vrKmWuY8a2DNpjUKZVUi9Wp9QjZVgheBihn
    

    The test data is from here, i.e. was generated with CryptoKit’s ChaCha20-Poly1305, so decryption with your Swift code should give the original plaintext (the key corresponds to the SHA256 hash of password).

    Note that sodium_crypto_aead_chacha20poly1305_ietf_encrypt() returns as result the concatenation of ciphertext and tag, so that $nonceCtTag corresponds to the combined representation (nonce|ciphertext|tag) to be passed in SealedBox(combined: ...).


    The code above uses sodium_crypto_aead_chacha20poly1305_ietf_encrypt() with a 12 bytes nonce instead of sodium_crypto_aead_chacha20poly1305_encrypt() with an 8 bytes nonce (see here for more details regarding the different variants).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search