aes-gcm via openssl

// FREEBIE
This commit is contained in:
Michael Kirk 2017-08-21 11:21:23 -04:00
parent d6d403ce69
commit 72fbb02028
17 changed files with 244 additions and 169 deletions

View File

@ -8,6 +8,7 @@ target 'Signal' do
pod 'JSQMessagesViewController', git: 'https://github.com/WhisperSystems/JSQMessagesViewController.git', branch: 'signal-master'
#pod 'JSQMessagesViewController', path: '../JSQMessagesViewController'
pod 'PureLayout'
pod 'OpenSSL', git: 'https://github.com/charlesmchen/OpenSSL-Pod', branch: '1.0.2l'
pod 'Reachability'
pod 'SignalServiceKit', path: '.'
pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git'

View File

@ -37,17 +37,19 @@ PODS:
- Mantle (2.1.0):
- Mantle/extobjc (= 2.1.0)
- Mantle/extobjc (2.1.0)
- OpenSSL (1.0.212)
- ProtocolBuffers (1.9.11)
- PureLayout (3.0.2)
- Reachability (3.2)
- SAMKeychain (1.5.2)
- SignalServiceKit (0.9.0):
- '25519'
- 25519
- AFNetworking
- AxolotlKit
- CocoaLumberjack
- libPhoneNumber-iOS
- Mantle
- OpenSSL
- Reachability
- SAMKeychain
- SocketRocket
@ -113,6 +115,7 @@ DEPENDENCIES:
- ATAppUpdater
- AxolotlKit (from `https://github.com/WhisperSystems/SignalProtocolKit.git`)
- JSQMessagesViewController (from `https://github.com/WhisperSystems/JSQMessagesViewController.git`, branch `signal-master`)
- OpenSSL (from `https://github.com/charlesmchen/OpenSSL-Pod`, branch `1.0.2l`)
- PureLayout
- Reachability
- SignalServiceKit (from `.`)
@ -124,6 +127,9 @@ EXTERNAL SOURCES:
JSQMessagesViewController:
:branch: signal-master
:git: https://github.com/WhisperSystems/JSQMessagesViewController.git
OpenSSL:
:branch: 1.0.2l
:git: https://github.com/charlesmchen/OpenSSL-Pod
SignalServiceKit:
:path: .
SocketRocket:
@ -136,12 +142,15 @@ CHECKOUT OPTIONS:
JSQMessagesViewController:
:commit: 8c10f920bb566fe1051f92abd360a2e3d5530e00
:git: https://github.com/WhisperSystems/JSQMessagesViewController.git
OpenSSL:
:commit: 07d058fd05b794bae017e1d196b0338003b8c29e
:git: https://github.com/charlesmchen/OpenSSL-Pod
SocketRocket:
:commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf
:git: https://github.com/facebook/SocketRocket.git
SPEC CHECKSUMS:
'25519': dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
25519: dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
ATAppUpdater: a9f7027060959d47e58733d3b48f6b9a28cb8de1
AxolotlKit: ba0ab24b879d34559a68e1270b079cc9bd7b3417
@ -151,17 +160,18 @@ SPEC CHECKSUMS:
JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
libPhoneNumber-iOS: f721ae4d5854bce60934f9fb9b0b28e8e68913cb
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
OpenSSL: 60dae0b3f35e3ba31642260f4695c37d6a4c0fef
ProtocolBuffers: d509225eb2ea43d9582a59e94348fcf86e2abd65
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
SignalServiceKit: db63e60f9a9f851e9ae48214bee230be92bb7e57
SignalServiceKit: bfac5572f3a1ff8a853ead9b5413274a075f3cb4
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
SQLCipher: 43d12c0eb9c57fb438749618fc3ce0065509a559
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266
PODFILE CHECKSUM: 13b48854ce4b92e887ffb55d72029fe49b45a789
PODFILE CHECKSUM: 6ed599004f6559be1963002dd4dd6a1360e642d4
COCOAPODS: 1.2.1
COCOAPODS: 1.3.1

View File

@ -2015,13 +2015,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Signal-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3465F381B1856CC06933B3A8 /* [CP] Copy Pods Resources */ = {
@ -2030,9 +2033,21 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Signal/Pods-Signal-resources.sh",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.xib",
"${PODS_ROOT}/SAMKeychain/Support/SAMKeychain.bundle",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/textsecure.cer",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GIAG2.crt",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -2108,13 +2123,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-SignalTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */ = {
@ -2524,11 +2542,7 @@
"DEBUG=1",
"$(inherited)",
);
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = (
"DEBUG=1",
"$(inherited)",
"SSK_BUILDING_FOR_TESTS=1",
);
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "DEBUG=1 $(inherited) SSK_BUILDING_FOR_TESTS=1";
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

View File

@ -12,7 +12,7 @@ extern NSString *const kNSNotificationName_OtherUsersProfileDidChange;
extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
@class TSThread;
@class OWSAES128Key;
@class OWSAES256Key;
// This class can be safely accessed and used from any thread.
@interface OWSProfileManager : NSObject <ProfileManagerProtocol>
@ -26,7 +26,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
#pragma mark - Local Profile
// These two methods should only be called from the main thread.
- (OWSAES128Key *)localProfileKey;
- (OWSAES256Key *)localProfileKey;
- (BOOL)hasLocalProfile;
- (nullable NSString *)localProfileName;
- (nullable UIImage *)localProfileAvatarImage;
@ -59,7 +59,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
#pragma mark - Other User's Profiles
- (nullable OWSAES128Key *)profileKeyForRecipientId:(NSString *)recipientId;
- (nullable OWSAES256Key *)profileKeyForRecipientId:(NSString *)recipientId;
- (nullable NSString *)profileNameForRecipientId:(NSString *)recipientId;

View File

@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface UserProfile : TSYapDatabaseObject
@property (atomic, readonly) NSString *recipientId;
@property (atomic, nullable) OWSAES128Key *profileKey;
@property (atomic, nullable) OWSAES256Key *profileKey;
@property (nonatomic, nullable) NSString *profileName;
@property (nonatomic, nullable) NSString *avatarUrlPath;
// This filename is relative to OWSProfileManager.profileAvatarsDirPath.
@ -176,7 +176,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
OWSAssert(self.localUserProfile);
if (!self.localUserProfile.profileKey) {
DDLogInfo(@"%@ Generating local profile key", self.tag);
self.localUserProfile.profileKey = [OWSAES128Key generateRandomKey];
self.localUserProfile.profileKey = [OWSAES256Key generateRandomKey];
// Make sure to save on the local db connection for consistency.
//
// NOTE: we do an async read/write here to avoid blocking during app launch path.
@ -184,7 +184,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
[self.localUserProfile saveWithTransaction:transaction];
}];
}
OWSAssert(self.localUserProfile.profileKey.keyData.length == kAES128_KeyByteLength);
OWSAssert(self.localUserProfile.profileKey.keyData.length == kAES256_KeyByteLength);
return self;
}
@ -259,11 +259,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
#pragma mark - Local Profile
- (OWSAES128Key *)localProfileKey
- (OWSAES256Key *)localProfileKey
{
@synchronized(self)
{
OWSAssert(self.localUserProfile.profileKey.keyData.length == kAES128_KeyByteLength);
OWSAssert(self.localUserProfile.profileKey.keyData.length == kAES256_KeyByteLength);
return self.localUserProfile.profileKey;
}
@ -787,7 +787,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(self)
{
OWSAES128Key *_Nullable profileKey = [OWSAES128Key keyWithData:profileKeyData];
OWSAES256Key *_Nullable profileKey = [OWSAES256Key keyWithData:profileKeyData];
if (profileKey == nil) {
OWSFail(@"Failed to make profile key for key data");
return;
@ -814,7 +814,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
});
}
- (nullable OWSAES128Key *)profileKeyForRecipientId:(NSString *)recipientId
- (nullable OWSAES256Key *)profileKeyForRecipientId:(NSString *)recipientId
{
OWSAssert(recipientId.length > 0);
@ -893,7 +893,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
return;
}
OWSAES128Key *profileKeyAtStart = userProfile.profileKey;
OWSAES256Key *profileKeyAtStart = userProfile.profileKey;
NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingPathExtension:@"jpg"];
NSString *filePath = [self.profileAvatarsDirPath stringByAppendingPathComponent:fileName];
@ -1074,9 +1074,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
#pragma mark - Profile Encryption
- (nullable NSData *)encryptProfileData:(nullable NSData *)encryptedData profileKey:(OWSAES128Key *)profileKey
- (nullable NSData *)encryptProfileData:(nullable NSData *)encryptedData profileKey:(OWSAES256Key *)profileKey
{
OWSAssert(profileKey.keyData.length == kAES128_KeyByteLength);
OWSAssert(profileKey.keyData.length == kAES256_KeyByteLength);
if (!encryptedData) {
return nil;
@ -1085,9 +1085,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
return [Cryptography encryptAESGCMWithData:encryptedData key:profileKey];
}
- (nullable NSData *)decryptProfileData:(nullable NSData *)encryptedData profileKey:(OWSAES128Key *)profileKey
- (nullable NSData *)decryptProfileData:(nullable NSData *)encryptedData profileKey:(OWSAES256Key *)profileKey
{
OWSAssert(profileKey.keyData.length == kAES128_KeyByteLength);
OWSAssert(profileKey.keyData.length == kAES256_KeyByteLength);
if (!encryptedData) {
return nil;
@ -1096,9 +1096,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
return [Cryptography decryptAESGCMWithData:encryptedData key:profileKey];
}
- (nullable NSString *)decryptProfileNameData:(nullable NSData *)encryptedData profileKey:(OWSAES128Key *)profileKey
- (nullable NSString *)decryptProfileNameData:(nullable NSData *)encryptedData profileKey:(OWSAES256Key *)profileKey
{
OWSAssert(profileKey.keyData.length == kAES128_KeyByteLength);
OWSAssert(profileKey.keyData.length == kAES256_KeyByteLength);
NSData *_Nullable decryptedData = [self decryptProfileData:encryptedData profileKey:profileKey];
if (decryptedData.length < 1) {

View File

@ -26,6 +26,7 @@
#import "PrivacySettingsTableViewController.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "Release.h"
#import "SignalsViewController.h"
#import "TSMessageAdapter.h"
#import "UIColor+OWS.h"

View File

@ -40,6 +40,7 @@ An Objective-C library for communicating with the Signal messaging service.
s.dependency 'YapDatabase/SQLCipher', '~> 2.9.3'
s.dependency 'SocketRocket'
s.dependency 'libPhoneNumber-iOS'
s.dependency 'OpenSSL'
s.dependency 'SAMKeychain'
s.dependency 'TwistedOakCollapsingFutures'
s.dependency 'Reachability'

View File

@ -5,6 +5,7 @@ target 'TSKitiOSTestApp' do
pod 'SocketRocket', git: 'https://github.com/facebook/SocketRocket.git'
pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git'
pod 'SignalServiceKit', :path => '../../../SignalServiceKit.podspec'
pod 'OpenSSL', git: 'https://github.com/charlesmchen/OpenSSL-Pod', branch: '1.0.2l'
target 'TSKitiOSTestAppTests' do
inherit! :search_paths

View File

@ -33,6 +33,7 @@ PODS:
- Mantle (2.1.0):
- Mantle/extobjc (= 2.1.0)
- Mantle/extobjc (2.1.0)
- OpenSSL (1.0.212)
- ProtocolBuffers (1.9.11)
- Reachability (3.2)
- SAMKeychain (1.5.2)
@ -43,6 +44,7 @@ PODS:
- CocoaLumberjack
- libPhoneNumber-iOS
- Mantle
- OpenSSL
- Reachability
- SAMKeychain
- SocketRocket
@ -106,12 +108,16 @@ PODS:
DEPENDENCIES:
- AxolotlKit (from `https://github.com/WhisperSystems/SignalProtocolKit.git`)
- OpenSSL (from `https://github.com/charlesmchen/OpenSSL-Pod`, branch `1.0.2l`)
- SignalServiceKit (from `../../../SignalServiceKit.podspec`)
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
EXTERNAL SOURCES:
AxolotlKit:
:git: https://github.com/WhisperSystems/SignalProtocolKit.git
OpenSSL:
:branch: 1.0.2l
:git: https://github.com/charlesmchen/OpenSSL-Pod
SignalServiceKit:
:path: ../../../SignalServiceKit.podspec
SocketRocket:
@ -121,6 +127,9 @@ CHECKOUT OPTIONS:
AxolotlKit:
:commit: 28afe5c1dbcfdea73d147e464c53d191d1e3ea50
:git: https://github.com/WhisperSystems/SignalProtocolKit.git
OpenSSL:
:commit: 07d058fd05b794bae017e1d196b0338003b8c29e
:git: https://github.com/charlesmchen/OpenSSL-Pod
SocketRocket:
:commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf
:git: https://github.com/facebook/SocketRocket.git
@ -133,16 +142,17 @@ SPEC CHECKSUMS:
HKDFKit: c058305d6f64b84f28c50bd7aa89574625bcb62a
libPhoneNumber-iOS: f721ae4d5854bce60934f9fb9b0b28e8e68913cb
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
OpenSSL: 60dae0b3f35e3ba31642260f4695c37d6a4c0fef
ProtocolBuffers: d509225eb2ea43d9582a59e94348fcf86e2abd65
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SAMKeychain: 1865333198217411f35327e8da61b43de79b635b
SignalServiceKit: db63e60f9a9f851e9ae48214bee230be92bb7e57
SignalServiceKit: bfac5572f3a1ff8a853ead9b5413274a075f3cb4
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
SQLCipher: 43d12c0eb9c57fb438749618fc3ce0065509a559
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266
PODFILE CHECKSUM: 5bfff8cb73ff80b5e5c383fda4dca6aeff2fa8d3
PODFILE CHECKSUM: 1d91553ff6ddb91426b1bcb43d0433c2c3cbe272
COCOAPODS: 1.2.1

View File

@ -459,9 +459,12 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-TSKitiOSTestApp-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -519,9 +522,14 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-TSKitiOSTestApp/Pods-TSKitiOSTestApp-resources.sh",
"${PODS_ROOT}/SAMKeychain/Support/SAMKeychain.bundle",
"${PODS_ROOT}/../../../src/Security/PinningCertificate/textsecure.cer",
"${PODS_ROOT}/../../../src/Security/PinningCertificate/GIAG2.crt",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -534,9 +542,12 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-TSKitiOSTestAppTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;

View File

@ -28,7 +28,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FF3F51F81980908EDE1836B76AA3A1EC"
BlueprintIdentifier = "AABBF31CEB020B42CD1A6FE25E97E11E"
BuildableName = "libSignalServiceKit.a"
BlueprintName = "SignalServiceKit"
ReferencedContainer = "container:Pods/Pods.xcodeproj">

View File

@ -3,11 +3,11 @@
//
@class TSThread;
@class OWSAES128Key;
@class OWSAES256Key;
@protocol ProfileManagerProtocol <NSObject>
- (OWSAES128Key *)localProfileKey;
- (OWSAES256Key *)localProfileKey;
- (void)setProfileKeyData:(NSData *)profileKeyData forRecipientId:(NSString *)recipientId;

View File

@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
return NO;
}
- (OWSAES128Key *)localProfileKey
- (OWSAES256Key *)localProfileKey
{
id<ProfileManagerProtocol> profileManager = [TextSecureKitEnv sharedEnv].profileManager;
return profileManager.localProfileKey;

View File

@ -4,10 +4,10 @@
NS_ASSUME_NONNULL_BEGIN
extern const NSUInteger kAES128_KeyByteLength;
extern const NSUInteger kAES256_KeyByteLength;
/// Key appropriate for use in AES128 crypto
@interface OWSAES128Key: NSObject <NSSecureCoding>
@interface OWSAES256Key : NSObject <NSSecureCoding>
/// Generates new secure random key
- (instancetype)init;
@ -60,8 +60,8 @@ typedef NS_ENUM(NSInteger, TSMACType) {
outKey:(NSData *_Nonnull *_Nullable)outKey
outDigest:(NSData *_Nonnull *_Nullable)outDigest;
+ (nullable NSData *)encryptAESGCMWithData:(NSData *)plainTextData key:(OWSAES128Key *)key;
+ (nullable NSData *)decryptAESGCMWithData:(NSData *)encryptedData key:(OWSAES128Key *)key;
+ (nullable NSData *)encryptAESGCMWithData:(NSData *)plaintextData key:(OWSAES256Key *)key;
+ (nullable NSData *)decryptAESGCMWithData:(NSData *)encryptedData key:(OWSAES256Key *)key;
@end

View File

@ -2,17 +2,12 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonHMAC.h>
// CommonCryptorSPI.h is a local copy of a private APple header fetched: Fri Aug 11 18:33:25 EDT 2017
// from https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonCryptorSPI.h
// We use it to provide the not-yet-public AES128-GCM cryptor
#import "CommonCryptorSPI.h"
#import "Cryptography.h"
#import "NSData+Base64.h"
#import "NSData+OWSConstantTimeCompare.h"
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonHMAC.h>
#import <openssl/evp.h>
#define HMAC256_KEY_LENGTH 32
#define HMAC256_OUTPUT_LENGTH 32
@ -21,19 +16,23 @@
NS_ASSUME_NONNULL_BEGIN
// Returned by many OpenSSL functions - indicating success
const int kOpenSSLSuccess = 1;
// length of initialization nonce
static const NSUInteger kAESGCM128_IVLength = 12;
static const NSUInteger kAESGCM256_IVLength = 12;
// length of authentication tag for AES128-GCM
static const NSUInteger kAESGCM128_TagLength = 16;
// length of authentication tag for AES256-GCM
static const NSUInteger kAESGCM256_TagLength = 16;
const NSUInteger kAES128_KeyByteLength = 16;
const NSUInteger kAES256_KeyByteLength = 32;
@implementation OWSAES128Key
@implementation OWSAES256Key
+ (nullable instancetype)keyWithData:(NSData *)data
{
if (data.length != kAES128_KeyByteLength) {
if (data.length != kAES256_KeyByteLength) {
OWSFail(@"Invalid key length for AES128: %lu", (unsigned long)data.length);
return nil;
}
@ -48,7 +47,7 @@ const NSUInteger kAES128_KeyByteLength = 16;
- (instancetype)init
{
return [self initWithData:[Cryptography generateRandomBytes:kAES128_KeyByteLength]];
return [self initWithData:[Cryptography generateRandomBytes:kAES256_KeyByteLength]];
}
- (instancetype)initWithData:(NSData *)data
@ -78,8 +77,8 @@ const NSUInteger kAES128_KeyByteLength = 16;
}
NSData *keyData = [aDecoder decodeObjectOfClass:[NSData class] forKey:@"keyData"];
if (keyData.length != kAES128_KeyByteLength) {
OWSFail(@"Invalid key length for AES128: %lu", (unsigned long)keyData.length);
if (keyData.length != kAES256_KeyByteLength) {
OWSFail(@"Invalid key length: %lu", (unsigned long)keyData.length);
return nil;
}
@ -386,137 +385,164 @@ const NSUInteger kAES128_KeyByteLength = 16;
return [encryptedAttachmentData copy];
}
+ (nullable NSData *)encryptAESGCMWithData:(NSData *)plainTextData key:(OWSAES128Key *)key
+ (nullable NSData *)encryptAESGCMWithData:(NSData *)plaintext key:(OWSAES256Key *)key
{
NSData *initializationVector = [Cryptography generateRandomBytes:kAESGCM128_IVLength];
uint8_t *cipherTextBytes = malloc(plainTextData.length);
if (cipherTextBytes == NULL) {
OWSFail(@"%@ Failed to allocate encryptedBytes", self.tag);
return nil;
}
uint8_t *authTagBytes = malloc(kAESGCM128_TagLength);
if (authTagBytes == NULL) {
free(cipherTextBytes);
OWSFail(@"%@ Failed to allocate authTagBytes", self.tag);
return nil;
}
// NOTE: Since `tagLength` is an input parameter, it seems weird that the signature for tagLength is a `size_t*` rather than just a `size_t`.
//
// I found a vague reference in the Safari repository implying that this may be a bug:
// source: https://www.mail-archive.com/webkit-changes@lists.webkit.org/msg114561.html
//
// Comment was:
// tagLength is actual an input <rdar://problem/30660074>
size_t tagLength = kAESGCM128_TagLength;
NSData *initializationVector = [Cryptography generateRandomBytes:kAESGCM256_IVLength];
NSMutableData *ciphertext = [NSMutableData dataWithLength:plaintext.length];
NSMutableData *authTag = [NSMutableData dataWithLength:kAESGCM256_TagLength];
CCCryptorStatus status
= CCCryptorGCM(kCCEncrypt, // CCOperation op, /* kCCEncrypt, kCCDecrypt */
kCCAlgorithmAES128, // CCAlgorithm alg,
key.keyData.bytes, // const void *key, /* raw key material */
key.keyData.length, // size_t keyLength,
initializationVector.bytes, // const void *iv,
initializationVector.length, // size_t ivLen,
NULL, // const void *aData,
0, // size_t aDataLen,
plainTextData.bytes, // const void *dataIn,
plainTextData.length, // size_t dataInLength,
cipherTextBytes, // void *dataOut,
authTagBytes, // const void *tag,
&tagLength // size_t *tagLength)
);
if (status != kCCSuccess) {
OWSFail(@"CCCryptorGCM encrypt failed with status: %d", status);
free(cipherTextBytes);
free(authTagBytes);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
OWSFail(@"%@ failed to build context while encrypting", self.tag);
return nil;
}
// build up return value: initializationVector || cipherText || authTag
// Initialise the encryption operation.
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to init encryption", self.tag);
return nil;
}
// Set IV length if default 12 bytes (96 bits) is not appropriate
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)initializationVector.length, NULL) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to set IV length", self.tag);
return nil;
}
// Initialise key and IV
if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.keyData.bytes, initializationVector.bytes) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to set key and iv while encrypting", self.tag);
return nil;
}
int bytesEncrypted = 0;
// Provide the message to be encrypted, and obtain the encrypted output.
// EVP_EncryptUpdate can be called multiple times if necessary
if (EVP_EncryptUpdate(ctx, ciphertext.mutableBytes, &bytesEncrypted, plaintext.bytes, (int)plaintext.length)
!= kOpenSSLSuccess) {
OWSFail(@"%@ encryptUpdate failed", self.tag);
return nil;
}
if (bytesEncrypted != plaintext.length) {
OWSFail(@"%@ bytesEncrypted != plainTextData.length", self.tag);
return nil;
}
int finalizedBytes = 0;
// Finalize the encryption. Normally ciphertext bytes may be written at
// this stage, but this does not occur in GCM mode
if (EVP_EncryptFinal_ex(ctx, ciphertext.mutableBytes + bytesEncrypted, &finalizedBytes) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to finalize encryption", self.tag);
return nil;
}
if (finalizedBytes != 0) {
OWSFail(@"%@ Unexpected finalized bytes written", self.tag);
return nil;
}
/* Get the tag */
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, kAESGCM256_TagLength, authTag.mutableBytes) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to write tag", self.tag);
return nil;
}
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
// build up return value: initializationVector || ciphertext || authTag
NSMutableData *encryptedData = [initializationVector mutableCopy];
[encryptedData appendBytes:cipherTextBytes length:plainTextData.length];
[encryptedData appendBytes:authTagBytes length:tagLength];
[encryptedData appendData:ciphertext];
[encryptedData appendData:authTag];
free(cipherTextBytes);
free(authTagBytes);
return [encryptedData copy];
}
+ (nullable NSData *)decryptAESGCMWithData:(NSData *)encryptedData key:(OWSAES128Key *)key
+ (nullable NSData *)decryptAESGCMWithData:(NSData *)encryptedData key:(OWSAES256Key *)key
{
OWSAssert(encryptedData.length > kAESGCM128_IVLength + kAESGCM128_TagLength);
NSUInteger cipherTextLength = encryptedData.length - kAESGCM128_IVLength - kAESGCM128_TagLength;
// encryptedData layout: initializationVector || cipherText || authTag
NSData *initializationVector = [encryptedData subdataWithRange:NSMakeRange(0, kAESGCM128_IVLength)];
NSData *cipherText = [encryptedData subdataWithRange:NSMakeRange(kAESGCM128_IVLength, cipherTextLength)];
OWSAssert(encryptedData.length > kAESGCM256_IVLength + kAESGCM256_TagLength);
NSUInteger cipherTextLength = encryptedData.length - kAESGCM256_IVLength - kAESGCM256_TagLength;
// encryptedData layout: initializationVector || ciphertext || authTag
NSData *initializationVector = [encryptedData subdataWithRange:NSMakeRange(0, kAESGCM256_IVLength)];
NSData *ciphertext = [encryptedData subdataWithRange:NSMakeRange(kAESGCM256_IVLength, cipherTextLength)];
NSData *authTag =
[encryptedData subdataWithRange:NSMakeRange(kAESGCM128_IVLength + cipherTextLength, kAESGCM128_TagLength)];
[encryptedData subdataWithRange:NSMakeRange(kAESGCM256_IVLength + cipherTextLength, kAESGCM256_TagLength)];
return
[self decryptAESGCMWithInitializationVector:initializationVector cipherText:cipherText authTag:authTag key:key];
[self decryptAESGCMWithInitializationVector:initializationVector ciphertext:ciphertext authTag:authTag key:key];
}
+ (nullable NSData *)decryptAESGCMWithInitializationVector:(NSData *)initializationVector
cipherText:(NSData *)cipherText
ciphertext:(NSData *)ciphertext
authTag:(NSData *)authTagFromEncrypt
key:(OWSAES128Key *)key
key:(OWSAES256Key *)key
{
void *plainTextBytes = malloc(cipherText.length);
if (plainTextBytes == NULL) {
OWSFail(@"Failed to malloc plainTextBytes");
NSMutableData *plaintext = [NSMutableData dataWithLength:ciphertext.length];
// Create and initialise the context
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
OWSFail(@"%@ failed to build context while decrypting", self.tag);
return nil;
}
void *decryptAuthTagBytes = malloc(kAESGCM128_TagLength);
if (decryptAuthTagBytes == NULL) {
OWSFail(@"Failed to malloc decryptAuthTagBytes");
free(plainTextBytes);
// Initialise the decryption operation.
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to init decryption", self.tag);
return nil;
}
// NOTE: Since `tagLength` is an input parameter, it seems weird that the signature for tagLength is a `size_t*` rather than just a `size_t`.
//
// I found a vague reference in the Safari repository implying that this may be a bug:
// source: https://www.mail-archive.com/webkit-changes@lists.webkit.org/msg114561.html
//
// Comment was:
// tagLength is actual an input <rdar://problem/30660074>
size_t tagLength = kAESGCM128_TagLength;
CCCryptorStatus status
= CCCryptorGCM(kCCDecrypt, // CCOperation op, /* kCCEncrypt, kCCDecrypt */
kCCAlgorithmAES128, // CCAlgorithm alg,
key.keyData.bytes, // const void *key, /* raw key material */
key.keyData.length, // size_t keyLength,
initializationVector.bytes, // const void *iv,
initializationVector.length, // size_t ivLen,
NULL, // const void *aData,
0, // size_t aDataLen,
cipherText.bytes, // const void *dataIn,
cipherText.length, // size_t dataInLength,
plainTextBytes, // void *dataOut,
decryptAuthTagBytes, // const void *tag,
&tagLength // size_t *tagLength
);
NSData *decryptAuthTag = [NSData dataWithBytesNoCopy:decryptAuthTagBytes length:tagLength freeWhenDone:YES];
if (![decryptAuthTag ows_constantTimeIsEqualToData:authTagFromEncrypt]) {
OWSFail(@"Auth tags don't match given tag: %@ computed tag: %@", authTagFromEncrypt, decryptAuthTag);
free(plainTextBytes);
// Set IV length. Not necessary if this is 12 bytes (96 bits)
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, kAESGCM256_IVLength, NULL) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to set key and iv while decrypting", self.tag);
return nil;
}
if (status != kCCSuccess) {
OWSFail(@"CCCryptorGCM decrypt failed with status: %d", status);
free(plainTextBytes);
// Initialise key and IV
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.keyData.bytes, initializationVector.bytes) != kOpenSSLSuccess) {
OWSFail(@"%@ failed to init decryption", self.tag);
return nil;
}
return [NSData dataWithBytesNoCopy:plainTextBytes length:cipherText.length freeWhenDone:YES];
// Provide the message to be decrypted, and obtain the plaintext output.
// EVP_DecryptUpdate can be called multiple times if necessary
int decryptedBytes = 0;
if (EVP_DecryptUpdate(ctx, plaintext.mutableBytes, &decryptedBytes, ciphertext.bytes, (int)ciphertext.length)
!= kOpenSSLSuccess) {
OWSFail(@"%@ decryptUpdate failed", self.tag);
return nil;
}
if (decryptedBytes != ciphertext.length) {
OWSFail(@"%@ Failed to decrypt entire ciphertext", self.tag);
return nil;
}
// Set expected tag value. Works in OpenSSL 1.0.1d and later
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, (int)authTagFromEncrypt.length, authTagFromEncrypt.bytes)
!= kOpenSSLSuccess) {
OWSFail(@"%@ Failed to set auth tag in decrypt.", self.tag);
return nil;
}
// Finalise the decryption. A positive return value indicates success,
// anything else is a failure - the plaintext is not trustworthy.
int finalBytes = 0;
int decryptStatus = EVP_DecryptFinal_ex(ctx, plaintext.bytes + decryptedBytes, &finalBytes);
// AESGCM doesn't write any final bytes
OWSAssert(finalBytes == 0);
// Clean up
EVP_CIPHER_CTX_free(ctx);
if (decryptStatus > 0) {
return [plaintext copy];
} else {
OWSFail(@"%@ Decrypt verificaiton failed", self.tag);
return nil;
}
}
#pragma mark - Logging

View File

@ -10,10 +10,10 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSFakeProfileManager ()
@property (nonatomic, readonly) NSMutableDictionary<NSString *, OWSAES128Key *> *profileKeys;
@property (nonatomic, readonly) NSMutableDictionary<NSString *, OWSAES256Key *> *profileKeys;
@property (nonatomic, readonly) NSMutableSet<NSString *> *recipientWhitelist;
@property (nonatomic, readonly) NSMutableSet<NSString *> *threadWhitelist;
@property (nonatomic, readonly) OWSAES128Key *localProfileKey;
@property (nonatomic, readonly) OWSAES256Key *localProfileKey;
@end
@ -36,17 +36,17 @@ NS_ASSUME_NONNULL_BEGIN
}
- (OWSAES128Key *)localProfileKey
- (OWSAES256Key *)localProfileKey
{
if (_localProfileKey == nil) {
_localProfileKey = [OWSAES128Key generateRandomKey];
_localProfileKey = [OWSAES256Key generateRandomKey];
}
return _localProfileKey;
}
- (void)setProfileKeyData:(NSData *)profileKey forRecipientId:(NSString *)recipientId
{
OWSAES128Key *key = [OWSAES128Key keyWithData:profileKey];
OWSAES256Key *key = [OWSAES256Key keyWithData:profileKey];
NSAssert(key, @"Unable to build key. Invalid key data?");
self.profileKeys[recipientId] = key;
}

View File

@ -11,9 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface Cryptography (TestingPrivateMethods)
+ (nullable NSData *)decryptAESGCMWithInitializationVector:(NSData *)initializationVector
cipherText:(NSData *)cipherText
ciphertext:(NSData *)ciphertext
authTag:(NSData *)authTagFromEncrypt
key:(OWSAES128Key *)key;
key:(OWSAES256Key *)key;
@end
@ -134,8 +134,8 @@ NS_ASSUME_NONNULL_BEGIN
NSData *plainTextData = [@"Super🔥secret🔥test🔥data🏁🏁" dataUsingEncoding:NSUTF8StringEncoding];
// Sanity Check
XCTAssertEqual(39, plainTextData.length);
OWSAES128Key *key = [OWSAES128Key new];
OWSAES256Key *key = [OWSAES256Key new];
NSData *_Nullable encryptedData = [Cryptography encryptAESGCMWithData:plainTextData key:key];
const NSUInteger ivLength = 12;
@ -156,7 +156,7 @@ NS_ASSUME_NONNULL_BEGIN
// Sanity Check
XCTAssertEqual(39, plainTextData.length);
OWSAES128Key *key = [OWSAES128Key new];
OWSAES256Key *key = [OWSAES256Key new];
NSData *_Nullable encryptedData = [Cryptography encryptAESGCMWithData:plainTextData key:key];
const NSUInteger ivLength = 12;
@ -174,7 +174,7 @@ NS_ASSUME_NONNULL_BEGIN
NSData *authTag = [encryptedData subdataWithRange:NSMakeRange(ivLength + cipherTextLength, tagLength)];
NSData *_Nullable decryptedData = [Cryptography decryptAESGCMWithInitializationVector:initializationVector
cipherText:cipherText
ciphertext:cipherText
authTag:authTag
key:key];
@ -194,7 +194,7 @@ NS_ASSUME_NONNULL_BEGIN
[bogusAuthTag replaceBytesInRange:NSMakeRange(0, 1) withBytes:&flippedByte];
decryptedData = [Cryptography decryptAESGCMWithInitializationVector:initializationVector
cipherText:cipherText
ciphertext:cipherText
authTag:bogusAuthTag
key:key];