Compare commits

...

21 Commits

Author SHA1 Message Date
Nora Trapp
b6985abcac Merge branch 'nt/deployment-target' 2019-09-23 16:51:42 -07:00
Nora Trapp
2e404a73df Update deployment target to iOS 10 2019-09-23 10:52:34 -07:00
Michael Kirk
3e0c2371d1 Merge branch 'mkirk/wrap-exceptions' 2018-10-30 11:14:30 -06:00
Michael Kirk
9d67d66aa7 gitignore xcuserdata 2018-10-30 11:14:18 -06:00
Michael Kirk
99f17d7f36 Label methods that throw objc exceptions, provide Swift alternative 2018-10-30 11:14:18 -06:00
Matthew Chen
8b8326cd50 Merge branch 'charlesmchen/sck' 2018-09-28 08:50:43 -04:00
Matthew Chen
222393e49b Add placeholder Swift test. 2018-09-25 13:55:02 -04:00
Matthew Chen
3409253900 Update podspec. 2018-09-25 12:48:21 -04:00
Matthew Chen
a92afaa296 Fix asserts & logging. 2018-09-25 11:22:57 -04:00
Michael Kirk
f6e051a765 Merge branch 'mkirk/overflow' 2018-09-07 13:29:04 -06:00
Michael Kirk
7e36357170 check overflow for one multiply vs many additions 2018-08-30 10:43:35 -06:00
Michael Kirk
4729d711b7 Assert length of result data components avoids overflow 2018-08-30 09:42:44 -06:00
Michael Kirk
79bc69920a check iteration overflow 2018-08-30 09:42:44 -06:00
Michael Kirk
96527fd38f overflow macros 2018-08-30 09:42:39 -06:00
Michael Kirk
62e1f578a0 Make OWSAssert terminate in production, introduce OWSAssertDebug which will not
terminate in production.

No change in behavior here since these two methods aren't yet used in HKDFKit.
2018-08-30 09:37:06 -06:00
Michael Kirk
51d6edfab8 Merge branch 'charlesmchen/loggingAndAsserts' 2018-08-29 11:53:13 -06:00
Matthew Chen
7c8e7cb9eb Respond to CR. Make headers private, change prefix. 2018-08-28 14:12:19 -04:00
Matthew Chen
3a9c12ff92 Logging and asserts. 2018-08-28 13:06:11 -04:00
Matthew Chen
780f980b8f Merge branch 'charlesmchen/cleanupFormatting' 2018-08-02 16:15:04 -04:00
Matthew Chen
f1d29b3f64 Clean up formatting. 2018-07-27 12:37:23 -04:00
Matthew Chen
b7d25e5c17 Merge remote-tracking branch 'origin/mkirk/framework-friendly' 2018-07-27 12:25:37 -04:00
8 changed files with 200 additions and 62 deletions

15
.clang-format Normal file
View File

@ -0,0 +1,15 @@
---
BasedOnStyle: WebKit
AllowShortFunctionsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
ColumnLimit: 120
IndentCaseLabels: true
MaxEmptyLinesToKeep: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PointerBindsToType: false
SpacesBeforeTrailingComments: 1
TabWidth: 8
UseTab: Never
...

36
.gitignore vendored
View File

@ -1,8 +1,30 @@
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control?
#
# Pods/
# Exclude the build directory
build/*
# Exclude temp nibs and swap files
*~.nib
*.swp
# Exclude OS X folder attributes
.DS_Store
# Exclude user-specific XCode 3 and 4 files
xcuserdata
*.xccheckout
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
Index/

View File

@ -14,9 +14,16 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/FredericJacobs/HKDFKit.git", :tag => "0.0.3" }
s.source_files = 'HKDFKit/HKDFKit/*{h,m}'
s.source_files = 'HKDFKit/HKDFKit/*.{h,m,mm,swift}', 'HKDFKit/Private/*.{h,m,mm,swift}'
s.public_header_files = 'HKDFKit/HKDFKit/*.h'
s.ios.deployment_target = "10.0"
s.requires_arc = true
s.dependency 'CocoaLumberjack'
s.dependency 'SignalCoreKit'
s.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'HKDFKit/HKDFKitTests/**/*.{h,m,swift}'
end
end

View File

@ -1,13 +1,11 @@
//
// HKDFKit.h
// HKDFKit
//
// Created by Frederic Jacobs on 29/03/14.
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface HKDFKit : NSObject
/**
@ -20,8 +18,15 @@
*
* @return The derived key material
*/
+ (NSData*)deriveKey:(NSData*)seed info:(NSData*)info salt:(NSData*)salt outputSize:(int)outputSize;
+ (NSData *)throws_deriveKey:(NSData *)seed
info:(nullable NSData *)info
salt:(NSData *)salt
outputSize:(int)outputSize NS_SWIFT_UNAVAILABLE("throws objc exceptions");
+ (nullable NSData *)deriveKey:(NSData *)seed
info:(nullable NSData *)info
salt:(NSData *)salt
outputSize:(int)outputSize
error:(NSError **)outError;
/**
* TextSecure v2 HKDF implementation
@ -33,8 +38,11 @@
*
* @return The derived key material
*/
+ (NSData*)TextSecureV2deriveKey:(NSData*)seed info:(NSData*)info salt:(NSData*)salt outputSize:(int)outputSize;
+ (NSData *)throws_TextSecureV2deriveKey:(NSData *)seed
info:(nullable NSData *)info
salt:(NSData *)salt
outputSize:(int)outputSize NS_SWIFT_UNAVAILABLE("throws objc exceptions");
@end
NS_ASSUME_NONNULL_END

View File

@ -1,47 +1,111 @@
//
// HKDFKit.m
// HKDFKit
//
// Created by Frederic Jacobs on 29/03/14.
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "HKDFKit.h"
#import <CommonCrypto/CommonCrypto.h>
#import <SignalCoreKit/OWSAsserts.h>
#import <SignalCoreKit/SCKExceptionWrapper.h>
NS_ASSUME_NONNULL_BEGIN
#define HKDF_HASH_ALG kCCHmacAlgSHA256
#define HKDF_HASH_LEN CC_SHA256_DIGEST_LENGTH
@implementation HKDFKit
+ (NSData *)deriveKey:(NSData *)seed info:(NSData *)info salt:(NSData *)salt outputSize:(int)outputSize{
return [self deriveKey:seed info:info salt:salt outputSize:outputSize offset:1];
+ (nullable NSData *)deriveKey:(NSData *)seed
info:(nullable NSData *)info
salt:(NSData *)salt
outputSize:(int)outputSize
error:(NSError **)outError
{
@try {
return [self throws_deriveKey:seed info:info salt:salt outputSize:outputSize];
} @catch (NSException *exception) {
*outError = SCKExceptionWrapperErrorMake(exception);
return nil;
}
}
+ (NSData*)TextSecureV2deriveKey:(NSData*)seed info:(NSData*)info salt:(NSData*)salt outputSize:(int)outputSize{
return [self deriveKey:seed info:info salt:salt outputSize:outputSize offset:0];
+ (NSData *)throws_deriveKey:(NSData *)seed info:(nullable NSData *)info salt:(NSData *)salt outputSize:(int)outputSize
{
return [self throws_deriveKey:seed info:info salt:salt outputSize:outputSize offset:1];
}
+ (NSData *)throws_TextSecureV2deriveKey:(NSData *)seed
info:(nullable NSData *)info
salt:(NSData *)salt
outputSize:(int)outputSize
{
return [self throws_deriveKey:seed info:info salt:salt outputSize:outputSize offset:0];
}
#pragma mark Private Methods
+ (NSData *)deriveKey:(NSData *)seed info:(NSData *)info salt:(NSData *)salt outputSize:(int)outputSize offset:(int)offset{
NSData *prk = [self extract:seed salt:salt];
NSData *okm = [self expand:prk info:info outputSize:outputSize offset:offset];
+ (NSData *)throws_deriveKey:(NSData *)seed
info:(nullable NSData *)info
salt:(NSData *)salt
outputSize:(int)outputSize
offset:(int)offset
{
NSData *prk = [self throws_extract:seed salt:salt];
NSData *okm = [self throws_expand:prk info:info outputSize:outputSize offset:offset];
return okm;
}
+ (NSData*)extract:(NSData*)data salt:(NSData*)salt{
char prk[HKDF_HASH_LEN] = {0};
CCHmac(HKDF_HASH_ALG, [salt bytes], [salt length], [data bytes], [data length], prk);
return [NSData dataWithBytes:prk length:sizeof(prk)];
+ (NSData *)throws_extract:(NSData *)data salt:(NSData *)salt
{
if (!salt) {
OWSRaiseException(NSInvalidArgumentException, @"Missing salt.");
}
if (salt.length >= SIZE_MAX) {
OWSRaiseException(NSInvalidArgumentException, @"Oversize salt.");
}
if (!data) {
OWSRaiseException(NSInvalidArgumentException, @"Missing data.");
}
if (data.length >= SIZE_MAX) {
OWSRaiseException(NSInvalidArgumentException, @"Oversize data.");
}
NSMutableData *_Nullable prkData = [[NSMutableData alloc] initWithLength:HKDF_HASH_LEN];
if (!prkData) {
OWSFail(@"Could not allocate buffer.");
}
CCHmac(HKDF_HASH_ALG, [salt bytes], [salt length], [data bytes], [data length], prkData.mutableBytes);
return [prkData copy];
}
+ (NSData*)expand:(NSData*)data info:(NSData*)info outputSize:(int)outputSize offset:(int)offset{
int iterations = (int)ceil((double)outputSize/(double)HKDF_HASH_LEN);
NSData *mixin = [NSData data];
NSMutableData *results = [NSMutableData data];
+ (NSData *)throws_expand:(NSData *)data info:(nullable NSData *)info outputSize:(int)outputSize offset:(int)offset
{
if (!data) {
OWSRaiseException(NSInvalidArgumentException, @"Missing data.");
}
if (data.length >= SIZE_MAX) {
OWSRaiseException(NSInvalidArgumentException, @"Oversize data.");
}
if (info != nil && info.length >= SIZE_MAX) {
OWSRaiseException(NSInvalidArgumentException, @"Oversize info.");
}
if (outputSize >= NSUIntegerMax) {
OWSRaiseException(NSInvalidArgumentException, @"Oversize outputSize.");
}
if (outputSize < 1) {
OWSRaiseException(NSInvalidArgumentException, @"Invalid outputSize.");
}
for (int i=offset; i<(iterations+offset); i++) {
int iterations = (int)ceil((double)outputSize / (double)HKDF_HASH_LEN);
NSData *mixin = [NSData data];
NSMutableData *results = [NSMutableData data];
NSUInteger generatedLength;
ows_mul_overflow(HKDF_HASH_LEN, iterations, &generatedLength);
int offsetIterations;
ows_add_overflow(iterations, offset, &offsetIterations);
for (int i = offset; i < offsetIterations; i++) {
CCHmacContext ctx;
CCHmacInit(&ctx, HKDF_HASH_ALG, [data bytes], [data length]);
CCHmacUpdate(&ctx, [mixin bytes], [mixin length]);
@ -50,14 +114,19 @@
}
unsigned char c = i;
CCHmacUpdate(&ctx, &c, 1);
unsigned char T[HKDF_HASH_LEN];
CCHmacFinal(&ctx, T);
NSData *stepResult = [NSData dataWithBytes:T length:sizeof(T)];
[results appendData:stepResult];
mixin = [stepResult copy];
NSMutableData *_Nullable stepResultData = [[NSMutableData alloc] initWithLength:HKDF_HASH_LEN];
if (!stepResultData) {
OWSFail(@"Could not allocate buffer.");
}
CCHmacFinal(&ctx, stepResultData.mutableBytes);
[results appendData:stepResultData];
mixin = [stepResultData copy];
}
return [[NSData dataWithData:results] subdataWithRange:NSMakeRange(0, outputSize)];
OWSAssert(results.length == generatedLength);
return [results subdataWithRange:NSMakeRange(0, outputSize)];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,16 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import XCTest
// Cocoapods-generated test targets (like this one)
// fail to link if:
//
// * They only contain Obj-C tests.
// * They depend on pods that use Swift.
//
// The work around is to add (this) empty swift file
// to our test target.
//
// See: https://github.com/CocoaPods/CocoaPods/issues/7170

View File

@ -1,14 +1,9 @@
//
// HKDFKitTests.m
// HKDFKitTests
//
// Created by Frederic Jacobs on 29/03/14.
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "HKDFKit.h"
#import <XCTest/XCTest.h>
@interface HKDFKitTests : XCTestCase
@ -29,9 +24,12 @@
int l = 42;
NSString *OKM = @"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865";
NSData *hkdf = [HKDFKit deriveKey:[self stringToData:IKM] info:[self stringToData:info] salt:[self stringToData:salt] outputSize:l];
NSData *hkdf = [HKDFKit throws_deriveKey:[self stringToData:IKM]
info:[self stringToData:info]
salt:[self stringToData:salt]
outputSize:l];
XCTAssert([hkdf isEqualToData:[self stringToData:OKM]], @"Basic test case with SHA-256");
}
@ -44,9 +42,12 @@
int l = 82;
NSString *OKM = @"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87";
NSData *hkdf = [HKDFKit deriveKey:[self stringToData:IKM] info:[self stringToData:info] salt:[self stringToData:salt] outputSize:l];
NSData *hkdf = [HKDFKit throws_deriveKey:[self stringToData:IKM]
info:[self stringToData:info]
salt:[self stringToData:salt]
outputSize:l];
XCTAssert(([hkdf isEqualToData:[self stringToData:OKM]]), @"Test with SHA-256 and longer inputs/outputs");
}
@ -59,9 +60,9 @@
int l = 42;
NSString *OKM = @"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8";
NSData *hkdf = [HKDFKit deriveKey:[self stringToData:IKM] info:info salt:salt outputSize:l];
NSData *hkdf = [HKDFKit throws_deriveKey:[self stringToData:IKM] info:info salt:salt outputSize:l];
XCTAssert(([hkdf isEqualToData:[self stringToData:OKM]]), @"Test with SHA-256 and zero-length salt/info");
}