12#import <CommonCrypto/CommonKeyDerivation.h>
13#import <CommonCrypto/CommonCryptor.h>
14#import <CommonCrypto/CommonDigest.h>
19@interface Encryptor (Private)
20- (NSData *)randomInitializationVector;
24@synthesize plaintextPassword = _plaintext_password;
26- (id)initWithPassword:(NSString *)plaintext_password
28 if (plaintext_password == nil)
31 if (!(
self = [super init]))
34 _plaintext_password = [plaintext_password retain];
35 const char *plaintext_password_data =
36 [plaintext_password length] ? [plaintext_password UTF8String] :
" ";
38 if (!plaintext_password_data || !strlen(plaintext_password_data))
39 [NSException raise:NSInternalInconsistencyException
40 format:@"%s: plaintext password data is zero length!", __func__];
42 uint8_t *derived_key = calloc(1, TSXEncryptorPBKDF2KeySize);
44 int ret = CCKeyDerivationPBKDF(
45 kCCPBKDF2, plaintext_password_data, strlen(plaintext_password_data) - 1,
46 (
const uint8_t *)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1,
47 TSXEncryptorPBKDF2Rounds, derived_key, TSXEncryptorPBKDF2KeySize);
51 NSLog(
@"%s: CCKeyDerivationPBKDF ret == %d, indicating some sort of failure.", __func__,
58 _encryption_key = [[NSData alloc] initWithBytesNoCopy:derived_key
59 length:TSXEncryptorPBKDF2KeySize
65#pragma mark Encrypting/Decrypting data
67- (NSData *)encryptData:(NSData *)plaintext_data
69 if (![plaintext_data length])
72 NSData *iv = [
self randomInitializationVector];
73 NSMutableData *encrypted_data = [NSMutableData
74 dataWithLength:[iv length] + [plaintext_data length] + TSXEncryptorBlockCipherBlockSize];
75 [encrypted_data replaceBytesInRange:NSMakeRange(0, [iv length]) withBytes:[iv bytes]];
77 size_t data_out_moved = 0;
78 int ret = CCCrypt(kCCEncrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions,
79 [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [iv bytes],
80 [plaintext_data bytes], [plaintext_data length],
81 [encrypted_data mutableBytes] + [iv length],
82 [encrypted_data length] - [iv length], &data_out_moved);
87 [encrypted_data setLength:[iv length] + data_out_moved];
88 return encrypted_data;
92 @"%s: uncaught error, ret CCCryptorStatus = %d (plaintext len = %lu; buffer size = "
94 __func__, ret, (
unsigned long)[plaintext_data length],
95 (
unsigned long)([encrypted_data length] - [iv length]));
102- (NSData *)decryptData:(NSData *)encrypted_data
104 if ([encrypted_data length] <= TSXEncryptorBlockCipherBlockSize)
107 NSMutableData *plaintext_data =
108 [NSMutableData dataWithLength:[encrypted_data length] + TSXEncryptorBlockCipherBlockSize];
109 size_t data_out_moved = 0;
112 CCCrypt(kCCDecrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions,
113 [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [encrypted_data bytes],
114 [encrypted_data bytes] + TSXEncryptorBlockCipherBlockSize,
115 [encrypted_data length] - TSXEncryptorBlockCipherBlockSize,
116 [plaintext_data mutableBytes], [plaintext_data length], &data_out_moved);
121 [plaintext_data setLength:data_out_moved];
122 return plaintext_data;
124 case kCCBufferTooSmall:
126 case kCCAlignmentError:
131 NSLog(
@"%s: uncaught error, ret CCCryptorStatus = %d (encrypted data len = %lu; buffer "
132 @"size = %lu; dom = %lu)",
133 __func__, ret, (
unsigned long)[encrypted_data length],
134 (
unsigned long)[plaintext_data length], data_out_moved);
141- (NSData *)encryptString:(NSString *)plaintext_string
143 return [
self encryptData:[plaintext_string dataUsingEncoding:NSUTF8StringEncoding]];
146- (NSString *)decryptString:(NSData *)encrypted_string
148 return [[[NSString alloc] initWithData:[
self decryptData:encrypted_string]
149 encoding:NSUTF8StringEncoding] autorelease];
152- (NSData *)randomInitializationVector
154 NSMutableData *iv = [NSMutableData dataWithLength:TSXEncryptorBlockCipherBlockSize];
157 if ((fd = open(
"/dev/urandom", O_RDONLY)) < 0)
160 NSInteger bytes_needed = [iv length];
161 char *p = [iv mutableBytes];
165 long bytes_read = read(fd, p, bytes_needed);
171 bytes_needed -= bytes_read;