소스 검색

Include header in HMAC.

Rob Napier 11 년 전
부모
커밋
b4f8de277e
5개의 변경된 파일35개의 추가작업 그리고 7개의 파일을 삭제
  1. 1 1
      RNCryptor/RNCryptor.m
  2. 20 4
      RNCryptor/RNDecryptor.m
  3. 5 1
      RNCryptor/RNEncryptor.m
  4. 1 1
      RNCryptorTests/RNCryptorTests.m
  5. 8 0
      RNCryptorVectors/main.m

+ 1 - 1
RNCryptor/RNCryptor.m

@@ -29,7 +29,7 @@
 #import <Security/SecRandom.h>
 
 NSString *const kRNCryptorErrorDomain = @"net.robnapier.RNCryptManager";
-const uint8_t kRNCryptorFileVersion = 1;
+const uint8_t kRNCryptorFileVersion = 2;
 
 // TODO: This is a slightly expensive solution, but it's convenient. May want to create a "walkable" data object
 @implementation NSMutableData (RNCryptor)

+ 20 - 4
RNCryptor/RNDecryptor.m

@@ -36,6 +36,8 @@ static const NSUInteger kPreambleSize = 2;
 @property (nonatomic, readwrite, copy) NSData *encryptionKey;
 @property (nonatomic, readwrite, copy) NSData *HMACKey;
 @property (nonatomic, readwrite, copy) NSString *password;
+@property (nonatomic, readwrite, assign) BOOL *hasV1HMAC;
+
 @end
 
 @implementation RNDecryptor
@@ -139,11 +141,20 @@ static const NSUInteger kPreambleSize = 2;
 - (BOOL)getSettings:(RNCryptorSettings *)settings forPreamble:(NSData *)preamble
 {
   const uint8_t *bytes = [preamble bytes];
-  if (bytes[0] == kRNCryptorFileVersion) {
-    *settings = kRNCryptorAES256Settings;
 
+  // See http://robnapier.net/blog/rncryptor-hmac-vulnerability-827 for information on the v1 bad HMAC
+#ifdef RNCRYPTOR_ALLOW_V1_BAD_HMAC
+  if (bytes[0] == 1) {
+    *settings = kRNCryptorAES256Settings;
     self.options = bytes[1];
+    self.hasV1HMAC = YES;
+    return YES;
+  }
+#endif
 
+  if (bytes[0] == kRNCryptorFileVersion) {
+    *settings = kRNCryptorAES256Settings;
+    self.options = bytes[1];
     return YES;
   }
 
@@ -173,7 +184,9 @@ static const NSUInteger kPreambleSize = 2;
     return;
   }
 
-  [data _RNConsumeToIndex:kPreambleSize]; // Throw away the preamble
+  NSData *header = [data subdataWithRange:NSMakeRange(0, headerSize)];  // We'll need this for the HMAC later
+
+  [[data _RNConsumeToIndex:kPreambleSize] mutableCopy]; // Throw away the preamble
 
   NSError *error = nil;
   if (self.options & kRNCryptorOptionHasPassword) {
@@ -181,7 +194,6 @@ static const NSUInteger kPreambleSize = 2;
 
     NSData *encryptionKeySalt = [data _RNConsumeToIndex:settings.keySettings.saltSize];
     NSData *HMACKeySalt = [data _RNConsumeToIndex:settings.HMACKeySettings.saltSize];
-
     self.encryptionKey = [[self class] keyForPassword:self.password salt:encryptionKeySalt settings:settings.keySettings];
     self.HMACKey = [[self class] keyForPassword:self.password salt:HMACKeySalt settings:settings.HMACKeySettings];
 
@@ -201,6 +213,10 @@ static const NSUInteger kPreambleSize = 2;
     CCHmacInit(&_HMACContext, settings.HMACAlgorithm, self.HMACKey.bytes, self.HMACKey.length);
     self.HMACLength = settings.HMACLength;
     self.HMACKey = nil; // Don't need this anymore
+
+    if (! self.hasV1HMAC) {
+      CCHmacUpdate(&_HMACContext, [header bytes], [header length]);
+    }
   }
 }
 

+ 5 - 1
RNCryptor/RNEncryptor.m

@@ -132,7 +132,11 @@
 
   dispatch_async(self.queue, ^{
     if (!self.haveWrittenHeader) {
-      [self.outData setData:[self header]];
+      NSData *header = [self header];
+      [self.outData setData:header];
+      if (self.hasHMAC) {
+        CCHmacUpdate(&_HMACContext, [header bytes], [header length]);
+      }
       self.haveWrittenHeader = YES;
     }
 

+ 1 - 1
RNCryptorTests/RNCryptorTests.m

@@ -275,7 +275,7 @@ static NSString *const kOpenSSLPassword = @"Passw0rd";
 
 - (void)testOpenSSLDecrypt
 {
-  NSData *encryptedData = [NSData dataWithContentsOfFile:kOpenSSLPath];
+  NSData *encryptedData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:kOpenSSLPath ofType:nil]];
 
   NSError *error = nil;
   NSData *decryptedData = [RNOpenSSLDecryptor decryptData:encryptedData

+ 8 - 0
RNCryptorVectors/main.m

@@ -63,6 +63,14 @@ int main(int argc, const char * argv[])
     string = @"This is a longer test vector intended to be longer than one block.";
     
     Encrypt(string, password, encryptionSalt, HMACSalt, IV);
+
+    NSError *error;
+    NSData *encryptedData = [RNEncryptor encryptData:[string dataUsingEncoding:NSUTF8StringEncoding]
+                                        withSettings:kRNCryptorAES256Settings
+                                       password:password
+                                               error:&error];
+
+    [encryptedData writeToFile:@"/tmp/RNCryptor.enc" atomically:NO];
   }
   return 0;
 }