Operations/QCCRSASmallCryptor.m
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Implements RSA encryption and decryption using the unified crypto API. |
*/ |
#import "QCCRSASmallCryptor.h" |
typedef NS_ENUM(NSInteger, QCCRSASmallCryptorOperation) { |
QCCRSASmallCryptorOperationEncrypt, |
QCCRSASmallCryptorOperationDecrypt |
}; |
NS_ASSUME_NONNULL_BEGIN |
@interface QCCRSASmallCryptor () |
- (instancetype)initWithOperation:(QCCRSASmallCryptorOperation)op smallInputData:(NSData *)smallInputData key:(SecKeyRef)key NS_DESIGNATED_INITIALIZER; |
@property (atomic, assign, readonly ) QCCRSASmallCryptorOperation op; |
// read/write versions of public properties |
@property (atomic, copy, readwrite, nullable) NSError * error; |
@property (atomic, copy, readwrite, nullable) NSData * smallOutputData; |
@end |
NS_ASSUME_NONNULL_END |
@implementation QCCRSASmallCryptor |
- (instancetype)init { |
abort(); |
} |
- (instancetype)initWithOperation:(QCCRSASmallCryptorOperation)op smallInputData:(NSData *)smallInputData key:(SecKeyRef)key { |
NSParameterAssert(smallInputData != nil); |
NSParameterAssert(key != NULL); |
self = [super init]; |
if (self != nil) { |
self->_op = op; |
self->_smallInputData = [smallInputData copy]; |
self->_key = key; |
self->_padding = QCCRSASmallCryptorPaddingPKCS1; |
} |
return self; |
} |
- (instancetype)initToEncryptSmallInputData:(NSData *)smallInputData key:(SecKeyRef)key { |
return [self initWithOperation:QCCRSASmallCryptorOperationEncrypt smallInputData:smallInputData key:key]; |
} |
- (instancetype)initToDecryptSmallInputData:(NSData *)smallInputData key:(SecKeyRef)key { |
return [self initWithOperation:QCCRSASmallCryptorOperationDecrypt smallInputData:smallInputData key:key]; |
} |
- (void)runUsingUnified { |
CFErrorRef errorCF = NULL; // Security framework seems to be grumpy if errorCF left uninitialised |
SecKeyAlgorithm algorithm; |
NSData * resultData; |
// Map our padding constant appropriately. |
switch (self.padding) { |
default: |
assert(NO); |
// fall through |
case QCCRSASmallCryptorPaddingPKCS1: { |
algorithm = kSecKeyAlgorithmRSAEncryptionPKCS1; |
} break; |
case QCCRSASmallCryptorPaddingOAEP: { |
algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA1; |
} break; |
} |
// Do the crypto. |
switch (self.op) { |
default: |
assert(NO); |
// fall through |
case QCCRSASmallCryptorOperationEncrypt: { |
resultData = CFBridgingRelease( SecKeyCreateEncryptedData( |
self.key, |
algorithm, |
(__bridge CFDataRef) self.smallInputData, |
&errorCF |
) ); |
} break; |
case QCCRSASmallCryptorOperationDecrypt: { |
resultData = CFBridgingRelease( SecKeyCreateDecryptedData( |
self.key, |
algorithm, |
(__bridge CFDataRef) self.smallInputData, |
&errorCF |
) ); |
} break; |
} |
// Set up the result. |
if (resultData == nil) { |
self.error = CFBridgingRelease( errorCF ); |
} else { |
self.smallOutputData = resultData; |
} |
} |
- (void)main { |
OSStatus err; |
NSUInteger smallInputDataLength; |
NSUInteger keyBlockSize; |
smallInputDataLength = self.smallInputData.length; |
keyBlockSize = SecKeyGetBlockSize(self.key); |
// Check that the input data length makes sense. In most cases these checks are |
// redundant (because the underlying crypto operation does the same checks) but |
// it's good to have them here to help with debugging. If you get the length |
// wrong, you can set a breakpoint here and learn what's wrong. |
err = errSecSuccess; |
switch (self.op) { |
default: |
assert(NO); |
// fall through |
case QCCRSASmallCryptorOperationEncrypt: { |
switch (self.padding) { |
default: |
assert(NO); |
// fall through |
case QCCRSASmallCryptorPaddingPKCS1: { |
assert(keyBlockSize > 11); |
if ((smallInputDataLength + 11) > keyBlockSize) { |
err = errSecParam; |
} |
} break; |
case QCCRSASmallCryptorPaddingOAEP: { |
// 42 is 2 + 2 * HashLen, where HashLen is the length of the hash |
// use by the OAEP algorithm. We currently only support OAEP with SHA1, |
// which has a hash length of 20. |
assert(keyBlockSize > 42); |
if ((smallInputDataLength + 42) > keyBlockSize) { |
err = errSecParam; |
} |
} break; |
} |
} break; |
case QCCRSASmallCryptorOperationDecrypt: { |
if (smallInputDataLength != keyBlockSize) { |
err = errSecParam; |
} |
} break; |
} |
// If everything is OK, call the real code. |
if (err != errSecSuccess) { |
self.error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecParam userInfo:nil]; |
} else { |
[self runUsingUnified]; |
} |
} |
@end |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-11-17