Зашифрованные NSData для NSString в obj-c? - PullRequest
15 голосов
/ 13 сентября 2009

У меня есть приложение для iPhone, которое шифрует введенную строку NSString с помощью CCCrypt (AES256) и ключ в виде открытого текста. Строка и ключ передаются методу шифрования, который возвращает объект NSData.

Запрос [описание данных], где «данные» - это зашифрованные строковые данные, дает строку NSString: «<0b368353 a707e7de 3eee5992 ee69827e e3603dc2 b0dbbc0b 861ca87d f39ce72a>», но когда я пытаюсь преобразовать это в NSString )».

Мне нужно вернуть NSString пользователю, который может быть использован для дешифрования обратно к исходной строке с использованием того же открытого текста. Если свойство 'description' объекта NSData может возвращать строку, есть ли способ, которым я могу создать NSString из объекта NSData, не получая "(null)"?

ОБНОВЛЕНИЕ: Спасибо Куинну, который предлагает использовать кодировку Base64 для получения запутанной строки. Из того, что я понимаю, кодировка Base64 не просто меняет символы, но обмен символами зависит от позиции, так что это нормально.

Мое единственное беспокойство заключается в том, что я хочу иметь возможность зашифровать сообщение с помощью «парольной фразы» и требовать ввода идентичной парольной фразы при необходимости расшифровки запутанной строки - кто-нибудь может предложить способы реализации этого?

Ответы [ 3 ]

33 голосов
/ 13 сентября 2009

Прежде всего, НЕ используйте -[NSData description] для создания строки NSSt для таких целей. (Лучше всего трактовать -description как результат отладки. Я извиняюсь, если мой предыдущий ответ ввел вас в заблуждение, я просто печатал описание, чтобы продемонстрировать, что NSData можно зашифровать и расшифровать.) Вместо этого используйте * NSString's -dataUsingEncoding: и -initWithData:encoding: методы для преобразования между NSData и NSString. Даже с учетом этого обратите внимание, что AES-зашифрованные данные, вероятно, не будут хорошо преобразовываться в строки как есть - некоторые последовательности байтов просто не будут хорошо воспроизводиться, поэтому рекомендуется кодировать данные перед созданием строки.

Я бы посоветовал вам попробовать Base64-кодировку NSData, поскольку данные Base64 всегда могут быть представлены в виде строки ASCII. (Конечно, когда вы это сделаете, вам придется декодировать из Base64 перед расшифровкой.)

Вот несколько полезных ресурсов ...


Редактировать: Я предполагал, что вы объедините это с моим ответом на ваш предыдущий вопрос о шифровании AES объектов NSString. Кодирование данных в виде Base64 не накладывает никаких ограничений на сами данные - это могут быть данные, зашифрованные AES. Вот что нужно сделать, если вы просто хотите вводить и выводить строку:

  • Шифрование
    • Укажите строку NSS для шифрования и фразу-пароль для шифрования.
    • Преобразовать строку в NSData и выполнить шифрование AES на ней (см. Предыдущий вопрос).
    • Base64-кодирует NSData, затем создает и возвращает и NSString закодированного вывода.
  • дешифрование
    • Укажите зашифрованную и зашифрованную строку и пароль для использования при расшифровке.
    • Создайте NSData из первой строки, затем Base64-декодируйте данные.
    • Выполните расшифровку AES для данных, затем создайте и верните строку NSString.

Это просто вопрос объединения двух частей в одну и выполнения их в обратном порядке на выходе. Из моего предыдущего ответа вы можете изменить encryptString:withKey: для выполнения последнего шага и возврата строки, а также изменить decryptData:withKey: на decryptString:withKey: и принять две строки. Это довольно просто.

2 голосов
/ 22 февраля 2011

Я собрал полный набор категорий для NSData и NSString, чтобы обеспечить шифрование AES256 для строк.

Пожалуйста, см. мой ответ на «оригинальный» вопрос для получения более подробной информации.

0 голосов
/ 13 марта 2019

У меня есть подобное требование, когда мне нужно зашифровать все строки, когда пользователь вводит пароль для входа в приложение, чтобы эти чувствительные строки не оставались незашифрованными все время. Поэтому я должен хранить эти строки в зашифрованном виде и расшифровывать только тогда, когда требуется.

Это было простое требование, и я хотел, чтобы оно было легким. Поэтому я создал маленький Обфускатор , используя много полезной информации, которую @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)
    }
}

}

публичный выпускной класс 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 }

}

...