3

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?

暗号化関数と復号化関数の両方をデバッグすると、文字列が返されます。

4

2 に答える 2

0

私はついにそれを理解しました...オブジェクトがどのタイプでなければならず、nsvaluetransformerが何を返さなければならないかについて混乱しました。nsvaluetransformer で値を適切な型にキャストしていなかったため、コードで nil を返していました。ただし、これを簡単に理解できる方法でクラッシュすることはありませんでした。次に、エンティティ列を NSObject に戻しました。transformedValue メソッドで NSData オブジェクトを返し、reverseTransformedValue メソッドで NSString を返しました。これが実際に機能させるために必要なすべてでした。どうもありがとうございました。それは確かにタイプエラーでした。

于 2015-10-23T06:54:37.393 に答える
0

修正されたコード サンプルを見たい人を助けるために、質問の transformValue() の戻り行を次のように置き換えます。 return base64cryptString.dataUsingEncoding(NSUTF8StringEncoding)

于 2016-04-14T20:43:01.987 に答える