#import <Foundation/Foundation.h> #import "NSData+CommonCrypto.h" #import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonCryptor.h> #import <CommonCrypto/CommonHMAC.h>
NSString * const kCommonCryptoErrorDomain = @"CommonCryptoErrorDomain";
@implementation NSError (CommonCryptoErrorDomain)
+ (NSError *) errorWithCCCryptorStatus: (CCCryptorStatus) status { NSString * description = nil, * reason = nil; switch ( status ) { case kCCSuccess: description = NSLocalizedString(@"Success", @"Error description"); break; case kCCParamError: description = NSLocalizedString(@"Parameter Error", @"Error description"); reason = NSLocalizedString(@"Illegal parameter supplied to encryption/decryption algorithm", @"Error reason"); break; case kCCBufferTooSmall: description = NSLocalizedString(@"Buffer Too Small", @"Error description"); reason = NSLocalizedString(@"Insufficient buffer provided for specified operation", @"Error reason"); break; case kCCMemoryFailure: description = NSLocalizedString(@"Memory Failure", @"Error description"); reason = NSLocalizedString(@"Failed to allocate memory", @"Error reason"); break; case kCCAlignmentError: description = NSLocalizedString(@"Alignment Error", @"Error description"); reason = NSLocalizedString(@"Input size to encryption algorithm was not aligned correctly", @"Error reason"); break; case kCCDecodeError: description = NSLocalizedString(@"Decode Error", @"Error description"); reason = NSLocalizedString(@"Input data did not decode or decrypt correctly", @"Error reason"); break; case kCCUnimplemented: description = NSLocalizedString(@"Unimplemented Function", @"Error description"); reason = NSLocalizedString(@"Function not implemented for the current algorithm", @"Error reason"); break; default: description = NSLocalizedString(@"Unknown Error", @"Error description"); break; } NSMutableDictionary * userInfo = [[NSMutableDictionary alloc] init]; [userInfo setObject: description forKey: NSLocalizedDescriptionKey]; if ( reason != nil ) [userInfo setObject: reason forKey: NSLocalizedFailureReasonErrorKey]; NSError * result = [NSError errorWithDomain: kCommonCryptoErrorDomain code: status userInfo: userInfo]; #if !__has_feature(objc_arc) [userInfo release]; #endif return ( result ); }
@end
#pragma mark -
@implementation NSData (CommonDigest)
- (NSData *) MD2Sum { unsigned char hash[CC_MD2_DIGEST_LENGTH]; (void) CC_MD2( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_MD2_DIGEST_LENGTH] ); }
- (NSData *) MD4Sum { unsigned char hash[CC_MD4_DIGEST_LENGTH]; (void) CC_MD4( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_MD4_DIGEST_LENGTH] ); }
- (NSData *) MD5Sum { unsigned char hash[CC_MD5_DIGEST_LENGTH]; (void) CC_MD5( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_MD5_DIGEST_LENGTH] ); }
- (NSData *) SHA1Hash { unsigned char hash[CC_SHA1_DIGEST_LENGTH]; (void) CC_SHA1( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_SHA1_DIGEST_LENGTH] ); }
- (NSData *) SHA224Hash { unsigned char hash[CC_SHA224_DIGEST_LENGTH]; (void) CC_SHA224( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_SHA224_DIGEST_LENGTH] ); }
- (NSData *) SHA256Hash { unsigned char hash[CC_SHA256_DIGEST_LENGTH]; (void) CC_SHA256( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_SHA256_DIGEST_LENGTH] ); }
- (NSData *) SHA384Hash { unsigned char hash[CC_SHA384_DIGEST_LENGTH]; (void) CC_SHA384( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_SHA384_DIGEST_LENGTH] ); }
- (NSData *) SHA512Hash { unsigned char hash[CC_SHA512_DIGEST_LENGTH]; (void) CC_SHA512( [self bytes], (CC_LONG)[self length], hash ); return ( [NSData dataWithBytes: hash length: CC_SHA512_DIGEST_LENGTH] ); }
@end
@implementation NSData (CommonCryptor)
- (NSData *) AES256EncryptedDataUsingKey: (id) key error: (NSError **) error { CCCryptorStatus status = kCCSuccess; NSData * result = [self dataEncryptedUsingAlgorithm: kCCAlgorithmAES128 key: key options: kCCOptionPKCS7Padding error: &status]; if ( result != nil ) return ( result ); if ( error != NULL ) *error = [NSError errorWithCCCryptorStatus: status]; return ( nil ); }
- (NSData *) decryptedAES256DataUsingKey: (id) key error: (NSError **) error { CCCryptorStatus status = kCCSuccess; NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmAES128 key: key options: kCCOptionPKCS7Padding error: &status]; if ( result != nil ) return ( result ); if ( error != NULL ) *error = [NSError errorWithCCCryptorStatus: status]; return ( nil ); }
- (NSData *) DESEncryptedDataUsingKey: (id) key error: (NSError **) error { CCCryptorStatus status = kCCSuccess; NSData * result = [self dataEncryptedUsingAlgorithm: kCCAlgorithmDES key: key options: kCCOptionPKCS7Padding error: &status]; if ( result != nil ) return ( result ); if ( error != NULL ) *error = [NSError errorWithCCCryptorStatus: status]; return ( nil ); }
- (NSData *) decryptedDESDataUsingKey: (id) key error: (NSError **) error { CCCryptorStatus status = kCCSuccess; NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmDES key: key options: kCCOptionPKCS7Padding error: &status]; if ( result != nil ) return ( result ); if ( error != NULL ) *error = [NSError errorWithCCCryptorStatus: status]; return ( nil ); }
- (NSData *) CASTEncryptedDataUsingKey: (id) key error: (NSError **) error { CCCryptorStatus status = kCCSuccess; NSData * result = [self dataEncryptedUsingAlgorithm: kCCAlgorithmCAST key: key options: kCCOptionPKCS7Padding error: &status]; if ( result != nil ) return ( result ); if ( error != NULL ) *error = [NSError errorWithCCCryptorStatus: status]; return ( nil ); }
- (NSData *) decryptedCASTDataUsingKey: (id) key error: (NSError **) error { CCCryptorStatus status = kCCSuccess; NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmCAST key: key options: kCCOptionPKCS7Padding error: &status]; if ( result != nil ) return ( result ); if ( error != NULL ) *error = [NSError errorWithCCCryptorStatus: status]; return ( nil ); }
@end
static void FixKeyLengths( CCAlgorithm algorithm, NSMutableData * keyData, NSMutableData * ivData ) { NSUInteger keyLength = [keyData length]; switch ( algorithm ) { case kCCAlgorithmAES128: { if ( keyLength < 16 ) { [keyData setLength: 16]; } else if ( keyLength < 24 ) { [keyData setLength: 24]; } else { [keyData setLength: 32]; } break; } case kCCAlgorithmDES: { [keyData setLength: 8]; break; } case kCCAlgorithm3DES: { [keyData setLength: 24]; break; } case kCCAlgorithmCAST: { if ( keyLength < 5 ) { [keyData setLength: 5]; } else if ( keyLength > 16 ) { [keyData setLength: 16]; } break; } case kCCAlgorithmRC4: { if ( keyLength > 512 ) [keyData setLength: 512]; break; } default: break; } [ivData setLength: [keyData length]]; }
@implementation NSData (LowLevelCommonCryptor)
- (NSData *) _runCryptor: (CCCryptorRef) cryptor result: (CCCryptorStatus *) status { size_t bufsize = CCCryptorGetOutputLength( cryptor, (size_t)[self length], true ); void * buf = malloc( bufsize ); size_t bufused = 0; size_t bytesTotal = 0; *status = CCCryptorUpdate( cryptor, [self bytes], (size_t)[self length], buf, bufsize, &bufused ); if ( *status != kCCSuccess ) { free( buf ); return ( nil ); } bytesTotal += bufused; *status = CCCryptorFinal( cryptor, buf + bufused, bufsize - bufused, &bufused ); if ( *status != kCCSuccess ) { free( buf ); return ( nil ); } bytesTotal += bufused; return ( [NSData dataWithBytesNoCopy: buf length: bytesTotal] ); }
- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm key: (id) key error: (CCCryptorStatus *) error { return ( [self dataEncryptedUsingAlgorithm: algorithm key: key initializationVector: nil options: 0 error: error] ); }
- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm key: (id) key options: (CCOptions) options error: (CCCryptorStatus *) error { return ( [self dataEncryptedUsingAlgorithm: algorithm key: key initializationVector: nil options: options error: error] ); }
- (NSData *) dataEncryptedUsingAlgorithm: (CCAlgorithm) algorithm key: (id) key initializationVector: (id) iv options: (CCOptions) options error: (CCCryptorStatus *) error { CCCryptorRef cryptor = NULL; CCCryptorStatus status = kCCSuccess; NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]); NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]); NSMutableData * keyData, * ivData; if ( [key isKindOfClass: [NSData class]] ) keyData = (NSMutableData *) [key mutableCopy]; else keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy]; if ( [iv isKindOfClass: [NSString class]] ) ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy]; else ivData = (NSMutableData *) [iv mutableCopy]; #if !__has_feature(objc_arc) [keyData autorelease]; [ivData autorelease]; #endif FixKeyLengths( algorithm, keyData, ivData ); status = CCCryptorCreate( kCCEncrypt, algorithm, options, [keyData bytes], [keyData length], [ivData bytes], &cryptor ); if ( status != kCCSuccess ) { if ( error != NULL ) *error = status; return ( nil ); } NSData * result = [self _runCryptor: cryptor result: &status]; if ( (result == nil) && (error != NULL) ) *error = status; CCCryptorRelease( cryptor ); return ( result ); }
- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm key: (id) key error: (CCCryptorStatus *) error { return ( [self decryptedDataUsingAlgorithm: algorithm key: key initializationVector: nil options: 0 error: error] ); }
- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm key: (id) key options: (CCOptions) options error: (CCCryptorStatus *) error { return ( [self decryptedDataUsingAlgorithm: algorithm key: key initializationVector: nil options: options error: error] ); }
- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm key: (id) key initializationVector: (id) iv options: (CCOptions) options error: (CCCryptorStatus *) error { CCCryptorRef cryptor = NULL; CCCryptorStatus status = kCCSuccess; NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]); NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]); NSMutableData * keyData, * ivData; if ( [key isKindOfClass: [NSData class]] ) keyData = (NSMutableData *) [key mutableCopy]; else keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy]; if ( [iv isKindOfClass: [NSString class]] ) ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy]; else ivData = (NSMutableData *) [iv mutableCopy]; #if !__has_feature(objc_arc) [keyData autorelease]; [ivData autorelease]; #endif FixKeyLengths( algorithm, keyData, ivData ); status = CCCryptorCreate( kCCDecrypt, algorithm, options, [keyData bytes], [keyData length], [ivData bytes], &cryptor ); if ( status != kCCSuccess ) { if ( error != NULL ) *error = status; return ( nil ); } NSData * result = [self _runCryptor: cryptor result: &status]; if ( (result == nil) && (error != NULL) ) *error = status; CCCryptorRelease( cryptor ); return ( result ); }
@end
@implementation NSData (CommonHMAC)
- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm { return ( [self HMACWithAlgorithm: algorithm key: nil] ); }
- (NSData *) HMACWithAlgorithm: (CCHmacAlgorithm) algorithm key: (id) key { NSParameterAssert(key == nil || [key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]); NSData * keyData = nil; if ( [key isKindOfClass: [NSString class]] ) keyData = [key dataUsingEncoding: NSUTF8StringEncoding]; else keyData = (NSData *) key; unsigned char buf[CC_SHA1_DIGEST_LENGTH]; CCHmac( algorithm, [keyData bytes], [keyData length], [self bytes], [self length], buf ); return ( [NSData dataWithBytes: buf length: (algorithm == kCCHmacAlgMD5 ? CC_MD5_DIGEST_LENGTH : CC_SHA1_DIGEST_LENGTH)] ); }
@end
|