在obj-c中加密NSData到NSString?

问题描述 投票:15回答:3

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

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

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

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

我唯一担心的是我希望能够使用'密码短语'加密消息,并且当需要解码混乱的字符串时需要输入相同的密码短语 - 任何人都可以建议实现此方法吗?

iphone objective-c encryption nsstring nsdata
3个回答
33
投票

首先,请勿使用-[NSData description]为此目的创建NSString。 (最好将-description视为调试输出。我很抱歉,如果my previous answer误导你,我只是打印描述来证明NSData可以加密和解密。)而是使用NSString的-dataUsingEncoding:-initWithData:encoding:方法在NSData和NSString之间进行转换。即使有这些,请注意AES加密的数据可能不会很好地转换为字符串 - 某些字节序列不能很好地播放,因此在创建字符串之前对数据进行编码是个好主意。

我建议你尝试Base64 encoding NSData,因为Base64数据总是可以表示为ASCII字符串。 (当然,当你这样做时,你必须在解密前从Base64解码。)

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


编辑:我假设你将这与我对NSString对象的AES加密的your previous question的答案结合起来。将数据编码为Base64不会对数据本身施加任何限制 - 它当然可以是AES加密的数据本身。如果你只想要字符串输入和输出,这是怎么做的:

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

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


2
投票

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

有关详细信息,请参阅“原始”问题的my answer


0
投票

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

这是一个简单的要求,我想保持清淡。所以我创建了一个small Obfuscator,使用@RobNapier在他的blog中共享的大量有用信息。对于那些正在寻找轻量级解决方案的人来说,它可能会有很多帮助。

import Foundation
import CommonCrypto
// A thin wrapper around interfacing
public enum CrypticAlgo {
    case AlgoAES
    case AlgoDES

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 }

}

© www.soinside.com 2019 - 2024. All rights reserved.