aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2015-09-14 03:01:09 +0200
committerMax <post@wickenrode.com>2015-09-14 03:01:09 +0200
commit4707c32d7c349d41fefea6e97bb0f82facf9a353 (patch)
tree41b7462f2fa9252ee476114a21277b862a26b8cf /Source
parent5ebf0d164f81cd558eee8dd2a869ac08f1e2d617 (diff)
downloadsequelpro-4707c32d7c349d41fefea6e97bb0f82facf9a353.tar.gz
sequelpro-4707c32d7c349d41fefea6e97bb0f82facf9a353.tar.bz2
sequelpro-4707c32d7c349d41fefea6e97bb0f82facf9a353.zip
Replace OpenSSL with Apple's CommonCrypto for session file decryption (fixes #2223)
This also removes the dependency on OpenSSL.
Diffstat (limited to 'Source')
-rw-r--r--Source/SPDataAdditions.h1
-rw-r--r--Source/SPDataAdditions.m58
2 files changed, 46 insertions, 13 deletions
diff --git a/Source/SPDataAdditions.h b/Source/SPDataAdditions.h
index 6c404b9e..5158c270 100644
--- a/Source/SPDataAdditions.h
+++ b/Source/SPDataAdditions.h
@@ -35,6 +35,7 @@
- (NSData *)dataEncryptedWithPassword:(NSString *)password;
- (NSData *)dataEncryptedWithKey:(NSData *)aesKey IV:(NSData *)iv;
- (NSData *)dataDecryptedWithPassword:(NSString *)password;
+- (NSData *)dataDecryptedWithKey:(NSData *)key;
- (NSData *)compress;
- (NSData *)decompress;
diff --git a/Source/SPDataAdditions.m b/Source/SPDataAdditions.m
index 4a07c437..8002595c 100644
--- a/Source/SPDataAdditions.m
+++ b/Source/SPDataAdditions.m
@@ -35,7 +35,6 @@
#import "SPDataAdditions.h"
#include <zlib.h>
-#include <openssl/aes.h>
#include <CommonCrypto/CommonCrypto.h>
#include <stdlib.h>
@@ -172,23 +171,50 @@ uint32_t LimitUInt32(NSUInteger i);
- (NSData *)dataDecryptedWithPassword:(NSString *)password
{
// Create the key from the password hash
- NSData *passwordDigest = [[password dataUsingEncoding:NSUTF8StringEncoding] sha1Hash];
+ NSData *passwordDigest = [[[password dataUsingEncoding:NSUTF8StringEncoding] sha1Hash] subdataWithRange:NSMakeRange(0, kCCKeySizeAES128)];
+
+ return [self dataDecryptedWithKey:passwordDigest];
- // AES-128-cbc decrypt the data
- AES_KEY aesKey;
- AES_set_decrypt_key([passwordDigest bytes], 128, &aesKey);
+}
+
+- (NSData *)dataDecryptedWithKey:(NSData *)aesKey
+{
+ if([aesKey length] != kCCKeySizeAES128)
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Key length invalid. Must be kCCKeySizeAES128 bytes!" userInfo:nil];
+
+ if([self length] < (2*kCCBlockSizeAES128) || [self length] > UINT32_MAX)
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Length of encrypted NSData must be in range 32 to 2^32!" userInfo:nil];
// Total length = encrypted length + IV
- NSInteger totalLength = [self length];
- NSInteger encryptedLength = totalLength - 16;
+ NSUInteger totalLength = [self length];
+ NSUInteger encryptedLength = totalLength - kCCBlockSizeAES128; // >=0 ensured above
// Take the IV from the first 128-bit block
- unsigned char iv[16];
- memcpy(iv, [self bytes], 16);
+ unsigned char iv[kCCBlockSizeAES128];
+ memcpy(iv, [self bytes], kCCBlockSizeAES128);
// Decrypt the data
- unsigned char *decryptedBytes = (unsigned char*)malloc(encryptedLength);
- AES_cbc_encrypt([self bytes] + 16, decryptedBytes, encryptedLength, &aesKey, iv, AES_DECRYPT);
+ unsigned char *decryptedBytes = calloc(1,encryptedLength);
+
+ CCCryptorStatus res = CCCrypt(
+ kCCDecrypt, // operation mode
+ kCCAlgorithmAES128, // algorithm
+ 0, // options. We use our own padding algorithm and CBC is the default
+ [aesKey bytes], // key bytes
+ kCCKeySizeAES128, // key length
+ iv, // iv bytes (length == block size)
+ ([self bytes] + kCCBlockSizeAES128), // raw data
+ encryptedLength, // length of raw data
+ decryptedBytes, // output buffer. overwriting input is OK
+ encryptedLength, // output buffer size
+ NULL // number of bytes written. not relevant here
+ );
+
+ if(res != kCCSuccess) {
+ @throw [NSException exceptionWithName:SPCommonCryptoExceptionName
+ reason:[NSString stringWithFormat:@"CCCrypt() failed! (CCCryptorStatus=%d)",res]
+ userInfo:@{@"cryptorStatus":@(res)}];
+ }
// If decryption was successful, these blocks will be zeroed
if ( *((UInt32*)decryptedBytes + ((encryptedLength / 4) - 4)) ||
@@ -200,8 +226,14 @@ uint32_t LimitUInt32(NSUInteger i);
}
// Get the size of the data from the last 32-bit chunk
- NSInteger bigIntDataLength = *((UInt32*)decryptedBytes + ((encryptedLength / 4) - 1));
- NSInteger dataLength = NSSwapBigIntToHost((unsigned int)bigIntDataLength);
+ uint32_t bigIntDataLength = *((UInt32*)decryptedBytes + ((encryptedLength / sizeof(UInt32)) - 1));
+ uint32_t dataLength = NSSwapBigIntToHost(bigIntDataLength);
+
+ if(dataLength >= (encryptedLength-sizeof(UInt32))) { //this way dataLength can still reach into padding, but we own that memory anyway.
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException
+ reason:[NSString stringWithFormat:@"dataLength=%u exceeds encryptedLength=%lu! Either the message is incomplete, decrypting resulted in invalid data, or this is a malicious message!",dataLength,encryptedLength]
+ userInfo:nil];
+ }
return [NSData dataWithBytesNoCopy:decryptedBytes length:dataLength];
}