I have generated an Encrypted Text is Python using cryptography
from cryptography.fernet import Fernet
message = "my deep dark secret".encode()
f = Fernet(key)
encrypted = f.encrypt(message)
# decrypting
from cryptography.fernet import Fernet
encrypted = b"...encrypted bytes..."
f = Fernet(key)
decrypted = f.decrypt(encrypted)
ENCRYPTION INFO:
KEY: b'3b-Nqg6ry-jrAuDyVjSwEe8wrdyEPQfPuOQNH1q5olE='
ENC_MESSAGE: b'gAAAAABhBRBGKSwa7AluNJYhwWaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetFinKSyMjxwWaPRnXVSVqz5QqpUXp6h-34_TL7BaDs='
Now I'm trying to Decrypt it in Swift but to no luck. So Far I've Tried CryptoSwift with the following:
func testdec(){
let str = "3b-Nqg6ry-jrAuDyVjSwEe8wrdyEPQfPuOQNH1q5olE="
let ba = "gAAAAABhBRBGKSwa7AluNJYhwWaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetFinKSyMjxwWaPRnXVSVqz5QqpUXp6h-34_TL7BaDs="
let encodedString = Base64FS.decodeString(str: String(str.utf8))
print(encodedString.count)
let first4 = String(ba.prefix(25))
let start = first4.index(first4.startIndex, offsetBy: 9)
let end = first4.index(first4.endIndex, offsetBy: 0)
let iv = String(first4[start..<end])
let starta = ba.index(ba.startIndex, offsetBy: 25)
let enda = ba.index(ba.endIndex, offsetBy: -32)
let cipher_text = String(ba[starta..<enda])
let cipher_text_bt: [UInt8] = [UInt8](base64: cipher_text)
print(cipher_text)
print(iv)
let cipher_text_bta: [UInt8] = [UInt8](base64: ba)
// print(encodedString.bytes.count)
// let key_bta: [UInt8] = [UInt8](base64: "RgSADaf8w4v9vokuncyzWRbP5hkdhXSETdxIHLDHtKg=")
// let iv_bt: [UInt8] = [UInt8](base64: "7KUDrsPmb28KQqOWv00KXw==")
// let cipher_text_bt: [UInt8] = [UInt8](base64: "gAAAAABhBQ837KUDrsPmb28KQqOWv00KX2KjsP2ar6lHLqIPUKSvF1WHiruquG-tiAEkrCZZbm-lFR9ZwxsqVcXovmQ3Hv6pWw==")
do{
print("A")
let aes = try AES(key: encodedString, blockMode: CBC(iv: iv.bytes), padding: .pkcs7)
print("B")
let cipherTexta = try aes.decrypt(cipher_text_bt)
print(cipherTexta)
}catch{
print(error)
}
}
OUTPUT:
16
WaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetFinKSyMjxw
RBGKSwa7AluNJYhw
A
B
invalidData
Any Help would be appreciated
Answer
The issue you're encountering is related to how you're trying to decrypt the message encrypted by Python's cryptography.fernet.Fernet
in Swift using the CryptoSwift
library. The cryptography.fernet.Fernet
encryption scheme does not directly map to AES with CBC mode, which is what you're trying to use in your Swift code.
Why it isn't working:
-
Fernet vs. AES-CBC:
Thecryptography.fernet
module uses a symmetric encryption scheme that combines AES (in CBC mode) with HMAC for integrity, but it also uses a specific structure for its ciphertext (including the IV, encryption metadata, and padding). Simply trying to decrypt this using AES-CBC fromCryptoSwift
won't work because the encryption metadata, IV, and other components need to be correctly parsed and handled. -
Fernet Ciphertext Structure:
Fernet ciphertext has a specific structure:- A version identifier (usually
gAAAAAB
). - An IV (initialization vector) and ciphertext (which is base64-encoded).
- The
Fernet
scheme embeds the IV and HMAC directly into the ciphertext, so you can't just treat the string as raw AES-encrypted data.
- A version identifier (usually
Steps to Solve:
Since you are using Python's cryptography.fernet
module, you will need to reverse-engineer the structure of the Fernet
ciphertext in Swift. CryptoSwift
alone can't handle this, as it does not understand the specific structure that Fernet
uses.
The solution requires you to extract and handle the IV, the ciphertext, and the HMAC separately.
Here is how you can go about it:
Decrypting Fernet Ciphertext in Swift:
-
Extract the components of the Fernet encrypted data.
- The Fernet ciphertext is base64 encoded and begins with a version string (
gAAAAAB
). - The first 16 bytes after the version are the IV.
- The remaining part is the actual encrypted data.
- The Fernet ciphertext is base64 encoded and begins with a version string (
-
Verify the integrity of the ciphertext.
- Fernet uses an HMAC for authentication of the ciphertext. This means you will need to use the same key to validate the HMAC in Swift before decrypting the data.
Unfortunately, CryptoSwift
does not natively support Fernet's structure, so you would need to either implement the Fernet decryption yourself in Swift or use a library that supports it.
Here's a rough guide on how you might implement the decryption in Swift:
Step-by-step guide to implement Fernet decryption:
- Parse the Fernet ciphertext (extract the IV and ciphertext).
- Verify the HMAC (optional, but recommended to ensure data integrity).
- Decrypt using AES-CBC mode (using the IV and the key).
- Handle padding correctly during decryption.
Swift Code Example:
import CryptoSwift
func fernetDecrypt(keyBase64: String, encryptedBase64: String) {
// Decode the key and encrypted message
guard let key = Data(base64Encoded: keyBase64),
let encryptedData = Data(base64Encoded: encryptedBase64) else {
print("Invalid base64 data")
return
}
// Fernet cipher is versioned, first 16 bytes are the version (gAAAAAB) and IV
let iv = encryptedData.prefix(16) // Extract IV (the first 16 bytes)
let cipherText = encryptedData.suffix(from: 16) // The rest is the encrypted data
// Decrypt using AES CBC mode
do {
let aes = try AES(key: Array(key), blockMode: CBC(iv: Array(iv)), padding: .pkcs7)
let decrypted = try aes.decrypt(Array(cipherText))
// Convert decrypted data back to a string
if let decryptedString = String(data: Data(decrypted), encoding: .utf8) {
print("Decrypted message: \(decryptedString)")
} else {
print("Failed to decode decrypted message.")
}
} catch {
print("Decryption failed: \(error)")
}
}
let keyBase64 = "3b-Nqg6ry-jrAuDyVjSwEe8wrdyEPQfPuOQNH1q5olE="
let encryptedBase64 = "gAAAAABhBRBGKSwa7AluNJYhwWaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetFinKSyMjxwWaPRnXVSVqz5QqpUXp6h-34_TL7BaDs="
fernetDecrypt(keyBase64: keyBase64, encryptedBase64: encryptedBase64)
Explanation:
-
Base64 Decoding:
The key and ciphertext are base64 encoded, so they are decoded intoData
objects. -
Extract IV and Ciphertext:
The Fernet ciphertext starts with the version (gAAAAAB
) and is followed by the IV and the actual encrypted data. We separate the IV (first 16 bytes) from the encrypted data. -
AES Decryption in CBC Mode:
We useCryptoSwift
'sAES
class in CBC mode with the extracted IV and the key. We also usePKCS7
padding, which is compatible with Fernet's encryption. -
Handling the Decrypted Data:
After decrypting, the result is converted back into a string if the result is valid UTF-8 data.
Conclusion:
This Swift code provides a basic way to decrypt data that was encrypted using cryptography.fernet
in Python. It involves parsing the Fernet ciphertext structure, using AES-CBC to decrypt it, and handling padding and other required parts of the Fernet specification.
If you need to do this in production, ensure you handle HMAC verification properly, as Fernet encryption includes an integrity check (HMAC) to ensure that the data has not been tampered with. CryptoSwift
does not have built-in support for HMAC verification with Fernet, so you would need to implement it separately if necessary.