123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- #import "RNCryptor.h"
- #import "RNCryptor+Private.h"
- #import <CommonCrypto/CommonCryptor.h>
- #import <CommonCrypto/CommonKeyDerivation.h>
- #import <Security/SecRandom.h>
- #import <fcntl.h>
- const RNCryptorSettings kRNCryptorAES256Settings = {
- .algorithm = kCCAlgorithmAES128,
- .blockSize = kCCBlockSizeAES128,
- .IVSize = kCCBlockSizeAES128,
- .options = kCCOptionPKCS7Padding,
- .HMACAlgorithm = kCCHmacAlgSHA256,
- .HMACLength = CC_SHA256_DIGEST_LENGTH,
- .keySettings = {
- .keySize = kCCKeySizeAES256,
- .saltSize = 8,
- .PBKDFAlgorithm = kCCPBKDF2,
- .PRF = kCCPRFHmacAlgSHA1,
- .rounds = 10000
- },
- .HMACKeySettings = {
- .keySize = kCCKeySizeAES256,
- .saltSize = 8,
- .PBKDFAlgorithm = kCCPBKDF2,
- .PRF = kCCPRFHmacAlgSHA1,
- .rounds = 10000
- }
- };
- extern int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) __attribute__((weak_import));
- extern int
- CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
- const uint8_t *salt, size_t saltLen,
- CCPseudoRandomAlgorithm prf, uint rounds,
- uint8_t *derivedKey, size_t derivedKeyLen) __attribute__((weak_import));
- NSString *const kRNCryptorErrorDomain = @"net.robnapier.RNCryptManager";
- const uint8_t kRNCryptorFileVersion = 3;
- @implementation NSMutableData (RNCryptor)
- - (NSData *)_RNConsumeToIndex:(NSUInteger)index
- {
- NSData *removed = [self subdataWithRange:NSMakeRange(0, index)];
- [self replaceBytesInRange:NSMakeRange(0, self.length - index) withBytes:([self mutableBytes] + index)];
- [self setLength:self.length - index];
- return removed;
- }
- @end
- @implementation RNCryptor
- @synthesize responseQueue = _responseQueue;
- @synthesize engine = _engine;
- @synthesize outData = __outData;
- @synthesize queue = _queue;
- @synthesize HMACLength = __HMACLength;
- @synthesize error = _error;
- @synthesize finished = _finished;
- @synthesize options = _options;
- @synthesize handler = _handler;
- + (NSData *)synchronousResultForCryptor:(RNCryptor *)cryptor data:(NSData *)inData error:(NSError **)anError
- {
- dispatch_semaphore_t sem = dispatch_semaphore_create(0);
- NSMutableData *data = [NSMutableData data];
- __block NSError *returnedError = nil;
- RNCryptorHandler handler = ^(RNCryptor *c, NSData *d) {
- [data appendData:d];
- if (c.isFinished) {
- returnedError = c.error;
- dispatch_semaphore_signal(sem);
- }
- };
- cryptor.handler = handler;
- dispatch_queue_t queue = dispatch_queue_create("net.robnapier.RNEncryptor.response", DISPATCH_QUEUE_SERIAL);
- cryptor.responseQueue = queue;
- [cryptor addData:inData];
- [cryptor finish];
- dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
- #if !OS_OBJECT_USE_OBJC
- dispatch_release(sem);
- if (queue) {
- dispatch_release(queue);
- }
- #endif
- if (returnedError) {
- if (anError) {
- *anError = returnedError;
- }
- return nil;
- }
- else {
- return data;
- }
- }
- #define CC_MAX_PRF_WORKSPACE 128+4
- #define kCCPRFHmacAlgSHA1hlen CC_SHA1_DIGEST_LENGTH
- #define kCCPRFHmacAlgSHA224hlen CC_SHA224_DIGEST_LENGTH
- #define kCCPRFHmacAlgSHA256hlen CC_SHA256_DIGEST_LENGTH
- #define kCCPRFHmacAlgSHA384hlen CC_SHA384_DIGEST_LENGTH
- #define kCCPRFHmacAlgSHA512hlen CC_SHA512_DIGEST_LENGTH
- static size_t
- getPRFhlen(CCPseudoRandomAlgorithm prf)
- {
- switch(prf) {
- case kCCPRFHmacAlgSHA1: return kCCPRFHmacAlgSHA1hlen;
- case kCCPRFHmacAlgSHA224: return kCCPRFHmacAlgSHA224hlen;
- case kCCPRFHmacAlgSHA256: return kCCPRFHmacAlgSHA256hlen;
- case kCCPRFHmacAlgSHA384: return kCCPRFHmacAlgSHA384hlen;
- case kCCPRFHmacAlgSHA512: return kCCPRFHmacAlgSHA512hlen;
- default:
- NSCAssert(NO, @"Unknown prf: %d", prf);
- return 1;
- }
- }
- static void
- PRF(CCPseudoRandomAlgorithm prf, const char *password, size_t passwordLen, u_int8_t *salt, size_t saltLen, u_int8_t *output)
- {
- switch(prf) {
- case kCCPRFHmacAlgSHA1:
- CCHmac(kCCHmacAlgSHA1, password, passwordLen, salt, saltLen, output);
- break;
- case kCCPRFHmacAlgSHA224:
- CCHmac(kCCHmacAlgSHA224, password, passwordLen, salt, saltLen, output);
- break;
- case kCCPRFHmacAlgSHA256:
- CCHmac(kCCHmacAlgSHA256, password, passwordLen, salt, saltLen, output);
- break;
- case kCCPRFHmacAlgSHA384:
- CCHmac(kCCHmacAlgSHA384, password, passwordLen, salt, saltLen, output);
- break;
- case kCCPRFHmacAlgSHA512:
- CCHmac(kCCHmacAlgSHA512, password, passwordLen, salt, saltLen, output);
- break;
- }
- }
- static int
- RN_CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
- const uint8_t *salt, size_t saltLen,
- CCPseudoRandomAlgorithm prf, uint rounds,
- uint8_t *derivedKey, size_t derivedKeyLen)
- {
- u_int8_t oldbuffer[CC_MAX_PRF_WORKSPACE], newbuffer[CC_MAX_PRF_WORKSPACE],
- saltCopy[CC_MAX_PRF_WORKSPACE+4], collector[CC_MAX_PRF_WORKSPACE];
- int rawblock, i, j;
- size_t r, nblocks;
- size_t hlen, offset;
- if(algorithm != kCCPBKDF2) return -1;
-
- if (rounds < 1 || derivedKeyLen == 0)
- return -1;
- if (saltLen == 0 || saltLen > CC_MAX_PRF_WORKSPACE)
- return -1;
- hlen = getPRFhlen(prf);
-
- nblocks = (derivedKeyLen+hlen-1)/hlen;
- r = derivedKeyLen % hlen;
- r = (r) ? r: hlen;
-
- memcpy(saltCopy, salt, saltLen);
- bzero(derivedKey, derivedKeyLen);
-
- for(rawblock = 0; rawblock < nblocks; rawblock++) {
- int block = rawblock+1;
- size_t copyLen;
- offset = rawblock * hlen;
- copyLen = (block != nblocks) ? hlen: r;
-
- for(i=0; i<4; i++) saltCopy[saltLen+i] = (block >> 8*(3-i)) & 0xff;
- PRF(prf, password, passwordLen, saltCopy, saltLen+4, oldbuffer);
- memcpy(collector, oldbuffer, hlen);
- for(i = 1; i < rounds; i++) {
- PRF(prf, password, passwordLen, oldbuffer, hlen, newbuffer);
- memcpy(oldbuffer, newbuffer, hlen);
- for(j = 0; j < hlen; j++) collector[j] ^= newbuffer[j];
- }
- memcpy(derivedKey+offset, collector, copyLen);
- }
-
- bzero(oldbuffer, CC_MAX_PRF_WORKSPACE);
- bzero(newbuffer, CC_MAX_PRF_WORKSPACE);
- bzero(collector, CC_MAX_PRF_WORKSPACE);
- bzero(saltCopy, CC_MAX_PRF_WORKSPACE+4);
-
- return 0;
- }
- + (NSData *)keyForPassword:(NSString *)password salt:(NSData *)salt settings:(RNCryptorKeyDerivationSettings)keySettings
- {
- NSMutableData *derivedKey = [NSMutableData dataWithLength:keySettings.keySize];
-
- NSData *passwordData;
- if (keySettings.hasV2Password) {
- passwordData = [NSData dataWithBytes:[password UTF8String] length:[password length]];
- }
- else {
- passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
- }
-
- int result;
- int (*PBKDF)(CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
- const uint8_t *salt, size_t saltLen,
- CCPseudoRandomAlgorithm prf, uint rounds,
- uint8_t *derivedKey, size_t derivedKeyLen);
- PBKDF = CCKeyDerivationPBKDF ?: RN_CCKeyDerivationPBKDF;
- result = PBKDF(keySettings.PBKDFAlgorithm,
- passwordData.bytes,
- passwordData.length,
- salt.bytes,
- salt.length,
- keySettings.PRF,
- keySettings.rounds,
- derivedKey.mutableBytes,
- derivedKey.length);
-
- NSAssert(result == kCCSuccess, @"Unable to create AES key for password: %d", result);
- return derivedKey;
- }
- static int RN_SecRandomCopyBytes(void *rnd, size_t count, uint8_t *bytes) {
- static int kSecRandomFD;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- kSecRandomFD = open("/dev/random", O_RDONLY);
- });
- if (kSecRandomFD < 0)
- return -1;
- while (count) {
- ssize_t bytes_read = read(kSecRandomFD, bytes, count);
- if (bytes_read == -1) {
- if (errno == EINTR)
- continue;
- return -1;
- }
- if (bytes_read == 0) {
- return -1;
- }
- bytes += bytes_read;
- count -= bytes_read;
- }
- return 0;
- }
- + (NSData *)randomDataOfLength:(size_t)length
- {
- NSMutableData *data = [NSMutableData dataWithLength:length];
- int result;
- if (SecRandomCopyBytes != NULL) {
- result = SecRandomCopyBytes(NULL, length, data.mutableBytes);
- }
- else {
- result = RN_SecRandomCopyBytes(NULL, length, data.mutableBytes);
- }
- NSAssert(result == 0, @"Unable to generate random bytes: %d", errno);
- return data;
- }
- - (id)initWithHandler:(RNCryptorHandler)handler
- {
- NSParameterAssert(handler);
- self = [super init];
- if (self) {
- NSString *responseQueueName = [@"net.robnapier.response." stringByAppendingString:NSStringFromClass([self class])];
- _responseQueue = dispatch_queue_create([responseQueueName UTF8String], NULL);
- NSString *queueName = [@"net.robnapier." stringByAppendingString:NSStringFromClass([self class])];
- _queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
- __outData = [NSMutableData data];
- _handler = [handler copy];
- }
- return self;
- }
- - (void)dealloc
- {
- if (_responseQueue) {
- #if !OS_OBJECT_USE_OBJC
- dispatch_release(_responseQueue);
- #endif
- _responseQueue = NULL;
- }
- if (_queue) {
- #if !OS_OBJECT_USE_OBJC
- dispatch_release(_queue);
- #endif
- _queue = NULL;
- }
- }
- - (void)setResponseQueue:(dispatch_queue_t)aResponseQueue
- {
- if (aResponseQueue) {
- #if !OS_OBJECT_USE_OBJC
- dispatch_retain(aResponseQueue);
- #endif
- }
- if (_responseQueue) {
- #if !OS_OBJECT_USE_OBJC
- dispatch_release(_responseQueue);
- #endif
- }
- _responseQueue = aResponseQueue;
- }
- - (void)addData:(NSData *)data
- {
- }
- - (void)finish
- {
- }
- - (void)cleanupAndNotifyWithError:(NSError *)error
- {
- self.error = error;
- self.finished = YES;
- if (self.handler) {
- dispatch_sync(self.responseQueue, ^{
- self.handler(self, self.outData);
- });
- self.handler = nil;
- }
- }
- - (BOOL)hasHMAC
- {
- return self.HMACLength > 0;
- }
- @end
|