Tool/RSACommands.m
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Commands for RSA-based encryption, decryption, signing, and verification. |
*/ |
#import "RSACommands.h" |
#import "QCCRSASHASignatureCompat.h" |
#import "QCCRSASmallCryptorCompat.h" |
#import "ToolCommon.h" |
#import "QHex.h" |
static BOOL validFileArguments(NSArray * arguments) { |
BOOL success; |
success = YES; |
for (NSString * filePath in arguments) { |
if ([NSURL fileURLWithPath:filePath] == nil) { |
success = NO; |
} |
} |
return success; |
} |
static SecKeyRef keyOfClassWithFile(CFStringRef keyClass, NSString * keyFilePath, NSError **errorPtr) { |
BOOL success; |
OSStatus err; |
NSURL * keyFileURL; |
NSData * keyPEMData; |
SecExternalItemType itemType; |
NSArray * importedKeys; |
SecKeyRef key; |
key = NULL; |
keyFileURL = [NSURL fileURLWithPath:keyFilePath]; |
assert(keyFileURL != nil); // checked by `validFileArguments` |
keyPEMData = [NSData dataWithContentsOfURL:keyFileURL options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (keyPEMData != nil); |
if (success) { |
CFArrayRef importedItems; |
err = SecItemImport( |
(__bridge CFDataRef) keyPEMData, |
CFSTR("pem"), |
NULL, |
&itemType, |
(SecItemImportExportFlags) 0, |
NULL, |
NULL, |
&importedItems |
); |
success = (err == errSecSuccess); |
if (success) { |
importedKeys = CFBridgingRelease(importedItems); |
} else if (errorPtr != NULL) { |
*errorPtr = [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil]; |
} |
} |
if (success) { |
success = (importedKeys.count == 1); |
if (success) { |
switch (itemType) { |
case kSecItemTypePrivateKey: { |
success = CFEqual(keyClass, kSecAttrKeyClassPrivate) != false; |
} break; |
case kSecItemTypePublicKey: { |
success = CFEqual(keyClass, kSecAttrKeyClassPublic) != false; |
} break; |
default: { |
success = NO; |
} break; |
} |
} |
if ( ! success && (errorPtr != NULL) ) { |
*errorPtr = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnsupportedFormat userInfo:nil]; |
} |
} |
if (success) { |
key = (SecKeyRef) CFRetain( (__bridge CFTypeRef) importedKeys[0] ); |
CFAutorelease(key); |
} |
return key; |
} |
static SecKeyRef publicKeyWithFile(NSString * publicKeyFilePath, NSError **errorPtr) { |
return keyOfClassWithFile(kSecAttrKeyClassPublic, publicKeyFilePath, errorPtr); |
} |
static SecKeyRef privateKeyWithFile(NSString * privateKeyFilePath, NSError **errorPtr) { |
return keyOfClassWithFile(kSecAttrKeyClassPrivate, privateKeyFilePath, errorPtr); |
} |
NS_ASSUME_NONNULL_BEGIN |
@interface RSASHAVerifyCommand () |
@property (nonatomic, assign, readwrite) QCCRSASHASignatureCompatAlgorithm algorithm; |
@end |
NS_ASSUME_NONNULL_END |
@implementation RSASHAVerifyCommand |
+ (NSString *)commandName { |
return @"rsa-verify"; |
} |
+ (NSString *)commandUsage { |
return [NSString stringWithFormat:@"%@ -a sha1|sha2-224|sha2-256|sha2-384|sha2-512 publicKeyFile.pem signatureFile dataFile", [self commandName]]; |
} |
- (NSString *)commandOptions { |
return @"a:"; |
} |
- (BOOL)setOption_a_argument:(NSString *)argument { |
BOOL result; |
result = YES; |
if ([argument isEqual:@"sha1"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA1; |
} else if ([argument isEqual:@"sha2-224"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_224; |
} else if ([argument isEqual:@"sha2-256"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_256; |
} else if ([argument isEqual:@"sha2-384"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_384; |
} else if ([argument isEqual:@"sha2-512"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_512; |
} else { |
result = NO; |
} |
return result; |
} |
- (BOOL)validateOptionsAndArguments:(NSArray *)optionsAndArguments { |
BOOL success; |
success = [super validateOptionsAndArguments:optionsAndArguments]; |
if (success) { |
success = (self.arguments.count == 3); |
} |
if (success) { |
success = validFileArguments(self.arguments); |
} |
// We don't check self.algorithm because the default, SHA1, is fine. |
return success; |
} |
- (BOOL)runError:(NSError **)errorPtr { |
BOOL success; |
NSString * publicKeyFilePath; |
NSData * signatureData; |
NSData * fileData; |
SecKeyRef publicKey; |
publicKey = NULL; |
publicKeyFilePath = self.arguments[0]; |
signatureData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:self.arguments[1]] options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (signatureData != nil); |
if (success) { |
fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:self.arguments[2]] options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (fileData != nil); |
} |
if (success) { |
publicKey = publicKeyWithFile(publicKeyFilePath, errorPtr); |
success = (publicKey != NULL); |
} |
if (success) { |
QCCRSASHAVerifyCompat * op; |
op = [[QCCRSASHAVerifyCompat alloc] initWithAlgorithm:self.algorithm inputData:fileData publicKey:publicKey signatureData:signatureData]; |
[[ToolCommon sharedInstance] synchronouslyRunOperation:op]; |
success = (op.error == nil); |
if (success) { |
if (op.verified) { |
fprintf(stdout, "verified\n"); |
} else { |
fprintf(stdout, "not verified\n"); |
} |
} else if (errorPtr != NULL) { |
*errorPtr = op.error; |
} |
} |
return success; |
} |
@end |
NS_ASSUME_NONNULL_BEGIN |
@interface RSASHASignCommand () |
@property (nonatomic, assign, readwrite) QCCRSASHASignatureCompatAlgorithm algorithm; |
@end |
NS_ASSUME_NONNULL_END |
@implementation RSASHASignCommand |
+ (NSString *)commandName { |
return @"rsa-sign"; |
} |
+ (NSString *)commandUsage { |
return [NSString stringWithFormat:@"%@ -a sha1|sha2-224|sha2-256|sha2-384|sha2-512 privateKeyFile.pem file", [self commandName]]; |
} |
- (NSString *)commandOptions { |
return @"a:"; |
} |
- (BOOL)setOption_a_argument:(NSString *)argument { |
BOOL result; |
result = YES; |
if ([argument isEqual:@"sha1"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA1; |
} else if ([argument isEqual:@"sha2-224"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_224; |
} else if ([argument isEqual:@"sha2-256"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_256; |
} else if ([argument isEqual:@"sha2-384"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_384; |
} else if ([argument isEqual:@"sha2-512"]) { |
self.algorithm = QCCRSASHASignatureCompatAlgorithmSHA2_512; |
} else { |
result = NO; |
} |
return result; |
} |
- (BOOL)validateOptionsAndArguments:(NSArray *)optionsAndArguments { |
BOOL success; |
success = [super validateOptionsAndArguments:optionsAndArguments]; |
if (success) { |
success = (self.arguments.count == 2); |
} |
if (success) { |
success = validFileArguments(self.arguments); |
} |
// We don't check self.algorithm because the default, SHA1, is fine. |
return success; |
} |
- (BOOL)runError:(NSError **)errorPtr { |
BOOL success; |
NSString * privateKeyFilePath; |
NSData * fileData; |
SecKeyRef privateKey; |
privateKey = NULL; |
privateKeyFilePath = self.arguments[0]; |
fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:self.arguments[1]] options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (fileData != nil); |
if (success) { |
privateKey = privateKeyWithFile(privateKeyFilePath, errorPtr); |
success = (privateKey != NULL); |
} |
if (success) { |
QCCRSASHASignCompat * op; |
op = [[QCCRSASHASignCompat alloc] initWithAlgorithm:self.algorithm inputData:fileData privateKey:privateKey]; |
[[ToolCommon sharedInstance] synchronouslyRunOperation:op]; |
success = (op.error == nil); |
if (success) { |
fprintf(stdout, "%s\n", [QHex hexStringWithData:op.signatureData].UTF8String); |
} else if (errorPtr != NULL) { |
*errorPtr = op.error; |
} |
} |
return success; |
} |
@end |
NS_ASSUME_NONNULL_BEGIN |
@interface RSACryptorCommand () |
@property (nonatomic, assign, readwrite) QCCRSASmallCryptorCompatPadding padding; |
@end |
NS_ASSUME_NONNULL_END |
@implementation RSACryptorCommand |
- (id)init { |
self = [super init]; |
if (self != nil) { |
self->_padding = QCCRSASmallCryptorCompatPaddingPKCS1; |
} |
return self; |
} |
- (NSString *)commandOptions { |
return @"p:"; |
} |
- (BOOL)setOption_p_argument:(NSString *)argument { |
BOOL result; |
result = YES; |
if ([argument isEqual:@"pkcs1"]) { |
self.padding = QCCRSASmallCryptorCompatPaddingPKCS1; |
} else if ([argument isEqual:@"oaep"]) { |
self.padding = QCCRSASmallCryptorCompatPaddingOAEP; |
} else { |
result = NO; |
} |
return result; |
} |
@end |
NS_ASSUME_NONNULL_BEGIN |
@interface RSASmallEncryptCommand () |
@end |
NS_ASSUME_NONNULL_END |
@implementation RSASmallEncryptCommand |
+ (NSString *)commandName { |
return @"rsa-small-encrypt"; |
} |
+ (NSString *)commandUsage { |
return [NSString stringWithFormat:@"%@ [-p pkcs1|oaep] publicKeyFile.pem file", [self commandName]]; |
} |
- (BOOL)validateOptionsAndArguments:(NSArray *)optionsAndArguments { |
BOOL success; |
success = [super validateOptionsAndArguments:optionsAndArguments]; |
if (success) { |
success = (self.arguments.count == 2); |
} |
if (success) { |
success = validFileArguments(self.arguments); |
} |
return success; |
} |
- (BOOL)runError:(NSError **)errorPtr { |
BOOL success; |
NSString * publicKeyFilePath; |
NSData * fileData; |
SecKeyRef publicKey; |
publicKey = NULL; |
publicKeyFilePath = self.arguments[0]; |
fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:self.arguments[1]] options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (fileData != nil); |
if (success) { |
publicKey = publicKeyWithFile(publicKeyFilePath, errorPtr); |
success = (publicKey != NULL); |
} |
if (success) { |
QCCRSASmallCryptorCompat * op; |
op = [[QCCRSASmallCryptorCompat alloc] initToEncryptSmallInputData:fileData key:publicKey]; |
op.padding = self.padding; |
[[ToolCommon sharedInstance] synchronouslyRunOperation:op]; |
success = (op.error == nil); |
if (success) { |
fprintf(stdout, "%s\n", [QHex hexStringWithData:op.smallOutputData].UTF8String); |
} else if (errorPtr != NULL) { |
*errorPtr = op.error; |
} |
} |
return success; |
} |
@end |
NS_ASSUME_NONNULL_BEGIN |
@interface RSASmallDecryptCommand () |
@end |
NS_ASSUME_NONNULL_END |
@implementation RSASmallDecryptCommand |
+ (NSString *)commandName { |
return @"rsa-small-decrypt"; |
} |
+ (NSString *)commandUsage { |
return [NSString stringWithFormat:@"%@ [-p pkcs1|oaep] privateKeyFile.pem file", [self commandName]]; |
} |
- (BOOL)validateOptionsAndArguments:(NSArray *)optionsAndArguments { |
BOOL success; |
success = [super validateOptionsAndArguments:optionsAndArguments]; |
if (success) { |
success = (self.arguments.count == 2); |
} |
if (success) { |
success = validFileArguments(self.arguments); |
} |
return success; |
} |
- (BOOL)runError:(NSError **)errorPtr { |
BOOL success; |
NSString * privateKeyFilePath; |
NSData * fileData; |
SecKeyRef privateKey; |
privateKey = NULL; |
privateKeyFilePath = self.arguments[0]; |
fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:self.arguments[1]] options:(NSDataReadingOptions) 0 error:errorPtr]; |
success = (fileData != nil); |
if (success) { |
privateKey = privateKeyWithFile(privateKeyFilePath, errorPtr); |
success = (privateKey != NULL); |
} |
if (success) { |
QCCRSASmallCryptorCompat * op; |
op = [[QCCRSASmallCryptorCompat alloc] initToDecryptSmallInputData:fileData key:privateKey]; |
op.padding = self.padding; |
[[ToolCommon sharedInstance] synchronouslyRunOperation:op]; |
success = (op.error == nil); |
if (success) { |
fprintf(stdout, "%s\n", [QHex hexStringWithData:op.smallOutputData].UTF8String); |
} else if (errorPtr != NULL) { |
*errorPtr = op.error; |
} |
} |
return success; |
} |
@end |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-11-17