objective-c 将 NSData 加密到 obj-c 中的 NSString?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1417893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:11:50  来源:igfitidea点击:

Encrypted NSData to NSString in obj-c?

iphoneobjective-cencryptionnsstringnsdata

提问by Boz

I have an iPhone app which encrypts an inputted NSString using CCCrypt (AES256) and a plaintext key. The string and key are given to the encryption method which returns an NSData object.

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

Requesting [data description] where 'data' is the encrypted string data gives an NSString like: "<0b368353 a707e7de 3eee5992 ee69827e e3603dc2 b0dbbc0b 861ca87d f39ce72a>" but when I try to convert that to an NSString, I get "(null)".

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

I need to return an NSString to the user, which can be used to decrypt back to the original string using the same plaintext key. If the 'description' property of the NSData object can return a string, is there any way I can produce an NSString from the NSData object without getting "(null)"?

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

UPDATE: Thanks to Quinn, who suggests using Base64 encoding to produce the muddled string. From what I understand, Base64 encoding does not simply swap characters, but the character exchange depends on the position, so that's fine.

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

My only concern is that I want to be able to encrypt the message with a 'passphrase', and require the identical passphrase to be entered when the muddled string needs to be decoded - can anybody suggest ways to implement this?

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

回答by Quinn Taylor

First off, DO NOTuse -[NSData description]to create an NSString for such purposes. (It's best to treat -descriptionas debugging output. I apologize if my previous answermisled you, I was merely printing the description to demonstrate that the NSData can be encrypted and decrypted.) Instead, use NSString's -dataUsingEncoding:and -initWithData:encoding:methods to convert between NSData and NSString. Even with these, note that AES-encrypted data will probably not translate well into strings as-is — some byte sequences just won't play nicely, so it's a good idea to encode the data before creating the string.

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

I'd suggest you try Base64 encodingthe NSData, since Base64 data can always be represented as an ASCII string. (Of course, when you do that, you'll have to decode from Base64 before decrypting.)

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

Here are some helpful resources...

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



Edit:I was assuming you'd combine this with my answer to your previous questionon AES encryption of NSString objects. Encoding data as Base64 doesn't place any restrictions on the data itself — it can certainly be AES-enrypted data itself. Here's what to do if you just want string input and output:

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

  • Encryption
    • Provide the NSString to be encrypted, and the passphrase to use for encrypting.
    • Convert the string to an NSData and perform AES encryption on it (see previous question).
    • Base64-encode the NSData, then create and return and NSString of the encoded output.
  • Decryption
    • Provide the encrypted and encoded string, and the passphrase to use for decrypting.
    • Create an NSData from the first string, then Base64-decode the data.
    • Perform AES decryption on the data, then create and return an NSString.
  • 加密
    • 提供要加密的 NSString 和用于加密的密码。
    • 将字符串转换为 NSData 并对其执行 AES 加密(请参阅上一个问题)。
    • 对 NSData 进行 Base64 编码,然后创建并返回编码输出的 NSString。
  • 解密
    • 提供加密和编码的字符串,以及用于解密的密码。
    • 从第一个字符串创建一个 NSData,然后对数据进行 Base64 解码。
    • 对数据执行 AES 解密,然后创建并返回一个 NSString。

It's really just a matter of chaining the two parts together and performing them in reverse on the way out. From my previous answer, you can modify encryptString:withKey:to perform the last step and return a string, and change decryptData:withKey:to be decryptString:withKey:and accept two strings. It's pretty straightforward.

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

回答by Michael Thiel

I have put together a complete bundle of categories for NSData and NSString to provide AES256 encryption for strings.

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

Please see my answeron the 'original' question for more details.

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

回答by Kraming

I have similar requirement where I need to encrypt all the strings when user enters the password to enter to app so that those sensitive strings doesn't remain unencrypted all the time. So I have to keep those strings encrypted and decrypt as an when require only.

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

It was a simple requirement and I wanted to keep it light. So I have created a small Obfuscatorusing lot of useful info shared by @RobNapier in one his blog. It might help for those who are looking a lightweight solution with lot of juicy comments.

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

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)
    }
}

}

public final class 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 }

}

}