Tool/CryptorCommands.m
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Commands for symmetric encryption and decryption. |
*/ |
#import "CryptorCommands.h" |
#import "QCCAESCryptor.h" |
#import "QCCAESPadCryptor.h" |
#import "QCCAESPadBigCryptor.h" |
#import "ToolCommon.h" |
#import "QHex.h" |
NS_ASSUME_NONNULL_BEGIN |
@interface AESCryptorCommand () |
@property (nonatomic, copy, readwrite, nullable) NSData * keyData; |
@property (nonatomic, copy, readwrite, nullable) NSData * ivData; |
@property (nonatomic, assign, readwrite) BOOL ecbMode; |
// for subclasses to implement |
+ (Class)cryptorClass; |
+ (BOOL)encrypt; |
- (BOOL)validateArguments; |
@end |
NS_ASSUME_NONNULL_END |
@implementation AESCryptorCommand |
+ (Class)cryptorClass { |
NSAssert(NO, @"implementation required"); |
return nil; |
} |
+ (BOOL)encrypt { |
NSAssert(NO, @"implementation required"); |
return YES; |
} |
- (BOOL)validateArguments { |
return (self.arguments.count == 1); |
} |
+ (NSString *)commandUsage { |
return [NSString stringWithFormat:@"%@ -k keyHexStr (-e | [-i ivHexStr]) file", [self commandName]]; |
} |
- (NSString *)commandOptions { |
return @"k:i:e"; |
} |
- (BOOL)setOption_k_argument:(NSString *)argument { |
self.keyData = [QHex optionalDataWithHexString:argument]; |
return (self.keyData != nil); |
} |
- (BOOL)setOption_i_argument:(NSString *)argument { |
self.ivData = [QHex optionalDataWithHexString:argument]; |
return (self.ivData != nil); |
} |
- (void)setOption_e { |
self.ecbMode = YES; |
} |
- (BOOL)validateOptionsAndArguments:(NSArray *)optionsAndArguments { |
BOOL success; |
success = [super validateOptionsAndArguments:optionsAndArguments]; |
if (success) { |
if ( ! [self validateArguments] ) { |
success = NO; |
} else if (self.keyData == nil) { |
success = NO; |
} else if (self.ecbMode && (self.ivData != nil)) { |
success = NO; // IV is incompatible with ECB |
} |
} |
return success; |
} |
- (BOOL)runError:(NSError **)errorPtr { |
BOOL success; |
NSData * fileData; |
QCCAESCryptor * op; |
fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:self.arguments[0]] options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (fileData != nil); |
if (success) { |
// We're playing fast'n'loose with types here. The various cryptor operations |
// don't share a command base class (becasue I don't want to have them coupled together) |
// so we don't have a class we can use for "op". Rather than write lots of pointless |
// code just to keep the compiler happy, I tell the compile that "op" is of type |
// QCCAESCryptor. In reality it could be any of the other cryptor classes. |
if ([[self class] encrypt]) { |
op = [[[[self class] cryptorClass] alloc] initToEncryptInputData:fileData keyData:self.keyData]; |
} else { |
op = [[[[self class] cryptorClass] alloc] initToDecryptInputData:fileData keyData:self.keyData]; |
} |
if (self.ecbMode) { |
op.ivData = nil; |
} else if (self.ivData != nil) { |
op.ivData = self.ivData; |
} |
[[ToolCommon sharedInstance] synchronouslyRunOperation:op]; |
if (op.error == nil) { |
(void) fwrite(op.outputData.bytes, op.outputData.length, 1, stdout); |
} else { |
if (errorPtr != NULL) { |
*errorPtr = op.error; |
} |
success = NO; |
} |
} |
return success; |
} |
@end |
@implementation AESEncryptCommand |
+ (NSString *)commandName { |
return @"aes-encrypt"; |
} |
+ (Class)cryptorClass { |
return [QCCAESCryptor class]; |
} |
+ (BOOL)encrypt { |
return YES; |
} |
@end |
@implementation AESDecryptCommand |
+ (NSString *)commandName { |
return @"aes-decrypt"; |
} |
+ (Class)cryptorClass { |
return [QCCAESCryptor class]; |
} |
+ (BOOL)encrypt { |
return NO; |
} |
@end |
@implementation AESPadEncryptCommand |
+ (NSString *)commandName { |
return @"aes-pad-encrypt"; |
} |
+ (Class)cryptorClass { |
return [QCCAESPadCryptor class]; |
} |
+ (BOOL)encrypt { |
return YES; |
} |
@end |
@implementation AESPadDecryptCommand |
+ (NSString *)commandName { |
return @"aes-pad-decrypt"; |
} |
+ (Class)cryptorClass { |
return [QCCAESPadCryptor class]; |
} |
+ (BOOL)encrypt { |
return NO; |
} |
@end |
@implementation AESBigCryptorCommand |
- (BOOL)validateArguments { |
return (self.arguments.count == 2); |
} |
+ (NSString *)commandUsage { |
return [NSString stringWithFormat:@"%@ -k keyHexStr (-e | [-i ivHexStr]) inputFile outputFile", [self commandName]]; |
} |
- (BOOL)runError:(NSError **)errorPtr { |
BOOL success; |
NSInputStream * inputStream; |
NSOutputStream * outputStream; |
QCCAESPadBigCryptor * op; |
inputStream = [NSInputStream inputStreamWithFileAtPath:self.arguments[0]]; |
success = (inputStream != nil); |
if (success) { |
outputStream = [NSOutputStream outputStreamToFileAtPath:self.arguments[1] append:NO]; |
success = (outputStream != nil); |
} |
if (success) { |
// We're playing fast'n'loose with types here. The various cryptor operations |
// don't share a command base class (becasue I don't want to have them coupled together) |
// so we don't have a class we can use for "op". Rather than write lots of pointless |
// code just to keep the compiler happy, I tell the compile that "op" is of type |
// QCCAESPadBigCryptor. In reality it could be any of the other cryptor classes. |
if ([[self class] encrypt]) { |
op = [[[[self class] cryptorClass] alloc] initToEncryptInputStream:inputStream toOutputStream:outputStream keyData:self.keyData]; |
} else { |
op = [[[[self class] cryptorClass] alloc] initToDecryptInputStream:inputStream toOutputStream:outputStream keyData:self.keyData]; |
} |
if (self.ecbMode) { |
op.ivData = nil; |
} else if (self.ivData != nil) { |
op.ivData = self.ivData; |
} |
[[ToolCommon sharedInstance] synchronouslyRunOperation:op]; |
if (op.error != nil) { |
if (errorPtr != NULL) { |
*errorPtr = op.error; |
} |
success = NO; |
} |
} |
return success; |
} |
@end |
@implementation AESPadBigEncryptCommand |
+ (NSString *)commandName { |
return @"aes-pad-big-encrypt"; |
} |
+ (Class)cryptorClass { |
return [QCCAESPadBigCryptor class]; |
} |
+ (BOOL)encrypt { |
return YES; |
} |
@end |
@implementation AESPadBigDecryptCommand |
+ (NSString *)commandName { |
return @"aes-pad-big-decrypt"; |
} |
+ (Class)cryptorClass { |
return [QCCAESPadBigCryptor class]; |
} |
+ (BOOL)encrypt { |
return NO; |
} |
@end |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-11-17