在obj-c中加密NSData到NSString?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在obj-c中加密NSData到NSString?相关的知识,希望对你有一定的参考价值。
我有一个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编码不只是交换字符,但字符交换取决于位置,所以没关系。
我唯一担心的是我希望能够使用'密码短语'加密消息,并且当需要解码混乱的字符串时需要输入相同的密码短语 - 任何人都可以建议实现此方法吗?
首先,请勿使用-[NSData description]
为此目的创建NSString。 (最好将-description
视为调试输出。我很抱歉,如果my previous answer误导你,我只是打印描述来证明NSData可以加密和解密。)而是使用NSString的-dataUsingEncoding:
和-initWithData:encoding:
方法在NSData和NSString之间进行转换。即使有这些,请注意AES加密的数据可能不会很好地转换为字符串 - 某些字节序列不能很好地播放,因此在创建字符串之前对数据进行编码是个好主意。
我建议你尝试Base64 encoding NSData,因为Base64数据总是可以表示为ASCII字符串。 (当然,当你这样做时,你必须在解密前从Base64解码。)
这是一些有用的资源......
- Colloquy有一些代码在NSData上进行编码/解码(header和implementation)
- Google Toolbox for Mac具有类似的功能(header和implementation)
- 关于这个话题的Cocoa With Love blog post。
- 关于这个话题的CocoaDev.com wiki page。
编辑:我假设你将这与我对NSString对象的AES加密的your previous question的答案结合起来。将数据编码为Base64不会对数据本身施加任何限制 - 它当然可以是AES加密的数据本身。如果你只想要字符串输入和输出,这是怎么做的:
- 加密 提供要加密的NSString,以及用于加密的密码。 将字符串转换为NSData并对其执行AES加密(请参阅上一个问题)。 Base64编码NSData,然后创建并返回编码输出的NSString。
- 解密 提供加密和编码的字符串以及用于解密的密码。 从第一个字符串创建NSData,然后Base64解码数据。 对数据执行AES解密,然后创建并返回NSString。
这只是将两个部分链接在一起并在出路时反向执行的问题。根据我之前的回答,您可以修改encryptString:withKey:
以执行最后一步并返回一个字符串,并将decryptData:withKey:
更改为decryptString:withKey:
并接受两个字符串。这很简单。
我已经为NSData和NSString整理了一组完整的类别,为字符串提供AES256加密。
有关详细信息,请参阅“原始”问题的my answer。
我有类似的要求,当用户输入密码进入应用程序时,我需要加密所有字符串,以便这些敏感字符串不会始终保持未加密状态。所以我必须保持这些字符串的加密和解密,只需要时间。
这是一个简单的要求,我想保持清淡。所以我创建了一个small Obfuscator,使用@RobNapier在他的blog中共享的大量有用信息。对于那些正在寻找轻量级解决方案的人来说,它可能会有很多帮助。
import Foundation import CommonCrypto // A thin wrapper around interfacing public enum CrypticAlgo { case AlgoAES case AlgoDESfunc 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)!) }
以上是关于在obj-c中加密NSData到NSString?的主要内容,如果未能解决你的问题,请参考以下文章
php加密文件 解密data 转nsstring 为nil. rc4 ios