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;