在 Swift 中使用 CommonCrypto 解密时出现问题

2024-05-18

我在一家Swift-only加密/解密Extension for String and NSData,并且 crypt 部分的工作基于 @Zaph 在链接问题中提供的答案:在 Swift 中使用 CCCrypt (CommonCrypt) 时出现问题 https://stackoverflow.com/questions/25754147/issue-using-cccrypt-commoncrypt-in-swift

使用 Objective-C 中的旧 NSData+AESCrypt.m 类别测试了 crypt 输出

我一直在解密部分遇到一个问题:代码编译并运行良好,但结果不是最初加密的预期文本。

extension NSData {
    func AES256EncryptDataWithKey(key: String) -> NSData {
        let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let keyBytes         = UnsafePointer<UInt8>(keyData.bytes)
        let keyLength        = size_t(kCCKeySizeAES256)
        let dataLength    = UInt(self.length)
        let dataBytes     = UnsafePointer<UInt8>(self.bytes)
        let bufferData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
        var bufferPointer = UnsafeMutablePointer<UInt8>(bufferData.mutableBytes)
        let bufferLength  = size_t(bufferData.length)
        let operation: CCOperation = UInt32(kCCEncrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
        var numBytesEncrypted: UInt = 0
        var cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            keyBytes, keyLength,
            nil,
            dataBytes, dataLength,
            bufferPointer, bufferLength,
            &numBytesEncrypted)
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            bufferData.length = Int(numBytesEncrypted) // Requiered to adjust buffer size
            return bufferData as NSData
        } else {
            println("Error: \(cryptStatus)")
            return NSData()
        }
    }

    func AES256DecryptDataWithKey(key: String) -> NSData {
        let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let keyBytes         = UnsafePointer<UInt8>(keyData.bytes)
        let keyLength        = size_t(kCCKeySizeAES256)
        let dataLength    = UInt(self.length)
        let dataBytes     = UnsafePointer<UInt8>(self.bytes)
        let string = self.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
        let bufferData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
        var bufferPointer = UnsafeMutablePointer<UInt8>(bufferData.mutableBytes)
        let bufferLength  = size_t(bufferData.length)
        let operation: CCOperation = UInt32(kCCDecrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
        var numBytesDecrypted: UInt = 0
        var cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            keyBytes, keyLength,
            nil,
            dataBytes, dataLength,
            bufferPointer, bufferLength,
            &numBytesDecrypted)            
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            bufferData.length = Int(numBytesDecrypted) // Requiered to adjust buffer size
            return bufferData as NSData
        } else {
            println("Error: \(cryptStatus)")
            return NSData()
        }
    }
}

extension String {        
    func AES256EncryptStringWithKey(key: String) -> String {
        let data = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let encryptedData = data.AES256EncryptDataWithKey(key)
        // Not all data is a UTF-8 string so Base64 is used
        let base64cryptString = encryptedData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
        return base64cryptString
    }

    func AES256DecryptStringWithKey(key: String) -> String {
        let data: NSData! = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let decryptedData = data.AES256DecryptDataWithKey(key)            
        // Not all data is a UTF-8 string so Base64 is used
        let base64decryptString = decryptedData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
        return base64decryptString
    }
}

正如你所看到的String.encryptStringWithKey()称为NSData.encryptDataWithKey()。所以扩展适用于这两种类型String and NSData

    let string: String = "Don´t try to read this text. Top Secret Stuff"
    let key = "12345678901234567890123456789012"
    println("Original String  : \(string)");
    let encryptedString = string.AES256EncryptStringWithKey(key)
    println("Encrypted String : \(encryptedString)")        
    let decryptedString = encryptedString.AES256DecryptStringWithKey(key)
    println("Decrypted String: \(decryptedString)")

任何帮助将不胜感激


不同之处在于 NSData+AESCrypt.m 使用 CBC 模式(默认),iv 为 NULL。问题中的代码使用 ECB 模式。

最佳实践是将 CBC 模式与随机 iv 结合使用。 iv 通常附加在加密数据之前,因此解密可以在解密之前将 iv 和数据分开。

不要使用NSData+AESCrypt.m,它还没有维护,是NSData上的一个类别,不支持ARC。考虑RNC加密器 https://github.com/RNCryptor/RNCryptor对于 Objective-C,它是积极维护的。

这是我在“NSData+AESCrypt.m”中所做的更改,方法AES256EncryptWithKey: kCCOptionPKCS7Padding + kCCOptionECBMode。我添加了kCCOptionECBMode, 就这样。

这是我拨打的电话: NSString *keyString = @"12345678901234567890123456789012";

NSString *message = @"Don´t try to read this text. Top Secret Stuff";
NSData   *data    = [message dataUsingEncoding:NSUTF8StringEncoding];

NSData *crypData = [data AES256EncryptWithKey:keyString];
NSLog(@"crypData: %@", crypData);

输出:

crypData: <118a32dc c23f7caa 883abc3c 1c7f0770 e200016b 2737acfa 17bb96fb a02b02a7 c147603b 06acd863 94bb8ff2 6cb14515>

与上面的代码相同(与上一个问题相同):

cryptData = <118a32dc c23f7caa 883abc3c 1c7f0770 e200016b 2737acfa 17bb96fb a02b02a7 c147603b 06acd863 94bb8ff2 6cb14515>

这只是使所有输入相同的问题:操作、算法、选项、keyBytes、keyLength、dataBytes、dataLength 和 iv(如果是非 ECB 模式)。CCCrypt只是一个函数调用,仅此而已。输入相同的输入,得到相同的输出。

Put in NSLog()语句,最好是数据和字符串的十六进制转储。根据需要进行比较和修复。

不管你相信与否,这是电子安全中最简单的部分。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Swift 中使用 CommonCrypto 解密时出现问题 的相关文章

随机推荐