解密SWIFT中的Fernet加密文本(PYTHON)。

0 人关注

我在Python中使用密码学生成了一个加密的文本

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='

现在我试图在Swift中解密,但没有成功。 到目前为止,我已经尝试了CryptoSwift的以下方法。

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==")
            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:

WaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetFinKSyMjxw RBGKSwa7AluNJYhw invalidData

希望得到任何帮助

2 个评论
你是否看了一下 spec ?我没有看到任何HMAC,仅举一个问题。
Fernet在CBC模式下使用128比特的PKCS7填充。它没有HMAC。如果你看到代码,没有HMAC。
python
swift
xcode
cryptography
cryptoswift
Syed Faizan
Syed Faizan
发布于 2021-07-31
1 个回答
Bram
Bram
发布于 2021-08-02
已采纳
0 人赞同

我已经成功地让你的密码文本被解密,只使用苹果提供的来源。如果你支持iOS 13及以上版本,我建议你使用 CryptoKit 来验证HMAC,但现在,我已经采用了完整的 CommonCrypto 方案。

首先是一个小的扩展,从base64 URL字符串中创建 Data

import Foundation
import CommonCrypto
extension Data {
    init?(base64URL base64: String) {
        var base64 = base64
            .replacingOccurrences(of: "-", with: "+")
            .replacingOccurrences(of: "_", with: "/")
        if base64.count % 4 != 0 {
            base64.append(String(repeating: "=", count: 4 - base64.count % 4))
        self.init(base64Encoded: base64)

解密函数有点晦涩难懂,但它支持非常古老的CommonCrypto的语法。withUnsafeBytes的语法会更干净,但这是一个快速的变通方法。

func decrypt(ciphertext: Data, key: Data, iv: Data) -> Data {
    var decryptor: CCCryptorRef?
    defer {
        CCCryptorRelease(decryptor)
    var key = Array(key)
    var iv = Array(iv)
    var ciphertext = Array(ciphertext)
    CCCryptorCreate(CCOperation(kCCDecrypt), CCAlgorithm(kCCAlgorithmAES), CCOptions(kCCOptionPKCS7Padding), &key, key.count, &iv, &decryptor)
    var outputBytes = [UInt8](repeating: 0, count: CCCryptorGetOutputLength(decryptor, ciphertext.count, false))
    CCCryptorUpdate(decryptor, &ciphertext, ciphertext.count, &outputBytes, outputBytes.count, nil)
    var movedBytes = 0
    var finalBytes = [UInt8](repeating: 0, count: CCCryptorGetOutputLength(decryptor, 0, true))
    CCCryptorFinal(decryptor, &finalBytes, finalBytes.count, &movedBytes)
    return Data(outputBytes + finalBytes[0 ..< movedBytes])

然后是HMAC。如果可以的话,我建议你使用CryptoKit。这个功能当然是固定的,可能有办法让这个功能变得动态。不过对于Fernet来说,只支持SHA256。

func verifyHMAC(_ mac: Data, authenticating data: Data, using key: Data) -> Bool {
    var data = Array(data)
    var key = Array(key)
    var macOut = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
    CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), &key, key.count, &data, data.count, &macOut)
    return Array(mac) == macOut

所有这些都归结为以下代码。请注意,我没有检查版本和/或时间戳,这应该根据规范来做。

let fernetKey   = Data(base64URL: "3b-Nqg6ry-jrAuDyVjSwEe8wrdyEPQfPuOQNH1q5olE=")!
let signingKey  = fernetKey[0 ..< 16]
let cryptoKey   = fernetKey[16 ..< fernetKey.count]
let fernetToken = Data(base64URL: "gAAAAABhBRBGKSwa7AluNJYhwWaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetFinKSyMjxwWaPRnXVSVqz5QqpUXp6h-34_TL7BaDs=")!
let version     = Data([fernetToken[0]])
let timestamp   = fernetToken[1 ..< 9]
let iv          = fernetToken[9 ..< 25]
let ciphertext  = fernetToken[25 ..< fernetToken.count - 32]
let hmac        = fernetToken[fernetToken.count - 32 ..< fernetToken.count]