【问题标题】:How to encrypt data in core data (sqllite) in OS-X application如何在 OS-X 应用程序中加密核心数据(sqlite)中的数据
【发布时间】:2016-07-11 12:25:41
【问题描述】:

我发现,如果我使用可转换类型的属性和 NSXMLStoreType,我的数据是加密的,即具有可转换类型的属性是不可读的。不需要做任何其他事情,不需要代码。 请注意,我正在开发使用核心数据的 OS-X 应用程序。

但是,如果我将商店类型更改为 NSSQLiteStoreType,情况并非如此。

我可以用sqllitebrowser打开数据库,选择可转换的字段,如果我点击导出按钮,在生成的文本文件中,我可以正常读取值,即值(数据)没有加密。

我在大约 4 个月前问过the same question,但没有得到任何答复。

另外,我在 stackoverflow 上找到了this post

您可以加密 Core Data 模型实体中的各个属性 通过使它们具有可变形的属性,然后创建一个 NSValueTransformer 子类,它将加密和解密数据 为那个属性。

对我来说很不幸,答案的作者@Brad Larson 没有提供一个简单的例子来说明如何做到这一点。

任何人都可以提供任何示例代码,说明我如何加密可转换属性,使其无法以任何方式读取吗?

【问题讨论】:

    标签: macos cocoa core-data encryption


    【解决方案1】:

    您可以执行此处显示的操作 Cross-platform-AES-encryption

    添加一个新的 Objective-C 文件到项目选择类别和 NSData 类将其称为 Additions

    NSData+Additions.h

    #import <Foundation/Foundation.h>
    #import <CommonCrypto/CommonDigest.h>
    #import <CommonCrypto/CommonCryptor.h>
    
    @interface NSData (Additions)
    
    #pragma mark - data encryption
    
    + (NSData *)encrypt:(NSData *)plainText key:(NSData *)key iv:(NSData *)iv;
    + (NSData *)decrypt:(NSData *)encryptedText key:(NSData *)key iv:(NSData *)iv;
    
    + (NSData *)dataFromHexString:(NSString *)string;
    + (NSData *)sha256forData:(id)input;
    
    + (NSData *)generateRandomIV:(size_t)length;
    
    @end
    

    NSData+Additions.m

    #import "NSData+Additions.h"
    
    @implementation NSData (Additions)
    
    + (NSData *)encrypt:(NSData *)dataToEncrypt key:(NSData *)key iv:(NSData *)iv {
    
        NSUInteger dataLength = [dataToEncrypt length];
    
        size_t buffSize = dataLength + kCCBlockSizeAES128;
        void *buff = malloc(buffSize);
    
        size_t numBytesEncrypted = 0;
    
        CCCryptorStatus status = CCCrypt(kCCEncrypt,
                                         kCCAlgorithmAES128,
                                         kCCOptionPKCS7Padding,
                                         [key bytes], kCCKeySizeAES256,
                                         [iv bytes],
                                         [dataToEncrypt bytes], [dataToEncrypt length],
                                         buff, buffSize,
                                         &numBytesEncrypted);
    
        if (status == kCCSuccess) {
            return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];
        }
    
        free(buff);
        return nil;
    }
    
    + (NSData *)decrypt:(NSData *)encryptedData key:(NSData *)key iv:(NSData *)iv {
    
        NSUInteger dataLength = [encryptedData length];
    
        size_t buffSize = dataLength + kCCBlockSizeAES128;
    
        void *buff = malloc(buffSize);
    
        size_t numBytesEncrypted = 0;
        CCCryptorStatus status = CCCrypt(kCCDecrypt,
                                         kCCAlgorithmAES128,
                                         kCCOptionPKCS7Padding,
                                         [key bytes], kCCKeySizeAES256,
                                         [iv bytes],
                                         [encryptedData bytes], [encryptedData length],
                                         buff, buffSize,
                                         &numBytesEncrypted);
        if (status == kCCSuccess) {
            return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];
        }
    
        free(buff);
        return nil;
    }
    
    + (NSData *)dataFromHexString:(NSString *)string {
    
        NSMutableData *stringData = [[NSMutableData alloc] init];
        unsigned char whole_byte;
        char byte_chars[3] = {'\0','\0','\0'};
    
        for (int counter = 0; counter < [string length] / 2; counter++) {
            byte_chars[0] = [string characterAtIndex:counter * 2];
            byte_chars[1] = [string characterAtIndex:counter * 2 + 1];
            whole_byte = strtol(byte_chars, NULL, 16);
            [stringData appendBytes:&whole_byte length:1];
        }
    
        return stringData;
    }
    
    + (NSData *)sha256forData:(id)input {
        NSData *dataIn;
    
        if ([input isKindOfClass:[NSString class]]) {
            dataIn = [input dataUsingEncoding:NSUTF8StringEncoding];
        } else if ([input isKindOfClass:[NSData class]]) {
    
            NSUInteger dataLength = [input length];
            NSMutableString *string = [NSMutableString stringWithCapacity:dataLength * 2];
            const unsigned char *dataBytes = [input bytes];
    
            for (NSInteger idx = 0; idx < dataLength; ++idx)
                [string appendFormat:@"%02x", dataBytes[idx]];
    
            dataIn = [string dataUsingEncoding:NSUTF8StringEncoding];
        }
    
        NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
    
        CC_SHA256(dataIn.bytes, (CC_LONG)[dataIn length],  [macOut mutableBytes]);
    
        return macOut;
    }
    
    + (NSData *)generateRandomIV:(size_t)length {
        NSMutableData *data = [NSMutableData dataWithLength:length];
    
        SecRandomCopyBytes(kSecRandomDefault, length, [data mutableBytes]);
    
        return data;
    }
    
    @end
    

    那么你将需要用户名、密码、iVector 和一些随机盐。在盐中,我使用随机字符替换 # 但请确保如果您使用 % 不要忘记将其加倍 %% 否则它将是不完整的格式说明符警告。

    在你的课堂上这样使用它

    #define CC_USERNAME         @"secretName"
    #define CC_PASSWORD         @"secretPassword"
    #define CC_SALTED_STRING    [NSString stringWithFormat:@"####################%@#####################", CC_PASSWORD]
    

    然后创建通过 SHA256 运行的加盐字符串的 NSData 表示

    NSData *hash = [NSData sha256forData:CC_SALTED_STRING];
    

    下一步是随机生成16字节的iVector数据

    NSData *iVector = [NSData generateRandomIV:16];
    

    并使用这些对象来加密您的字符串。使用 iVector 数据的前 16 个字节创建一个 NSMutableData 对象(确保您使用 iVector 对象并且不要生成新的随机数,否则您将无法解密)。

    NSString *message = @"my secret message to the world";
    NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
    
    NSMutableData *encryptedData = [[NSMutableData alloc] initWithData:iVector];
    
    NSData *payLoad = [NSData encrypt:messageData key:hash iv:iVector];
    
    [encryptedData appendData:payLoad];
    

    要解密,将前 16 个字节和其余数据分开并将其与散列一起使用。

    NSData *pureData = [encryptedData subdataWithRange:NSMakeRange(16, [encryptedData length] - 16)];
    NSData *extractedVector = [encryptedData subdataWithRange:NSMakeRange(0, 16)];
    
    NSData *decryptedData = [NSData decrypt:pureData key:hash iv:extractedVector];
    
    NSString *decryptedMessage = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
    

    您可以在哈希上做一些额外的 md5,甚至在存储之前使用 zlib 打包加密数据。

    享受您定制的加密货币。

    【讨论】:

    • 我现在将尝试实现它......希望我能设法让它发挥作用。感谢您的时间和精力。
    • 我在文件 NSData+Base64.m 中遇到一堆错误。首先,编译器抱怨第 25 行 return [result autorelease];并在返回结果中更改该行之后;我收到警告@implementation NSData (Base64) Method definition base64EncodingStringWithSeparateLines not found,并在此行下方出现错误......再次提及......我正在开发 OS-X 应用程序
    • 我没有使用过base64。试试我写的实现。这应该足以满足您的需求。我的方法可能只是根据我的需要稍作修改。但是我写的代码可以自己运行,不需要使用 base64
    • 我还有一个问题....我使用绑定来插入和读取数据。我怎样才能用绑定来实现你的代码?
    • 你知道为什么 NSData *hash = [NSData sha256forData:CC_SALTED_STRING];产生警告“格式字符串未使用数据参数”?
    猜你喜欢
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2014-04-16
    • 1970-01-01
    • 2011-02-20
    • 2014-01-20
    相关资源
    最近更新 更多