RNDecryptor.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. //
  2. // RNDecryptor
  3. //
  4. // Copyright (c) 2012 Rob Napier
  5. //
  6. // This code is licensed under the MIT License:
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a
  9. // copy of this software and associated documentation files (the "Software"),
  10. // to deal in the Software without restriction, including without limitation
  11. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. // and/or sell copies of the Software, and to permit persons to whom the
  13. // Software is furnished to do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included in
  16. // all copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. // DEALINGS IN THE SOFTWARE.
  25. //
  26. #import "RNCryptor+Private.h"
  27. #import "RNDecryptor.h"
  28. #import "RNCryptorEngine.h"
  29. static const NSUInteger kPreambleSize = 2;
  30. @interface RNDecryptor ()
  31. @property (nonatomic, readonly, strong) NSMutableData *inData;
  32. @property (nonatomic, readwrite, copy) NSData *encryptionKey;
  33. @property (nonatomic, readwrite, copy) NSData *HMACKey;
  34. @property (nonatomic, readwrite, copy) NSString *password;
  35. @property (nonatomic, readwrite, assign) BOOL hasV1HMAC;
  36. @end
  37. @implementation RNDecryptor
  38. {
  39. CCHmacContext _HMACContext;
  40. NSMutableData *__inData;
  41. }
  42. @synthesize encryptionKey = _encryptionKey;
  43. @synthesize HMACKey = _HMACKey;
  44. @synthesize password = _password;
  45. + (NSData *)decryptData:(NSData *)theCipherText withPassword:(NSString *)aPassword error:(NSError **)anError
  46. {
  47. RNDecryptor *cryptor = [[self alloc] initWithPassword:aPassword
  48. handler:^(RNCryptor *c, NSData *d) {}];
  49. return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError];
  50. }
  51. + (NSData *)decryptData:(NSData *)theCipherText withEncryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)anError;
  52. {
  53. RNDecryptor *cryptor = [[self alloc] initWithEncryptionKey:encryptionKey
  54. HMACKey:HMACKey
  55. handler:^(RNCryptor *c, NSData *d) {}];
  56. return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError];
  57. }
  58. - (RNDecryptor *)initWithEncryptionKey:(NSData *)anEncryptionKey HMACKey:(NSData *)anHMACKey handler:(RNCryptorHandler)aHandler
  59. {
  60. self = [super initWithHandler:aHandler];
  61. if (self) {
  62. _encryptionKey = [anEncryptionKey copy];
  63. _HMACKey = [anHMACKey copy];
  64. }
  65. return self;
  66. }
  67. - (RNDecryptor *)initWithPassword:(NSString *)aPassword handler:(RNCryptorHandler)aHandler
  68. {
  69. NSParameterAssert(aPassword != nil);
  70. self = [self initWithEncryptionKey:nil HMACKey:nil handler:aHandler];
  71. if (self) {
  72. _password = aPassword;
  73. }
  74. return self;
  75. }
  76. - (NSMutableData *)inData
  77. {
  78. if (!__inData) {
  79. __inData = [NSMutableData data];
  80. }
  81. return __inData;
  82. }
  83. - (void)decryptData:(NSData *)data
  84. {
  85. dispatch_async(self.queue, ^{
  86. if (self.hasHMAC) {
  87. CCHmacUpdate(&_HMACContext, data.bytes, data.length);
  88. }
  89. NSError *error = nil;
  90. NSData *decryptedData = [self.engine addData:data error:&error];
  91. if (!decryptedData) {
  92. [self cleanupAndNotifyWithError:error];
  93. return;
  94. }
  95. [self.outData appendData:decryptedData];
  96. dispatch_sync(self.responseQueue, ^{
  97. self.handler(self, self.outData);
  98. });
  99. [self.outData setLength:0];
  100. });
  101. }
  102. - (void)addData:(NSData *)theData
  103. {
  104. if (self.isFinished) {
  105. return;
  106. }
  107. [self.inData appendData:theData];
  108. if (!self.engine) {
  109. [self consumeHeaderFromData:self.inData];
  110. }
  111. if (self.engine) {
  112. NSUInteger HMACLength = self.HMACLength;
  113. if (self.inData.length > HMACLength) {
  114. NSData *data = [self.inData _RNConsumeToIndex:self.inData.length - HMACLength];
  115. [self decryptData:data];
  116. }
  117. }
  118. }
  119. - (BOOL)getSettings:(RNCryptorSettings *)settings forPreamble:(NSData *)preamble
  120. {
  121. const uint8_t *bytes = [preamble bytes];
  122. // See http://robnapier.net/blog/rncryptor-hmac-vulnerability-827 for information on the v1 bad HMAC
  123. #ifdef RNCRYPTOR_ALLOW_V1_BAD_HMAC
  124. if (bytes[0] == 1) {
  125. *settings = kRNCryptorAES256Settings;
  126. self.options = bytes[1];
  127. self.hasV1HMAC = YES;
  128. return YES;
  129. }
  130. #endif
  131. if (bytes[0] == kRNCryptorFileVersion) {
  132. *settings = kRNCryptorAES256Settings;
  133. self.options = bytes[1];
  134. return YES;
  135. }
  136. return NO;
  137. }
  138. - (void)consumeHeaderFromData:(NSMutableData *)data
  139. {
  140. if (data.length < kPreambleSize) {
  141. return;
  142. }
  143. RNCryptorSettings settings;
  144. if (![self getSettings:&settings forPreamble:[data subdataWithRange:NSMakeRange(0, kPreambleSize)]]) {
  145. [self cleanupAndNotifyWithError:[NSError errorWithDomain:kRNCryptorErrorDomain
  146. code:kRNCryptorUnknownHeader
  147. userInfo:[NSDictionary dictionaryWithObject:@"Unknown header" /* DNL */
  148. forKey:NSLocalizedDescriptionKey]]];
  149. }
  150. NSUInteger headerSize = kPreambleSize + settings.IVSize;
  151. if (self.options & kRNCryptorOptionHasPassword) {
  152. headerSize += settings.keySettings.saltSize + settings.HMACKeySettings.saltSize;
  153. }
  154. if (data.length < headerSize) {
  155. return;
  156. }
  157. NSData *header = [data subdataWithRange:NSMakeRange(0, headerSize)]; // We'll need this for the HMAC later
  158. [[data _RNConsumeToIndex:kPreambleSize] mutableCopy]; // Throw away the preamble
  159. NSError *error = nil;
  160. if (self.options & kRNCryptorOptionHasPassword) {
  161. NSAssert(!self.encryptionKey && !self.HMACKey, @"Both password and the key (%d) or HMACKey (%d) are set.", self.encryptionKey != nil, self.HMACKey != nil);
  162. NSData *encryptionKeySalt = [data _RNConsumeToIndex:settings.keySettings.saltSize];
  163. NSData *HMACKeySalt = [data _RNConsumeToIndex:settings.HMACKeySettings.saltSize];
  164. self.encryptionKey = [[self class] keyForPassword:self.password salt:encryptionKeySalt settings:settings.keySettings];
  165. self.HMACKey = [[self class] keyForPassword:self.password salt:HMACKeySalt settings:settings.HMACKeySettings];
  166. self.password = nil; // Don't need this anymore.
  167. }
  168. NSData *IV = [data _RNConsumeToIndex:settings.IVSize];
  169. self.engine = [[RNCryptorEngine alloc] initWithOperation:kCCDecrypt settings:settings key:self.encryptionKey IV:IV error:&error];
  170. self.encryptionKey = nil; // Don't need this anymore
  171. if (!self.engine) {
  172. [self cleanupAndNotifyWithError:error];
  173. return;
  174. }
  175. if (self.HMACKey) {
  176. CCHmacInit(&_HMACContext, settings.HMACAlgorithm, self.HMACKey.bytes, self.HMACKey.length);
  177. self.HMACLength = settings.HMACLength;
  178. self.HMACKey = nil; // Don't need this anymore
  179. if (! self.hasV1HMAC) {
  180. CCHmacUpdate(&_HMACContext, [header bytes], [header length]);
  181. }
  182. }
  183. }
  184. - (void)finish
  185. {
  186. if (self.isFinished) {
  187. return;
  188. }
  189. dispatch_async(self.queue, ^{
  190. NSError *error = nil;
  191. NSData *decryptedData = [self.engine finishWithError:&error];
  192. if (!decryptedData) {
  193. [self cleanupAndNotifyWithError:error];
  194. return;
  195. }
  196. [self.outData appendData:decryptedData];
  197. if (self.hasHMAC) {
  198. NSMutableData *HMACData = [NSMutableData dataWithLength:self.HMACLength];
  199. CCHmacFinal(&_HMACContext, [HMACData mutableBytes]);
  200. if (![HMACData isEqualToData:self.inData]) {
  201. [self cleanupAndNotifyWithError:[NSError errorWithDomain:kRNCryptorErrorDomain
  202. code:kRNCryptorHMACMismatch
  203. userInfo:[NSDictionary dictionaryWithObject:@"HMAC Mismatch" /* DNL */
  204. forKey:NSLocalizedDescriptionKey]]];
  205. return;
  206. }
  207. }
  208. [self cleanupAndNotifyWithError:nil];
  209. });
  210. }
  211. @end