swift - 在 Swift 3 中创建 UnsafeMutablePointer<UInt8>

标签 swift encryption commoncrypto unsafemutablepointer

我正在将一个客户端应用程序从 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 函数参数之一

最佳答案

(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 模式下使用随机 IV 的 AES 加密 (Swift 3+)

iv是加密数据的前缀

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

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

key 的长度应恰好为 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。如果使用其他 key 大小,则会抛出错误。

PKCS#7 padding 是默认设置的。

这个例子需要通用加密
必须要有项目的桥接头:
#import <CommonCrypto/CommonCrypto.h>
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 所需的详细信息中解放出来。

为了安全起见,加密的数据也应该有身份验证,这个示例代码没有提供,为了体积小并允许与其他平台更好的互操作性。

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

对于健壮的生产就绪的多平台加密代码,请参阅 RNCryptor

关于swift - 在 Swift 3 中创建 UnsafeMutablePointer<UInt8>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43358722/

相关文章:

java - 从 jPBC 保存和加载非对称 key

iphone - iOS 上的 AES-256 加密不会产生与 openssl 相同的结果

ios - 如何删除 UICollectionView 中单元格的空间

swift - 将具有 String 和 NSImage 属性的类导出到文件

android - 如何使用 Android Key Store Provider 存储 key

c# - 如何在 Windows 上的 .net 框架中使用来自 ECC X509 证书的公钥加密数据?

ios - 解密 AES/GCM/PKCS5Padding iOS Swift

ios - 没有这样的模块 Common Crypto

jquery - Xcode WebView 相机访问不工作

ios - 扫描二维码并打开 URL – Swift AVFoundation 库