我试图用Swift CryptoKit解密数据,我使用openssl_encrypt()
chacha20-poly1305
用php加密。加密工作,但当解密我得到错误:incorrectParameterSize
(Swift:错误1,第10行)。
PHP加密使用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;
使用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)")
}
我也尝试使用sodium_crypto_aead_chacha20poly1305_encrypt()
加密,导致错误"authenticationFailure"(Swift: error 2, line 12).
PHP加密使用sodium_crypto_aead_chachha20poly1305_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);
在实际场景中,您需要在尝试解密数据之前验证数据、nonce和密钥,以确保它们未被修改或损坏。
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)")
}
ChaCha20-Poly1305是经过身份验证的加密,即在加密过程中除了密文之外还生成一个标记,在解密过程中需要进行身份验证。
PHP/OpenSSL代码由于一个bug没有生成这个标签,因此在使用Swift代码解密时丢失了这个标签,所以解密失败(PHP/OpenSSL内部解密工作)。有关该bug的详细信息请参见#76935。
PHP/钠,另一方面,工作:
$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
测试数据来自这里,即使用CryptoKit的ChaCha20-Poly1305生成,因此使用Swift代码解密应该给出原始明文(密钥对应于password
的SHA256哈希)。
注意,sodium_crypto_aead_chacha20poly1305_ietf_encrypt()
返回密文和标签的连接结果,因此$nonceCtTag
对应于SealedBox(combined: ...)
中传递的combined
表示(nonce|ciphertext|tag)。
上面的代码使用sodium_crypto_aead_chacha20poly1305_ietf_encrypt()
和一个12字节的nonce代替sodium_crypto_aead_chacha20poly1305_encrypt()
和一个8字节的nonce(见这里更多的细节关于不同的变体)。