微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 SWIFT 中解密 Fernet 加密文本 (PYTHON)

如何解决在 SWIFT 中解密 Fernet 加密文本 (PYTHON)

我使用密码学生成一个加密文本是 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)

加密信息:

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

输出

16
WaHrQGwAA8UpMH8Wtw3tEoTD2E_-nbeoAvxbtBpFiC0ZjbVne_ZetfinkSyMjxw
RBGKSwa7AluNJYhw
A
B
invalidData

任何帮助将不胜感激

解决方法

我仅使用 Apple 提供的资源就设法解密了您的密文。如果您支持 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)
    }
}

decrypt 函数有点晦涩,但它支持非常古老的 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,&outputBytes,outputBytes.count,nil)
    
    var movedBytes = 0
    var finalBytes = [UInt8](repeating: 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),&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]

let plainText = decrypt(ciphertext: ciphertext,key: cryptoKey,iv: iv)
print(plainText,String(data: plainText,encoding: .utf8) ?? "Non utf8")
print(verifyHMAC(hmac,authenticating: version + timestamp + iv + ciphertext,using: signingKey))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。