【问题标题】:Create UnsafeMutablePointer<UInt8> in Swift 3在 Swift 3 中创建 UnsafeMutablePointer<UInt8>
【发布时间】:2017-04-12 01:26:42
【问题描述】:

我正在将客户端应用程序从 Swift 2 更新到 Swift 3,并且我正在处理 commonCrypto(哎呀!)。

我正在尝试转换一个 DES 加密函数,但我不知道如何替换这段代码:

let cryptData: NSMutableData! = NSMutableData(length: Int(dataLength) + kCCBlockSizeDES)
let cryptPointer = UnsafeMutablePointer<UInt8>(cryptData.mutableBytes)

获取cryptPointer的正确方法是什么?到目前为止,我正在尝试:

var cryptData = Data(count: Int(dataLength) + kCCBlockSizeDES)
let cryptPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: cryptData.count)
cryptData.copyBytes(to: cryptPointer, count: cryptData.count)

但我无法正确加密和解​​密。

请注意,我需要指针变量,因为它是 CCCrypt 函数参数之一

【问题讨论】:

    标签: swift encryption commoncrypto unsafemutablepointer


    【解决方案1】:

    (DES 不安全,不应在新工作中使用;它已被 AES 取代)

    示例片段:

    let cryptLength = size_t(data.count + kCCBlockSizeDES)
    var cryptData = Data(repeating:0, count:cryptLength)
    var numBytesEncrypted :size_t = 0
    
    let keyLength             = size_t(kCCKeySizeDES)
    let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
    let options:  CCOptions   = UInt32(kCCOptionPKCS7Padding)
    
    let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            ivData.withUnsafeBytes {ivBytes in
                keyData.withUnsafeBytes {keyBytes in
                    CCCrypt(CCOperation(operation),
                            algoritm,
                            options,
                            keyBytes, keyLength,
                            ivBytes,
                            dataBytes, data.count,
                            cryptBytes, cryptLength,
                            &numBytesEncrypted)
                }
            }
        }
    }
    

    日落文档部分的示例:

    CBC 模式下的 AES 加密,带有随机 IV (Swift 3+)

    iv 是加密数据的前缀

    aesCBC128Encrypt 将创建一个随机 IV 并作为加密代码的前缀。
    aesCBC128Decrypt 将在解密期间使用前缀 IV。

    输入是数据,键是数据对象。如果需要在调用方法中转换为和/或从编码形式(如 Base64)。

    密钥的长度应为 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。如果使用其他密钥大小,则会引发错误。

    PKCS#7 padding是默认设置的。

    此示例需要 Common Crypto
    项目必须有桥接头:
    #import &lt;CommonCrypto/CommonCrypto.h&gt;
    Security.framework 添加到项目中。

    这是示例,不是生产代码。

    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>
    

    注意事项:
    CBC 模式示例代码的一个典型问题是,它将随机 IV 的创建和共享留给用户。此示例包括生成 IV、为加密数据添加前缀并在解密期间使用前缀 IV。这将临时用户从CBC mode 所需的详细信息中解放出来。

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

    还缺少从密码中导出密钥的密钥,建议使用PBKDF2,将文本密码用作密钥材料。

    有关强大的生产就绪多平台加密代码,请参阅RNCryptor

    【讨论】:

    • 是的!这行得通!非常感谢你。我必须使用 DES 加密,因为这个应用程序需要通过套接字与使用 DES 的服务器通信,所以这是要求的一部分。
    猜你喜欢
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多