123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- //
- // RNEncryptor
- //
- // Copyright (c) 2012 Rob Napier
- //
- // This code is licensed under the MIT License:
- //
- // Permission is hereby granted, free of charge, to any person obtaining a
- // copy of this software and associated documentation files (the "Software"),
- // to deal in the Software without restriction, including without limitation
- // the rights to use, copy, modify, merge, publish, distribute, sublicense,
- // and/or sell copies of the Software, and to permit persons to whom the
- // Software is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- //
- #import "RNEncryptor.h"
- #import "RNCryptor+Private.h"
- #import "RNCryptorEngine.h"
- #import <CommonCrypto/CommonHMAC.h>
- @interface RNEncryptor ()
- @property (nonatomic, readwrite, strong) NSData *encryptionSalt;
- @property (nonatomic, readwrite, strong) NSData *HMACSalt;
- @property (nonatomic, readwrite, strong) NSData *IV;
- @property (nonatomic, readwrite, assign) BOOL haveWrittenHeader;
- @end
- @implementation RNEncryptor
- {
- CCHmacContext _HMACContext;
- }
- @synthesize encryptionSalt = _encryptionSalt;
- @synthesize HMACSalt = _HMACSalt;
- @synthesize IV = _IV;
- @synthesize haveWrittenHeader = _haveWrittenHeader;
- + (NSData *)encryptData:(NSData *)thePlaintext withSettings:(RNCryptorSettings)theSettings password:(NSString *)aPassword error:(NSError **)anError
- {
- RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings
- password:aPassword
- handler:^(RNCryptor *c, NSData *d) {}];
- return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError];
- }
- + (NSData *)encryptData:(NSData *)thePlaintext
- withSettings:(RNCryptorSettings)theSettings
- password:(NSString *)aPassword
- IV:(NSData *)anIV
- encryptionSalt:(NSData *)anEncryptionSalt
- HMACSalt:(NSData *)anHMACSalt
- error:(NSError **)anError
- {
- RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings
- password:aPassword
- IV:anIV
- encryptionSalt:anEncryptionSalt
- HMACSalt:anHMACSalt
- handler:^(RNCryptor *c, NSData *d) {}];
- return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError];
- }
- + (NSData *)encryptData:(NSData *)thePlaintext withSettings:(RNCryptorSettings)theSettings encryptionKey:(NSData *)anEncryptionKey HMACKey:(NSData *)anHMACKey error:(NSError **)anError {
- RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings
- encryptionKey:anEncryptionKey
- HMACKey:anHMACKey
- handler:^(RNCryptor *c, NSData *d) {}];
- return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError];
- }
- + (NSData *)encryptData:(NSData *)thePlaintext
- withSettings:(RNCryptorSettings)theSettings
- encryptionKey:(NSData *)anEncryptionKey
- HMACKey:(NSData *)anHMACKey
- IV:(NSData *)anIV
- error:(NSError **)anError
- {
- RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings
- encryptionKey:anEncryptionKey
- HMACKey:anHMACKey
- IV:anIV
- handler:^(RNCryptor *c, NSData *d) {}];
- return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError];
- }
- - (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings
- encryptionKey:(NSData *)anEncryptionKey
- HMACKey:(NSData *)anHMACKey
- handler:(RNCryptorHandler)aHandler {
- return [self initWithSettings:kRNCryptorAES256Settings
- encryptionKey:anEncryptionKey
- HMACKey:anHMACKey
- IV:[[self class] randomDataOfLength:theSettings.IVSize]
- handler:aHandler];
- }
- - (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings
- encryptionKey:(NSData *)anEncryptionKey
- HMACKey:(NSData *)anHMACKey
- IV:(NSData *)anIV
- handler:(RNCryptorHandler)aHandler
- {
- self = [super initWithHandler:aHandler];
- if (self) {
- self.IV = anIV;
- if (anHMACKey) {
- CCHmacInit(&_HMACContext, theSettings.HMACAlgorithm, anHMACKey.bytes, anHMACKey.length);
- self.HMACLength = theSettings.HMACLength;
- }
- NSError *error = nil;
- self.engine = [[RNCryptorEngine alloc] initWithOperation:kCCEncrypt
- settings:theSettings
- key:anEncryptionKey
- IV:self.IV
- error:&error];
- if (!self.engine) {
- [self cleanupAndNotifyWithError:error];
- self = nil;
- return nil;
- }
- }
- return self;
- }
- - (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings password:(NSString *)aPassword handler:(RNCryptorHandler)aHandler {
- return [self initWithSettings:theSettings
- password:aPassword
- IV:[[self class] randomDataOfLength:theSettings.IVSize]
- encryptionSalt:[[self class] randomDataOfLength:theSettings.keySettings.saltSize]
- HMACSalt:[[self class] randomDataOfLength:theSettings.HMACKeySettings.saltSize]
- handler:aHandler];
- }
- - (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings
- password:(NSString *)aPassword
- IV:(NSData *)anIV
- encryptionSalt:(NSData *)anEncryptionSalt
- HMACSalt:(NSData *)anHMACSalt
- handler:(RNCryptorHandler)aHandler;
- {
- NSParameterAssert(aPassword.length > 0); // We'll go forward, but this is undefined behavior for RNCryptor
- NSParameterAssert(anIV);
- NSParameterAssert(anEncryptionSalt);
- NSParameterAssert(anHMACSalt);
- NSData *encryptionKey = [[self class] keyForPassword:aPassword salt:anEncryptionSalt settings:theSettings.keySettings];
- NSData *HMACKey = [[self class] keyForPassword:aPassword salt:anHMACSalt settings:theSettings.HMACKeySettings];
- self = [self initWithSettings:theSettings
- encryptionKey:encryptionKey
- HMACKey:HMACKey
- IV:anIV
- handler:aHandler];
- if (self) {
- self.options |= kRNCryptorOptionHasPassword;
- self.encryptionSalt = anEncryptionSalt;
- self.HMACSalt = anHMACSalt;
- }
- return self;
- }
- - (NSData *)header
- {
- uint8_t header[2] = {kRNCryptorFileVersion, self.options};
- NSMutableData *headerData = [NSMutableData dataWithBytes:header length:sizeof(header)];
- if (self.options & kRNCryptorOptionHasPassword) {
- [headerData appendData:self.encryptionSalt];
- [headerData appendData:self.HMACSalt];
- }
- [headerData appendData:self.IV];
- return headerData;
- }
- - (void)addData:(NSData *)data
- {
- if (self.isFinished) {
- return;
- }
- dispatch_async(self.queue, ^{
- if (!self.haveWrittenHeader) {
- NSData *header = [self header];
- [self.outData setData:header];
- if (self.hasHMAC) {
- CCHmacUpdate(&_HMACContext, [header bytes], [header length]);
- }
- self.haveWrittenHeader = YES;
- }
- NSError *error = nil;
- NSData *encryptedData = [self.engine addData:data error:&error];
- if (!encryptedData) {
- [self cleanupAndNotifyWithError:error];
- }
- if (self.hasHMAC) {
- CCHmacUpdate(&_HMACContext, encryptedData.bytes, encryptedData.length);
- }
- [self.outData appendData:encryptedData];
- dispatch_sync(self.responseQueue, ^{
- self.handler(self, self.outData);
- });
- [self.outData setLength:0];
- });
- }
- - (void)finish
- {
- if (self.isFinished) {
- return;
- }
- dispatch_async(self.queue, ^{
- NSError *error = nil;
- NSData *encryptedData = [self.engine finishWithError:&error];
- [self.outData appendData:encryptedData];
- if (self.hasHMAC) {
- CCHmacUpdate(&_HMACContext, encryptedData.bytes, encryptedData.length);
- NSMutableData *HMACData = [NSMutableData dataWithLength:self.HMACLength];
- CCHmacFinal(&_HMACContext, [HMACData mutableBytes]);
- [self.outData appendData:HMACData];
- }
- [self cleanupAndNotifyWithError:error];
- });
- }
- @end
|