diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m index b7962e9fc..0654b2d66 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m @@ -250,6 +250,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f; NSData *plaintext = [Cryptography decryptAttachment:cipherText withKey:attachment.encryptionKey digest:attachment.digest + unpaddedSize:attachment.byteCount error:&decryptError]; if (decryptError) { diff --git a/SignalServiceKit/src/Util/Cryptography.h b/SignalServiceKit/src/Util/Cryptography.h index 9a35081e8..f0369969d 100755 --- a/SignalServiceKit/src/Util/Cryptography.h +++ b/SignalServiceKit/src/Util/Cryptography.h @@ -59,6 +59,7 @@ typedef NS_ENUM(NSInteger, TSMACType) { + (NSData *)decryptAttachment:(NSData *)dataToDecrypt withKey:(NSData *)key digest:(nullable NSData *)digest + unpaddedSize:(UInt32)unpaddedSize error:(NSError **)error; + (NSData *)encryptAttachmentData:(NSData *)attachmentData diff --git a/SignalServiceKit/src/Util/Cryptography.m b/SignalServiceKit/src/Util/Cryptography.m index 0ec59232b..cf4b7586f 100755 --- a/SignalServiceKit/src/Util/Cryptography.m +++ b/SignalServiceKit/src/Util/Cryptography.m @@ -297,6 +297,7 @@ const NSUInteger kAES256_KeyByteLength = 32; + (NSData *)decryptAttachment:(NSData *)dataToDecrypt withKey:(NSData *)key digest:(nullable NSData *)digest + unpaddedSize:(UInt32)unpaddedSize error:(NSError **)error; { if (digest.length <= 0) { @@ -328,14 +329,51 @@ const NSUInteger kAES256_KeyByteLength = 32; NSData *hmac = [dataToDecrypt subdataWithRange:NSMakeRange([dataToDecrypt length] - HMAC256_OUTPUT_LENGTH, HMAC256_OUTPUT_LENGTH)]; - return [Cryptography decryptCBCMode:encryptedAttachment - key:encryptionKey - IV:iv - version:nil - HMACKey:hmacKey - HMACType:TSHMACSHA256AttachementType - matchingHMAC:hmac - digest:digest]; + NSData *paddedPlainText = [Cryptography decryptCBCMode:encryptedAttachment + key:encryptionKey + IV:iv + version:nil + HMACKey:hmacKey + HMACType:TSHMACSHA256AttachementType + matchingHMAC:hmac + digest:digest]; + if (unpaddedSize == 0) { + // Work around for legacy iOS client's which weren't setting padding size. + // Since we know those clients pre-date attachment padding we return the entire data. + DDLogWarn(@"%@ Decrypted attachment with unspecified size.", self.tag); + return paddedPlainText; + } else { + if (unpaddedSize > paddedPlainText.length) { + *error = OWSErrorWithCodeDescription( + OWSErrorCodeFailedToDecryptMessage, NSLocalizedString(@"ERROR_MESSAGE_INVALID_MESSAGE", @"")); + return nil; + } + + if (unpaddedSize == paddedPlainText.length) { + DDLogInfo(@"%@ decrypted unpadded attachment.", self.tag); + return [paddedPlainText copy]; + } else { + unsigned long paddingSize = paddedPlainText.length - unpaddedSize; + DDLogInfo(@"%@ decrypted padded attachment with unpaddedSize: %u, paddingSize: %lu", + self.tag, + unpaddedSize, + paddingSize); + return [paddedPlainText subdataWithRange:NSMakeRange(0, unpaddedSize)]; + } + } +} + ++ (unsigned long)paddedSize:(unsigned long)unpaddedSize +{ + // Don't enable this until clients are sufficiently rolled out. + BOOL shouldPad = NO; + if (shouldPad) { + // Note: This just rounds up to the nearsest power of two, + // but the actual padding scheme is TBD + return pow(2, ceil( log2( unpaddedSize ))); + } else { + return unpaddedSize; + } } + (NSData *)encryptAttachmentData:(NSData *)attachmentData @@ -352,8 +390,13 @@ const NSUInteger kAES256_KeyByteLength = 32; [attachmentKey appendData:hmacKey]; *outKey = [attachmentKey copy]; + // Apply any padding + unsigned long desiredSize = [self paddedSize:attachmentData.length]; + NSMutableData *paddedAttachmentData = [attachmentData mutableCopy]; + paddedAttachmentData.length = desiredSize; + // Encrypt - size_t bufferSize = [attachmentData length] + kCCBlockSizeAES128; + size_t bufferSize = [paddedAttachmentData length] + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); if (buffer == NULL) { @@ -368,8 +411,8 @@ const NSUInteger kAES256_KeyByteLength = 32; [encryptionKey bytes], [encryptionKey length], [iv bytes], - [attachmentData bytes], - [attachmentData length], + [paddedAttachmentData bytes], + [paddedAttachmentData length], buffer, bufferSize, &bytesEncrypted); @@ -382,22 +425,22 @@ const NSUInteger kAES256_KeyByteLength = 32; NSData *cipherText = [NSData dataWithBytesNoCopy:buffer length:bytesEncrypted freeWhenDone:YES]; - NSMutableData *encryptedAttachmentData = [NSMutableData data]; - [encryptedAttachmentData appendData:iv]; - [encryptedAttachmentData appendData:cipherText]; + NSMutableData *encryptedPaddedData = [NSMutableData data]; + [encryptedPaddedData appendData:iv]; + [encryptedPaddedData appendData:cipherText]; // compute hmac of: iv || encrypted data NSData *hmac = - [Cryptography truncatedSHA256HMAC:encryptedAttachmentData withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH]; + [Cryptography truncatedSHA256HMAC:encryptedPaddedData withHMACKey:hmacKey truncation:HMAC256_OUTPUT_LENGTH]; DDLogVerbose(@"%@ computed hmac: %@", self.tag, hmac); - [encryptedAttachmentData appendData:hmac]; + [encryptedPaddedData appendData:hmac]; // compute digest of: iv || encrypted data || hmac - *outDigest = [self computeSHA256Digest:encryptedAttachmentData]; + *outDigest = [self computeSHA256Digest:encryptedPaddedData]; DDLogVerbose(@"%@ computed digest: %@", self.tag, *outDigest); - return [encryptedAttachmentData copy]; + return [encryptedPaddedData copy]; } + (nullable NSData *)encryptAESGCMWithData:(NSData *)plaintext key:(OWSAES256Key *)key