15

我有一个 iPhone 应用程序,它使用 CCCrypt (AES256) 和明文密钥对输入的 NSString 进行加密。字符串和密钥被提供给返回 NSData 对象的加密方法。

请求 [data description] 其中 'data' 是加密的字符串数据会给出一个 NSString,例如:“<0b368353 a707e7de 3eee5992 ee69827e e3603dc2 b0dbbc0b 861ca87d f39ce72a>”但是当我尝试将其转换为 NSString 时,我得到“(null)”。

我需要向用户返回一个 NSString,它可用于使用相同的明文密钥解密回原始字符串。如果 NSData 对象的“描述”属性可以返回一个字符串,有什么方法可以从 NSData 对象生成一个 NSString 而不会得到“(null)”?

更新:感谢 Quinn,他建议使用 Base64 编码来生成混乱的字符串。据我了解,Base64编码并不是简单地交换字符,而是字符交换取决于位置,所以没关系。

我唯一担心的是我希望能够使用“密码”加密消息,并且在需要解码混乱的字符串时需要输入相同的密码 - 任何人都可以提出实现这一点的方法吗?

4

3 回答 3

33

首先,不要-[NSData description]为此目的创建 NSString 。(最好将-description其视为调试输出。如果我之前的回答误导了您,我深表歉意,我只是打印描述以证明 NSData 可以加密和解密。)相反,使用 NSString 的-dataUsingEncoding:-initWithData:encoding:方法在 NSData 和 NSString 之间进行转换。即使有了这些,请注意 AES 加密的数据可能无法按原样很好地转换为字符串 - 某些字节序列不能很好地播放,因此在创建字符串之前对数据进行编码是个好主意。

我建议您尝试对 NSData 进行Base64 编码,因为 Base64 数据始终可以表示为 ASCII 字符串。(当然,当你这样做时,你必须在解密之前从 Base64 解码。)

这里有一些有用的资源...


编辑:我假设您会将其与我对您之前关于 NSString 对象的 AES 加密的问题的回答结合起来。将数据编码为 Base64 不会对数据本身施加任何限制——它当然可以是 AES 加密的数据本身。如果您只需要字符串输入和输出,请执行以下操作:

  • 加密
    • 提供要加密的 NSString,以及用于加密的密码。
    • 将字符串转换为 NSData 并对其执行 AES 加密(请参阅上一个问题)。
    • Base64 编码 NSData,然后创建并返回编码输出的 NSString。
  • 解密
    • 提供加密和编码的字符串,以及用于解密的密码。
    • 从第一个字符串创建一个 NSData,然后对数据进行 Base64 解码。
    • 对数据执行 AES 解密,然后创建并返回一个 NSString。

这实际上只是将两个部分链接在一起并在输出时反向执行它们的问题。从我之前的回答中,您可以修改encryptString:withKey:为执行最后一步并返回一个字符串,然后更改decryptData:withKey:decryptString:withKey:接受两个字符串。这很简单。

于 2009-09-13T15:05:07.570 回答
2

我已经为 NSData 和 NSString 整理了一整套类别,为字符串提供 AES256 加密。

有关更多详细信息,请参阅对“原始”问题的回答。

于 2011-02-22T13:04:35.887 回答
0

我有类似的要求,当用户输入密码以进入应用程序时,我需要加密所有字符串,以便这些敏感字符串不会一直保持未加密状态。因此,我必须仅在需要时将这些字符串加密和解密。

这是一个简单的要求,我想保持轻松。因此,我使用@RobNapier 在他的博客中分享的许多有用信息创建了一个小型混淆器。对于那些正在寻找具有大量多汁评论的轻量级解决方案的人来说,它可能会有所帮助。

进口基金会
导入 CommonCrypto
// 接口周围的薄包装
公共枚举 CrypticAlgo {
    案例算法AES
    案例算法DES

func blockSize() -> Int {
    switch self {
    case .AlgoAES:
        return kCCBlockSizeAES128
    case .AlgoDES:
        return kCCBlockSizeDES
    }
}

func keySize() -> size_t {
    switch self {
    case .AlgoAES:
        return kCCKeySizeAES128
    case .AlgoDES:
        return kCCKeySizeDES
    }
}

func algo() -> UInt32 {
    switch self {
    case .AlgoAES:
        return CCAlgorithm(kCCAlgorithmAES)
    case .AlgoDES:
        return CCAlgorithm(kCCAlgorithmDES)
    }
}

}

公共最终类 MGObfuscate {

private var ivData: [UInt8]? private var derivedKey: Data? private let crypticAlgo: CrypticAlgo public init(password: String, salt: String, algo: CrypticAlgo) { //Quickly get the data to release the password string let passwordData = password.data(using: .utf8)! // // Rounds require for 1 sec delay in generating hash. // Salt is a public attribute. If attacker somehow get the drivedKey and try to crack // the password via brute force, The delay due to Rounds will make it frustrating // to get actual password and deter his/her efforts. // let rounds = CCCalibratePBKDF(CCPBKDFAlgorithm(kCCPBKDF2), password.count, salt.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), Int(CC_SHA256_DIGEST_LENGTH), 1000) let saltData = salt.data(using: .utf8)! derivedKey = MGObfuscate.derivedKey(for: passwordData, saltData: saltData, rounds: rounds) self.crypticAlgo = algo var ivData = [UInt8](repeating: 0, count: algo.blockSize()) // Random criptographically secure bytes for initialisation Vector let rStatus = SecRandomCopyBytes(kSecRandomDefault, ivData.count, &ivData) self.ivData = ivData // print(ivData) guard rStatus == errSecSuccess else { fatalError("seed not generated \(rStatus)") } } @inline(__always) private static func derivedKey(for passwordData: Data, saltData: Data, rounds: UInt32) -> Data { var derivedData = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) let result = derivedData.withUnsafeMutableBytes { (drivedBytes: UnsafeMutablePointer<UInt8>?) in passwordData.withUnsafeBytes({ (passwordBytes: UnsafePointer<Int8>!) in saltData.withUnsafeBytes({ (saltBytes: UnsafePointer<UInt8>!) in CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), passwordBytes, passwordData.count, saltBytes, saltData.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), rounds, drivedBytes, Int(CC_SHA256_DIGEST_LENGTH)) }) }) } if kCCSuccess != result { fatalError("failed to generate hash for password") } return derivedData } private func runCryptic(operation: Int, inputData: Data, keyData: Data, ivData: Data) -> Data { let cryptLength = size_t(inputData.count + crypticAlgo.blockSize()) var cryptData = Data(count: cryptLength) let keyLength = crypticAlgo.keySize() var bytesProcessed: size_t = 0 let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in inputData.withUnsafeBytes { dataBytes in keyData.withUnsafeBytes { keyBytes in ivData.withUnsafeBytes{ ivBytes in CCCrypt(CCOperation(operation), crypticAlgo.algo(), CCOptions(kCCOptionPKCS7Padding), keyBytes, keyLength, ivBytes, dataBytes, inputData.count, cryptBytes, cryptLength, &bytesProcessed) } } } } if cryptStatus == CCCryptorStatus(kCCSuccess) { cryptData.removeSubrange(bytesProcessed..<cryptData.count) } else { fatalError("Error: \(cryptStatus)") } return cryptData } public func encriptAndPurge(inputString: inout String?) -> Data? { if let inputdata = inputString?.data(using: .utf8) { inputString = nil return runCryptic(operation: kCCEncrypt, inputData: inputdata, keyData: derivedKey!, ivData: Data(bytes: ivData!)) } return nil } public func encript(inputString: String) -> Data { let inputdata = inputString.data(using: .utf8)! return runCryptic(operation: kCCEncrypt, inputData: inputdata, keyData: derivedKey!, ivData: Data(bytes: ivData!)) } public func decript(data: Data, result: (String) -> Void) { let data = runCryptic(operation: kCCDecrypt, inputData: data, keyData: derivedKey!, ivData: Data(bytes: ivData!)) result(String(data: data, encoding: .utf8)!) } public func purge() { ivData = nil derivedKey = nil }

}

于 2019-03-13T08:22:42.380 回答