Ios 在Swift中使用CCCrypt(CommonCrypt)发布

Ios 在Swift中使用CCCrypt(CommonCrypt)发布,ios,objective-c,swift,cryptography,commoncrypto,Ios,Objective C,Swift,Cryptography,Commoncrypto,我正在将一个Objective-C类别(NSData+AESCrypt.m)移植到Swift,我发现了一个使用指针的问题。Swift中加密部分的代码编译正确,但生成运行时EXEC\u BAD\u ACCES错误 到目前为止,我掌握的代码是(我尽可能多地剖析代码): let key=“12345678900123456789012345678901234567890120” let keyLength=UInt(kCCKeySizeAES256+1) 让keyPointer=strdup(key)

我正在将一个Objective-C类别(NSData+AESCrypt.m)移植到Swift,我发现了一个使用指针的问题。Swift中加密部分的代码编译正确,但生成运行时EXEC\u BAD\u ACCES错误

到目前为止,我掌握的代码是(我尽可能多地剖析代码):

let key=“12345678900123456789012345678901234567890120”
let keyLength=UInt(kCCKeySizeAES256+1)
让keyPointer=strdup(key)//将key转换为
Swift 2.0

下面是一个示例
如果这不是所需要的,那么这些方法应该是一个很好的例子
注意:键字符串已转换为数据

将Security.framework添加到项目中
#import
添加到桥接标头

let keyString        = "12345678901234567890123456789012"
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
print("keyLength   = \(keyData.length), keyData   = \(keyData)")

let message       = "Don´t try to read this text. Top Secret Stuff"
let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
print("data length = \(data.length), data      = \(data)")

let cryptData    = NSMutableData(length: Int(data.length) + kCCBlockSizeAES128)!

let keyLength              = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options:   CCOptions   = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)

var numBytesEncrypted :size_t = 0

var cryptStatus = CCCrypt(operation,
    algoritm,
    options,
    keyData.bytes, keyLength,
    nil,
    data.bytes, data.length,
    cryptData.mutableBytes, cryptData.length,
    &numBytesEncrypted)

if UInt32(cryptStatus) == UInt32(kCCSuccess) {
    cryptData.length = Int(numBytesEncrypted)
    print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)")

    // Not all data is a UTF-8 string so Base64 is used
    let base64cryptString = cryptData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
    print("base64cryptString = \(base64cryptString)")

} else {
    print("Error: \(cryptStatus)")
}
输出:

keyLength   = 32, keyData   = <31323334 35363738 39303132 33343536 37383930 31323334 35363738 39303132>
dataLength  = 46, data      = <446f6ec2 b4742074 72792074 6f207265 61642074 68697320 74657874 2e20546f 70205365 63726574 20537475 6666>
cryptLength = 48, cryptData = <118a32dc c23f7caa 883abc3c 1c7f0770 e200016b 2737acfa 17bb96fb a02b02a7 c147603b 06acd863 94bb8ff2 6cb14515>
base64cryptString = EYoy3MI/fKqIOrw8HH8HcOIAAWsnN6z6F7uW+6ArAqfBR2A7BqzYY5S7j/JssUUV
用法示例:

let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData   = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData:   \(clearData as NSData)")
print("keyData:     \(keyData as NSData)")

var cryptData :Data?
do {
    cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
    print("cryptData:   \(cryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCEncrypt: \(status)")
}

let decryptData :Data?
do {
    let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
    print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCDecrypt: \(status)")
}
示例输出:

clearData:   <636c6561 72446174 61303132 33343536>
keyData:     <6b657944 61746138 39303132 33343536>
cryptData:   <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>
clearData:
关键数据:
密码数据:
解密数据:
注:

CBC模式示例代码的一个典型问题是,它将随机IV的创建和共享留给用户。此示例包括生成IV,在加密数据前加前缀,并在解密期间使用前缀IV。这将使临时用户不必再考虑必要的细节

为了安全起见,加密的数据也应该具有身份验证,本示例代码没有提供这种功能,以便更小,并允许其他平台更好地互操作

还缺少从密码中派生密钥的密钥,建议使用文本密码作为密钥材料


有关可靠的可用于生产的多平台加密代码,请参阅。

Swift 2.0加密和解密。刚刚更新了上述答案以支持Swift 2.0

static func AES128Encryption()
    {
        let keyString        = "12345678901234567890123456789012"
        let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let keyBytes         = UnsafeMutablePointer<Void>(keyData.bytes)
        print("keyLength   = \(keyData.length), keyData   = \(keyData)")

        let message       = "Don´t try to read this text. Top Secret Stuff"
        let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let dataLength    = size_t(data.length)
        let dataBytes     = UnsafeMutablePointer<Void>(data.bytes)
        print("dataLength  = \(dataLength), data      = \(data)")

        let cryptData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
        let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
        let cryptLength  = size_t(cryptData!.length)

        let keyLength              = size_t(kCCKeySizeAES256)
        let operation: CCOperation = UInt32(kCCEncrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)

        var numBytesEncrypted :size_t = 0

        let cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            keyBytes, keyLength,
            nil,
            dataBytes, dataLength,
            cryptPointer, cryptLength,
            &numBytesEncrypted)

        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
          //  let x: UInt = numBytesEncrypted
            cryptData!.length = Int(numBytesEncrypted)
            print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)")

            // Not all data is a UTF-8 string so Base64 is used
            let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
            print("base64cryptString = \(base64cryptString)")

        } else {
            print("Error: \(cryptStatus)")
        }
    }

    static func AES128Decryption(data:NSData) //data = cryptData
    {
        let keyString        = "12345678901234567890123456789012"
        let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let keyBytes         = UnsafeMutablePointer<Void>(keyData.bytes)
        print("keyLength   = \(keyData.length), keyData   = \(keyData)")

        //let message       = "Don´t try to read this text. Top Secret Stuff"
       // let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let dataLength    = size_t(data.length)
        let dataBytes     = UnsafeMutablePointer<Void>(data.bytes)
        print("dataLength  = \(dataLength), data      = \(data)")

        let cryptData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
        let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
        let cryptLength  = size_t(cryptData!.length)

        let keyLength              = size_t(kCCKeySizeAES256)
        let operation: CCOperation = UInt32(kCCDecrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)

        var numBytesEncrypted :size_t = 0

        let cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            keyBytes, keyLength,
            nil,
            dataBytes, dataLength,
            cryptPointer, cryptLength,
            &numBytesEncrypted)

        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            //  let x: UInt = numBytesEncrypted
            cryptData!.length = Int(numBytesEncrypted)
            print("DecryptcryptLength = \(numBytesEncrypted), Decrypt = \(cryptData)")

            // Not all data is a UTF-8 string so Base64 is used
            let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
            print("base64DecryptString = \(base64cryptString)")
               print( "utf8 actual string = \(NSString(data: cryptData!, encoding: NSUTF8StringEncoding))");
        } else {
            print("Error: \(cryptStatus)")
        }
    }
静态函数AES128Encryption()
{
让keyString=“1234567890012345678901234567890123456789012”
让keyData:NSData!=(keyString作为NSString)。dataUsingEncoding(NSUTF8StringEncoding)作为NSData!
让keyBytes=UnsafeMutablePointer(keyData.bytes)
打印(“keyLength=\(keyData.length),keyData=\(keyData)”)
let message=“不要尝试阅读此文本。绝密内容”
让数据:NSData!=(消息作为NSString)。数据使用编码(NSUTF8StringEncoding)作为NSData!
设dataLength=size\u t(data.length)
让dataBytes=UnsafeMutablePointer(data.bytes)
打印(“数据长度=\(数据长度),数据=\(数据)”)
让cryptData=NSMutableData(长度:Int(dataLength)+kCCBlockSizeAES128)
让cryptPointer=unsafemeutablepointer(cryptData!.mutableBytes)
让cryptLength=size\u t(cryptData!.length)
let keyLength=大小(kCCKeySizeAES256)
let操作:cOperation=UInt32(kCCEncrypt)
let算法:CCAlgorithm=UInt32(kCCAlgorithmAES128)
let选项:CCOptions=UInt32(kCCOptionPKCS7Padding+kCCOptionECBMode)
var numBytesEncrypted:size\u t=0
让cryptStatus=CCCrypt(操作,
算法,
选项,
keyBytes,keyLength,
无
数据字节,数据长度,
密码指针,密码长度,
&(未加密)
如果UInt32(加密状态)=UInt32(kCCSuccess){
//设x:UInt=numBytesEncrypted
cryptData!.length=Int(numBytesEncrypted)
打印(“cryptLength=\(numBytesEncrypted),cryptData=\(cryptData)”)
//并非所有数据都是UTF-8字符串,因此使用Base64
让base64cryptString=cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
打印(“base64cryptString=\(base64cryptString)”)
}否则{
打印(“错误:\(加密状态)”)
}
}
静态func AES128解密(数据:NSData)//数据=加密数据
{
让keyString=“1234567890012345678901234567890123456789012”
让keyData:NSData!=(keyString作为NSString)。dataUsingEncoding(NSUTF8StringEncoding)作为NSData!
让keyBytes=UnsafeMutablePointer(keyData.bytes)
打印(“keyLength=\(keyData.length),keyData=\(keyData)”)
//let message=“不要尝试阅读此文本。绝密内容”
//让数据:NSData!=(消息作为NSString)。数据使用编码(NSUTF8StringEncoding)作为NSData!
设dataLength=size\u t(data.length)
让dataBytes=UnsafeMutablePointer(data.bytes)
打印(“数据长度=\(数据长度),数据=\(数据)”)
让cryptData=NSMutableData(长度:Int(dataLength)+kCCBlockSizeAES128)
让cryptPointer=unsafemeutablepointer(cryptData!.mutableBytes)
让cryptLength=size\u t(cryptData!.length)
let keyLength=大小(kCCKeySizeAES256)
let操作:cOperation=UInt32(kCCDecrypt)
let算法:CCAlgorithm=UInt32(kCCAlgorithmAES128)
let选项:CCOptions=UInt32(kCCOptionPKCS7Padding+kCCOptionECBMode)
var numBytesEncrypted:size\u t=0
让cryptStatus=CCCrypt(操作,
算法,
选项,
keyBytes,keyLength,
无
数据字节,数据长度,
密码指针,密码长度,
&(未加密)
如果UInt32(加密状态)=UInt32(kCCSuccess){
//设x:UInt=numBytesEncrypted
cryptData!.length=Int(numBytesEncrypted)
打印(“DecryptcryptLength=\(numBytesEncrypted),Decrypt=\(cryptData)”)
//并非所有数据都是UTF-8字符串,因此使用Base64
让base64cryptString=cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
打印(“base64DecryptString=\(base64cryptString)”)
打印(“utf8实际字符串=\(NSString(数据:cryptData!,编码:NSUTF8StringEncoding));
}否则{
打印(“错误:\(加密状态)”)
}
}

扎夫被现代swift(又一个
enum AESError: Error {
    case KeyError((String, Int))
    case IVError((String, Int))
    case CryptorError((String, Int))
}

// The iv is prefixed to the encrypted data
func aesCBCEncrypt(data:Data, keyData:Data) throws -> Data {
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
        throw AESError.KeyError(("Invalid key length", keyLength))
    }

    let ivSize = kCCBlockSizeAES128;
    let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
    var cryptData = Data(count:cryptLength)

    let status = cryptData.withUnsafeMutableBytes {ivBytes in
        SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
    }
    if (status != 0) {
        throw AESError.IVError(("IV generation failed", Int(status)))
    }

    var numBytesEncrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCEncrypt),
                        CCAlgorithm(kCCAlgorithmAES),
                        options,
                        keyBytes, keyLength,
                        cryptBytes,
                        dataBytes, data.count,
                        cryptBytes+kCCBlockSizeAES128, cryptLength,
                        &numBytesEncrypted)
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        cryptData.count = numBytesEncrypted + ivSize
    }
    else {
        throw AESError.CryptorError(("Encryption failed", Int(cryptStatus)))
    }

    return cryptData;
}

// The iv is prefixed to the encrypted data
func aesCBCDecrypt(data:Data, keyData:Data) throws -> Data? {
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
        throw AESError.KeyError(("Invalid key length", keyLength))
    }

    let ivSize = kCCBlockSizeAES128;
    let clearLength = size_t(data.count - ivSize)
    var clearData = Data(count:clearLength)

    var numBytesDecrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCDecrypt),
                        CCAlgorithm(kCCAlgorithmAES128),
                        options,
                        keyBytes, keyLength,
                        dataBytes,
                        dataBytes+kCCBlockSizeAES128, clearLength,
                        cryptBytes, clearLength,
                        &numBytesDecrypted)
            }
        }
    }

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        clearData.count = numBytesDecrypted
    }
    else {
        throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
    }

    return clearData;
}
let clearData = "clearData0123456".data(using:String.Encoding.utf8)!
let keyData   = "keyData890123456".data(using:String.Encoding.utf8)!
print("clearData:   \(clearData as NSData)")
print("keyData:     \(keyData as NSData)")

var cryptData :Data?
do {
    cryptData = try aesCBCEncrypt(data:clearData, keyData:keyData)
    print("cryptData:   \(cryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCEncrypt: \(status)")
}

let decryptData :Data?
do {
    let decryptData = try aesCBCDecrypt(data:cryptData!, keyData:keyData)
    print("decryptData: \(decryptData! as NSData)")
}
catch (let status) {
    print("Error aesCBCDecrypt: \(status)")
}
clearData:   <636c6561 72446174 61303132 33343536>
keyData:     <6b657944 61746138 39303132 33343536>
cryptData:   <92c57393 f454d959 5a4d158f 6e1cd3e7 77986ee9 b2970f49 2bafcf1a 8ee9d51a bde49c31 d7780256 71837a61 60fa4be0>
decryptData: <636c6561 72446174 61303132 33343536>
static func AES128Encryption()
    {
        let keyString        = "12345678901234567890123456789012"
        let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let keyBytes         = UnsafeMutablePointer<Void>(keyData.bytes)
        print("keyLength   = \(keyData.length), keyData   = \(keyData)")

        let message       = "Don´t try to read this text. Top Secret Stuff"
        let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let dataLength    = size_t(data.length)
        let dataBytes     = UnsafeMutablePointer<Void>(data.bytes)
        print("dataLength  = \(dataLength), data      = \(data)")

        let cryptData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
        let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
        let cryptLength  = size_t(cryptData!.length)

        let keyLength              = size_t(kCCKeySizeAES256)
        let operation: CCOperation = UInt32(kCCEncrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)

        var numBytesEncrypted :size_t = 0

        let cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            keyBytes, keyLength,
            nil,
            dataBytes, dataLength,
            cryptPointer, cryptLength,
            &numBytesEncrypted)

        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
          //  let x: UInt = numBytesEncrypted
            cryptData!.length = Int(numBytesEncrypted)
            print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)")

            // Not all data is a UTF-8 string so Base64 is used
            let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
            print("base64cryptString = \(base64cryptString)")

        } else {
            print("Error: \(cryptStatus)")
        }
    }

    static func AES128Decryption(data:NSData) //data = cryptData
    {
        let keyString        = "12345678901234567890123456789012"
        let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let keyBytes         = UnsafeMutablePointer<Void>(keyData.bytes)
        print("keyLength   = \(keyData.length), keyData   = \(keyData)")

        //let message       = "Don´t try to read this text. Top Secret Stuff"
       // let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
        let dataLength    = size_t(data.length)
        let dataBytes     = UnsafeMutablePointer<Void>(data.bytes)
        print("dataLength  = \(dataLength), data      = \(data)")

        let cryptData    = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
        let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
        let cryptLength  = size_t(cryptData!.length)

        let keyLength              = size_t(kCCKeySizeAES256)
        let operation: CCOperation = UInt32(kCCDecrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)

        var numBytesEncrypted :size_t = 0

        let cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            keyBytes, keyLength,
            nil,
            dataBytes, dataLength,
            cryptPointer, cryptLength,
            &numBytesEncrypted)

        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            //  let x: UInt = numBytesEncrypted
            cryptData!.length = Int(numBytesEncrypted)
            print("DecryptcryptLength = \(numBytesEncrypted), Decrypt = \(cryptData)")

            // Not all data is a UTF-8 string so Base64 is used
            let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
            print("base64DecryptString = \(base64cryptString)")
               print( "utf8 actual string = \(NSString(data: cryptData!, encoding: NSUTF8StringEncoding))");
        } else {
            print("Error: \(cryptStatus)")
        }
    }
extension Data
{
    func aes256CBCEncrypt(keyData: Data) -> Data? {
        let keyLength = keyData.count
        if keyData.count != kCCKeySizeAES256 {
            return nil
        }
        let data = self;
        let ivSize = kCCBlockSizeAES128;
        let cryptLength = size_t(ivSize + data.count + kCCBlockSizeAES128)
        var cryptData = Data(count:cryptLength)

        let status: Int32 = cryptData.withUnsafeMutableBytes {
            guard let ivBytes = $0.baseAddress else {
                return 0
            }
            return SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, ivBytes)
        }
        if (status != 0) {
// who cares, really?            return nil 
        }

        var numBytesEncrypted :size_t = 0
        let options   = CCOptions(kCCOptionPKCS7Padding)

        let cryptStatus: CCCryptorStatus = cryptData.withUnsafeMutableBytes {
            guard let cryptBytes = $0.baseAddress else {
                return CCCryptorStatus(kCCMemoryFailure) // sadly kCCMoronSwiftLanguageSpecDeveloperDetected does not exist
            }
            let cryptStatus: CCCryptorStatus = data.withUnsafeBytes {
                guard let dataBytes = $0.baseAddress else {
                    return CCCryptorStatus(kCCMemoryFailure)
                }
                return keyData.withUnsafeBytes {
                    guard let keyBytes = $0.baseAddress else {
                        return CCCryptorStatus(kCCMemoryFailure)
                    }
                    return CCCrypt(CCOperation(kCCEncrypt),
                            CCAlgorithm(kCCAlgorithmAES),
                            options,
                            keyBytes, keyLength,
                            cryptBytes,
                            dataBytes, data.count,
                            cryptBytes+kCCBlockSizeAES128, cryptLength,
                            &numBytesEncrypted)
                }
            }
            return cryptStatus
        }

        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData.count = numBytesEncrypted + ivSize
        }
        else {
            return nil
        }
        return cryptData;
    }
}