在Swift中使用CommonCrypto发布解密 [英] Issue decrypting with CommonCrypto in Swift

查看:374
本文介绍了在Swift中使用CommonCrypto发布解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Swift-only crypt / decrypt 中使用 / code>和 NSData ,并且crypt部分工作在@Zaph提供的答案链接的问题:在Swift中使用CCCrypt(CommonCrypt)



隐藏输出使用良好的旧NSData + AESCrypt.m类别在Objective-C中测试



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

 扩展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 .length)
let操作: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)
如果UInt32(cryptStatus)== UInt32(kCCSuccess){
bufferData.length = Int(numBytesEncrypted)//请求调整缓冲区大小
return bufferData as NSData
} else {
println(Error:\(cryptStatus))
return NSData()
}
} b
$ b 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操作: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)//请求调整缓冲区大小
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)
//并非所有数据都是UTF-8字符串,因此使用Base64
let base64cryptString = encryptedData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
return base64cryptString
}

func AES256DecryptStringWithKey(key:String) - > String {
let data:NSData! =(self as NSString).dataUsingEncoding(NSUTF8StringEncoding)as NSData!
let decryptptedData = data.AES256DecryptDataWithKey(key)
//并非所有数据都是UTF-8字符串,因此使用Base64
let base64decryptString = decryptptedData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
return base64decryptString
}
}

正如你可以看到 String.encryptStringWithKey()调用 NSData.encryptDataWithKey()。因此扩展适用于两种类型 String NSData



<$
let key =12345678901234567890123456789012
println(Original String:\\)pre> let string:String =不要尝试阅读此文本。 \\(串));
let encryptedString = string.AES256EncryptStringWithKey(key)
println(Encrypted String:\(encryptedString))
let decryptedString = encryptedString.AES256DecryptStringWithKey(key)
println解密字符串:\(decryptedString))

任何帮助将不胜感激

解决方案

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



最佳做法是使用随机iv的CBC模式。 iv通常预先处理加密数据,因此解密可以在解密之前分离iv和数据。



不要使用NSData + AESCrypt.m,它没有维护,是NSData上的一个类,不支持ARC。考虑对目标C使用 RNCryptor ,它会被积极维护。



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



这是我做的调用:
NSString * keyString = @12345678901234567890123456789012;

  NSString * message = @不要尝试阅读此文本。 
NSData * data = [message dataUsingEncoding:NSUTF8StringEncoding];

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

输出:

 code> 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& 

这只是让所有输入都相同的问题:operation,algorithm,options,keyBytes ,keyLength,dataBytes,dataLength和iv(如果为非ECB模式)。 CCCrypt 只是一个函数调用,就是这样。



放入 NSLog()语句,最好是十六进制转储数据和字符串。



相信与否,这是电子安全的简单部分。


I am working in a Swift-only crypt/decrypt Extension for String and NSData, and the crypt part is working based in the answer provided by @Zaph in the linked question: Issue using CCCrypt (CommonCrypt) in Swift

The crypt output was tested using the good old NSData+AESCrypt.m Category in Objective-C

I have been working in the decrypt part with an issue: The code compiles and runs fine, but the result is not the expected text originally encrypted.

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
    }
}

As you can see the String.encryptStringWithKey() calls the NSData.encryptDataWithKey(). so the Extensions work for both types 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)")

Any help will be appreciated

解决方案

The difference is that NSData+AESCrypt.m is using CBC mode (the default) with an iv of NULL. The code in the question is using ECB mode.

Best practice is to use CBC mode with a random iv. The iv is typically pre-pended to the encrypted data so the decryption can separate the iv and data prior to decryption.

Do not use NSData+AESCrypt.m, it has not been maintained, is a category on NSData, does not support ARC. Consider RNCryptor for Objective-C, it is actively maintained.

This is the change I made in "NSData+AESCrypt.m", method AES256EncryptWithKey: kCCOptionPKCS7Padding + kCCOptionECBMode. I added kCCOptionECBMode, that's all.

Here is the call I made: 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);

Output:

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

Which is the same as from the above code (the same as the previous question):

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

It is just a matter of getting all of the inputs the same: operation, algorithm, options, keyBytes, keyLength, dataBytes, dataLength and iv if non ECB mode. CCCrypt is just a function call, that's all. Put in the same input, get the same output.

Put in NSLog() statements, preferably hex dumps for data and strings. Compare and fix as needed.

Believe it or not, this is the easy part of electronic security.

这篇关于在Swift中使用CommonCrypto发布解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆