Шифрование основных данных iOS с использованием NSValueTransformer
Я экспериментирую с шифрованием данных с помощью Core Data и CommonCrypto. Я пытаюсь использовать NSValueTransformer для ленивого шифрования и дешифрования.
Однако, когда я сейчас пытаюсь сохранить зашифрованные данные в постоянном хранилище, происходит сбой. Каждый раз, когда я пытаюсь сохранить свои данные в базе данных, это дает мне:
- [__ NSCFString bytes]: нераспознанный селектор отправлен на экземпляр
Я уверен, что это какая-то база данных и несоответствие NSManagedObject, но я не могу понять это. Я чувствую, что это, вероятно, довольно просто, но я не могу найти решение. Мой код:
NSValueTransformer
class TryHardEncryption: NSValueTransformer {
override class func transformedValueClass() -> AnyClass {
return NSString.self
}
override class func allowsReverseTransformation() -> Bool {
return true
}
override func reverseTransformedValue(value: AnyObject?) -> AnyObject? {
if let message = value as? NSString {
let keyString = "12345678901234567890123456789012"
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length), keyData = \(keyData)")
let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let dataLength = size_t(data.length)
let dataBytes = UnsafeMutablePointer<Void>(data.bytes)
print("dataLength = \(dataLength), data = \(data)")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
print("DecryptcryptLength = \(numBytesEncrypted), Decrypt = \(cryptData)")
// Not all data is a UTF-8 string so Base64 is used
let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
print("base64DecryptString = \(base64cryptString)")
print( "utf8 actual string = \(NSString(data: cryptData!, encoding: NSUTF8StringEncoding))");
return base64cryptString
} else {
print("Error: \(cryptStatus)")
}
}
return nil
}
override func transformedValue(value: AnyObject?) -> AnyObject? {
if let message = value as? NSString {
let keyString = "12345678901234567890123456789012"
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafePointer<UInt8>(keyData.bytes)
print("keyLength = \(keyData.length), keyData = \(keyData)")
let data: NSData! = message.dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let dataLength = Int(data.length)
let dataBytes = UnsafePointer<UInt8>(data.bytes)
print("dataLength = \(dataLength), data = \(data)")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)!
let cryptPointer = UnsafeMutablePointer<UInt8>(cryptData.mutableBytes)
let cryptLength = size_t(cryptData.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)")
// Not all data is a UTF-8 string so Base64 is used
let base64cryptString = cryptData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
print("base64cryptString = \(base64cryptString)")
return NSString(string: base64cryptString) as NSObject
} else {
print("Error: \(cryptStatus)")
}
}
return nil
}
}
Что я должен был сделать, чтобы заставить NSValueTransformer работать:
let transformer: TryHardEncryption = TryHardEncryption()
NSValueTransformer.setValueTransformer(transformer, forName: "TryHardEncryption")
Без приведенного выше кода NSValueTransformer никогда не вызывался.
Я пометил поле базы данных как тип Transformable и назвал его: TryHardEncryption. Ребята, вы знаете, что здесь не так?
РЕДАКТИРОВАТЬ Это свойство, которое это касается:
@NSManaged var establishmentDescription: String?
Функции шифрования и дешифрования возвращают строку, когда я их отлаживаю.
2 ответа
Я наконец понял это... Я был озадачен тем, какой тип объекта должен быть и что должен вернуть мой nsvaluetransformer. Я не приводил значение к нужному типу в nsvaluetransformer, и поэтому я возвращал ноль в коде. Однако это не было сбой таким образом, чтобы я мог легко понять это. Во-вторых, я изменил столбец сущности обратно на NSObject. Возвращает объект NSData в методе transformedValue и строку NSString в методе reverseTransformedValue. Это было на самом деле все, что мне нужно, чтобы заставить его работать. Большое спасибо за вашу помощь. Это действительно была ошибка типа.
Чтобы помочь любому, кто хотел бы увидеть исправленный пример кода, замените строку возврата transmedValue() в вопросе следующим: return base64cryptString.dataUsingEncoding(NSUTF8StringEncoding)