15 #import <CommonCrypto/CommonKeyDerivation.h>
16 #import <CommonCrypto/CommonCryptor.h>
17 #import <CommonCrypto/CommonDigest.h>
18 #import <openssl/evp.h>
23 @interface Encryptor (Private)
24 - (NSData *)randomInitializationVector;
28 @synthesize plaintextPassword = _plaintext_password;
30 - (id)initWithPassword:(NSString *)plaintext_password
32 if (plaintext_password == nil)
35 if (!(
self = [super init]))
38 _plaintext_password = [plaintext_password retain];
39 const char *plaintext_password_data =
40 [plaintext_password length] ? [plaintext_password UTF8String] :
" ";
42 if (!plaintext_password_data || !strlen(plaintext_password_data))
43 [NSException raise:NSInternalInconsistencyException
44 format:@"%s: plaintext password data is zero length!", __func__];
46 uint8_t *derived_key = calloc(1, TSXEncryptorPBKDF2KeySize);
48 if (CCKeyDerivationPBKDF != NULL)
50 int ret = CCKeyDerivationPBKDF(
51 kCCPBKDF2, plaintext_password_data, strlen(plaintext_password_data) - 1,
52 (
const uint8_t *)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1,
53 TSXEncryptorPBKDF2Rounds, derived_key, TSXEncryptorPBKDF2KeySize);
59 NSLog(
@"%s: CCKeyDerivationPBKDF ret == %d, indicating some sort of failure.", __func__,
69 unsigned long ret = PKCS5_PBKDF2_HMAC_SHA1(
70 plaintext_password_data, (
int)strlen(plaintext_password_data) - 1,
71 (
const unsigned char *)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen,
72 TSXEncryptorPBKDF2Rounds, TSXEncryptorPBKDF2KeySize, derived_key);
78 NSLog(
@"%s: PKCS5_PBKDF2_HMAC_SHA1 ret == %lu, indicating some sort of failure.",
86 _encryption_key = [[NSData alloc] initWithBytesNoCopy:derived_key
87 length:TSXEncryptorPBKDF2KeySize
93 #pragma mark Encrypting/Decrypting data
95 - (NSData *)encryptData:(NSData *)plaintext_data
97 if (![plaintext_data length])
100 NSData *iv = [
self randomInitializationVector];
101 NSMutableData *encrypted_data = [NSMutableData
102 dataWithLength:[iv length] + [plaintext_data length] + TSXEncryptorBlockCipherBlockSize];
103 [encrypted_data replaceBytesInRange:NSMakeRange(0, [iv length]) withBytes:[iv bytes]];
105 size_t data_out_moved = 0;
106 int ret = CCCrypt(kCCEncrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions,
107 [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [iv bytes],
108 [plaintext_data bytes], [plaintext_data length],
109 [encrypted_data mutableBytes] + [iv length],
110 [encrypted_data length] - [iv length], &data_out_moved);
115 [encrypted_data setLength:[iv length] + data_out_moved];
116 return encrypted_data;
120 @"%s: uncaught error, ret CCCryptorStatus = %d (plaintext len = %lu; buffer size = "
122 __func__, ret, (
unsigned long)[plaintext_data length],
123 (
unsigned long)([encrypted_data length] - [iv length]));
130 - (NSData *)decryptData:(NSData *)encrypted_data
132 if ([encrypted_data length] <= TSXEncryptorBlockCipherBlockSize)
135 NSMutableData *plaintext_data =
136 [NSMutableData dataWithLength:[encrypted_data length] + TSXEncryptorBlockCipherBlockSize];
137 size_t data_out_moved = 0;
140 CCCrypt(kCCDecrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions,
141 [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [encrypted_data bytes],
142 [encrypted_data bytes] + TSXEncryptorBlockCipherBlockSize,
143 [encrypted_data length] - TSXEncryptorBlockCipherBlockSize,
144 [plaintext_data mutableBytes], [plaintext_data length], &data_out_moved);
149 [plaintext_data setLength:data_out_moved];
150 return plaintext_data;
152 case kCCBufferTooSmall:
154 case kCCAlignmentError:
159 NSLog(
@"%s: uncaught error, ret CCCryptorStatus = %d (encrypted data len = %lu; buffer "
160 @"size = %lu; dom = %lu)",
161 __func__, ret, (
unsigned long)[encrypted_data length],
162 (
unsigned long)[plaintext_data length], data_out_moved);
169 - (NSData *)encryptString:(NSString *)plaintext_string
171 return [
self encryptData:[plaintext_string dataUsingEncoding:NSUTF8StringEncoding]];
174 - (NSString *)decryptString:(NSData *)encrypted_string
176 return [[[NSString alloc] initWithData:[
self decryptData:encrypted_string]
177 encoding:NSUTF8StringEncoding] autorelease];
180 - (NSData *)randomInitializationVector
182 NSMutableData *iv = [NSMutableData dataWithLength:TSXEncryptorBlockCipherBlockSize];
185 if ((fd = open(
"/dev/urandom", O_RDONLY)) < 0)
188 NSInteger bytes_needed = [iv length];
189 char *p = [iv mutableBytes];
193 long bytes_read = read(fd, p, bytes_needed);
199 bytes_needed -= bytes_read;