Reputation: 1
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);
Upvotes: 0
Views: 422
Reputation: 49121
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).
Upvotes: 0
Reputation: 345
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)")
}
Upvotes: 0