Шифрование основных данных 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?

Обе функции шифрования и дешифрования возвращают строку при их отладке.


person Orion    schedule 16.10.2015    source источник
comment
Это может быть простой случай обновления модели и отсутствия создания новых файлов для измененных сущностей, может быть предупреждение об этом, не уверен, но вы можете просто просмотреть свои классы модели и проверить их, если ваше приложение небольшое. экспериментальное приложение.   -  person A-Live    schedule 16.10.2015
comment
Я отменил все изменения в NSManagedObject, которые я сделал до изменения типа Transformable, но снова не повезло :( Спасибо за информацию.   -  person Orion    schedule 16.10.2015
comment
Вы пытались поставить точку останова исключения и запустить приложение с ней? Это может показать вам точную строку, где возникает проблема. Кроме того, что касается того факта, что вам пришлось использовать NSValueTransformer.setValueTransformer, ввели ли вы имя типа преобразователя в инспекторе модели данных (новое текстовое поле должно появиться под раскрывающимся списком типов атрибутов, когда вы выбираете преобразуемый)?   -  person A-Live    schedule 16.10.2015
comment
При отладке я вижу, что код входит в метод transformValue. Я даже распечатываю результат, и все кажется нормальным. Я убедился, что имена равны, скопировав значение поля имени, которое появилось в инспекторе модели данных, в метод setvaluetransformer.   -  person Orion    schedule 16.10.2015
comment
Тогда ваши функции не кажутся проблемой, в нижней части навигатора точек останова вы можете найти кнопку +, а затем добавить общую точку останова исключения из открытого меню, такая точка останова должна показать вам точную строку, где происходит исключение (это не так). не всегда очень эффективно, но полезно в большинстве случаев), вам нужно будет запустить приложение с включенными точками останова, чтобы оно заработало. Вы пробовали это?   -  person A-Live    schedule 16.10.2015
comment
Хм, точка останова сообщает мне о новом исключении, но я не получаю никакой дополнительной информации для моей текущей ошибки. Я вернул тип обратно к строке, и все кажется нормальным. Это должно быть несоответствие типов.   -  person Orion    schedule 19.10.2015
comment
Вы получаете строку в своем коде, если да, то какая это строка? В любом случае, вы можете попробовать ввести bt в представлении консоли, когда приложение остановлено в точке останова, отладчик должен распечатать стопку, и это должно сделать исходный код более понятным, даже если это системный фреймворк.   -  person A-Live    schedule 19.10.2015
comment
Я, наконец, понял это... Я был сбит с толку относительно того, какого типа должен быть сам объект и что должен возвращать мой nsvaluetransformer. Я не приводил значение к правильному типу в nsvaluetransformer и поэтому возвращал nil в коде. Однако он не рушился так, чтобы я легко это понял. Во-вторых, я изменил столбец сущности обратно на NSObject. Возвращает объект NSData в методе transformValue и NSString в методе reverseTransformedValue. Это было фактически все, что мне нужно, чтобы заставить его работать. Большое спасибо за помощь. Это действительно была ошибка типа.   -  person Orion    schedule 19.10.2015


Ответы (2)


Я, наконец, понял это... Я был сбит с толку относительно того, какого типа должен быть сам объект и что должен возвращать мой nsvaluetransformer. Я не приводил значение к правильному типу в nsvaluetransformer и поэтому возвращал nil в коде. Однако он не рушился так, чтобы я легко это понял. Во-вторых, я изменил столбец сущности обратно на NSObject. Возвращает объект NSData в методе transformValue и NSString в методе reverseTransformedValue. Это было фактически все, что мне нужно, чтобы заставить его работать. Спасибо большое за вашу помощь. Это действительно была ошибка типа.

person Orion    schedule 23.10.2015

Чтобы помочь всем, кто хотел бы увидеть исправленный пример кода, замените строку возврата transformValue() в вопросе на это: return base64cryptString.dataUsingEncoding(NSUTF8StringEncoding)

person r590    schedule 14.04.2016