Compare commits
No commits in common. "main" and "mkirk/framework-friendly" have entirely different histories.
main
...
mkirk/fram
@ -1,15 +0,0 @@
|
||||
---
|
||||
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
|
||||
...
|
||||
@ -1,16 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@ -1,11 +1,15 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// BuildTestsTests.m
|
||||
// BuildTestsTests
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/07/14.
|
||||
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Curve25519.h"
|
||||
#import "Ed25519.h"
|
||||
#import <SignalCoreKit/Randomness.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "Curve25519.h"
|
||||
#import "Randomness.h"
|
||||
#import "Ed25519.h"
|
||||
|
||||
@interface SigningTests : XCTestCase
|
||||
|
||||
@ -31,13 +35,14 @@
|
||||
ECKeyPair *key = [Curve25519 generateKeyPair];
|
||||
|
||||
NSData *data = [Randomness generateRandomBytes:i];
|
||||
|
||||
NSData *signature = [Ed25519 throws_sign:data withKeyPair:key];
|
||||
|
||||
if (![Ed25519 throws_verifySignature:signature publicKey:[key publicKey] data:data]) {
|
||||
|
||||
NSData *signature = [Ed25519 sign:data withKeyPair:key];
|
||||
|
||||
if (![Ed25519 verifySignature:signature publicKey:[key publicKey] data:data]) {
|
||||
XCTAssert(false, @"Failed to verify signature while performing testing");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,10 +53,10 @@
|
||||
ECKeyPair *key = [Curve25519 generateKeyPair];
|
||||
|
||||
NSData *data = [Randomness generateRandomBytes:32];
|
||||
|
||||
NSData *signature = [Ed25519 throws_sign:data withKeyPair:key];
|
||||
|
||||
if (![Ed25519 throws_verifySignature:signature publicKey:[key publicKey] data:data]) {
|
||||
|
||||
NSData *signature = [Ed25519 sign:data withKeyPair:key];
|
||||
|
||||
if (![Ed25519 verifySignature:signature publicKey:[key publicKey] data:data]) {
|
||||
XCTAssert(false, @"Verifying a signed 32-byte identity key failed");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,42 +1,26 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
// Curve25519.h
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/07/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#define ECCKeyLength 32
|
||||
#define ECCSignatureLength 64
|
||||
|
||||
extern NSErrorDomain const Curve25519KitErrorDomain;
|
||||
typedef NS_ERROR_ENUM(Curve25519KitErrorDomain, Curve25519KitError){
|
||||
Curve25519KitError_InvalidKeySize = 1
|
||||
};
|
||||
@interface ECKeyPair : NSObject <NSSecureCoding> {
|
||||
uint8_t publicKey [ECCKeyLength];
|
||||
uint8_t privateKey[ECCKeyLength];
|
||||
}
|
||||
|
||||
@interface ECKeyPair : NSObject <NSSecureCoding>
|
||||
|
||||
@property (atomic, readonly) NSData *publicKey;
|
||||
@property (atomic, readonly) NSData *privateKey;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Build a keypair from existing key data.
|
||||
* If you need a *new* keypair, user `Curve25519.generateKeyPair` instead.
|
||||
*/
|
||||
- (nullable instancetype)initWithPublicKeyData:(NSData *)publicKeyData
|
||||
privateKeyData:(NSData *)privateKeyData
|
||||
error:(NSError **)error NS_DESIGNATED_INITIALIZER;
|
||||
-(NSData*) publicKey;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface Curve25519 : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Generate a 32-byte shared secret from a public key and a key pair using curve25519.
|
||||
*
|
||||
@ -45,21 +29,15 @@ typedef NS_ERROR_ENUM(Curve25519KitErrorDomain, Curve25519KitError){
|
||||
*
|
||||
* @return 32-byte shared secret derived from ECDH with curve25519 public key and key pair.
|
||||
*/
|
||||
+ (NSData *)throws_generateSharedSecretFromPublicKey:(NSData *)theirPublicKey andKeyPair:(ECKeyPair *)keyPair NS_SWIFT_UNAVAILABLE("throws objc expections");
|
||||
|
||||
+ (NSData *)throws_generateSharedSecretFromPublicKey:(NSData *)publicKey privateKey:(NSData *)privateKey NS_SWIFT_UNAVAILABLE("throws objc expections");
|
||||
|
||||
+ (nullable NSData *)generateSharedSecretFromPublicKey:(NSData *)publicKey
|
||||
privateKey:(NSData *)privateKey
|
||||
error:(NSError **)outError;
|
||||
+ (NSData*)generateSharedSecretFromPublicKey:(NSData*)theirPublicKey andKeyPair:(ECKeyPair*)keyPair;
|
||||
|
||||
/**
|
||||
* Generate a curve25519 key pair
|
||||
*
|
||||
* @return curve25519 key pair.
|
||||
*/
|
||||
+ (ECKeyPair *)generateKeyPair;
|
||||
|
||||
+ (ECKeyPair*)generateKeyPair;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,198 +1,124 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
// Curve25519.m
|
||||
// BuildTests
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/07/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Curve25519.h"
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalCoreKit/Randomness.h>
|
||||
#import <SignalCoreKit/SCKExceptionWrapper.h>
|
||||
#import "Randomness.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
NSErrorDomain const Curve25519KitErrorDomain = @"Curve25519KitErrorDomain";
|
||||
|
||||
NSString *const TSECKeyPairPublicKey = @"TSECKeyPairPublicKey";
|
||||
NSString *const TSECKeyPairPrivateKey = @"TSECKeyPairPrivateKey";
|
||||
NSString *const TSECKeyPairPreKeyId = @"TSECKeyPairPreKeyId";
|
||||
NSString * const TSECKeyPairPublicKey = @"TSECKeyPairPublicKey";
|
||||
NSString * const TSECKeyPairPrivateKey = @"TSECKeyPairPrivateKey";
|
||||
NSString * const TSECKeyPairPreKeyId = @"TSECKeyPairPreKeyId";
|
||||
|
||||
extern void curve25519_donna(unsigned char *output, const unsigned char *a, const unsigned char *b);
|
||||
|
||||
extern int curve25519_sign(unsigned char *signature_out, /* 64 bytes */
|
||||
const unsigned char *curve25519_privkey, /* 32 bytes */
|
||||
const unsigned char *msg,
|
||||
const unsigned long msg_len,
|
||||
const unsigned char *random); /* 64 bytes */
|
||||
extern int curve25519_sign(unsigned char* signature_out, /* 64 bytes */
|
||||
const unsigned char* curve25519_privkey, /* 32 bytes */
|
||||
const unsigned char* msg, const unsigned long msg_len,
|
||||
const unsigned char* random); /* 64 bytes */
|
||||
|
||||
@implementation ECKeyPair
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
+ (BOOL)supportsSecureCoding{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeBytes:self.publicKey.bytes length:ECCKeyLength forKey:TSECKeyPairPublicKey];
|
||||
[coder encodeBytes:self.privateKey.bytes length:ECCKeyLength forKey:TSECKeyPairPrivateKey];
|
||||
-(void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeBytes:self->publicKey length:ECCKeyLength forKey:TSECKeyPairPublicKey];
|
||||
[coder encodeBytes:self->privateKey length:ECCKeyLength forKey:TSECKeyPairPrivateKey];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
NSUInteger returnedLength = 0;
|
||||
const uint8_t *returnedBuffer = NULL;
|
||||
|
||||
// De-serialize public key
|
||||
returnedBuffer = [coder decodeBytesForKey:TSECKeyPairPublicKey returnedLength:&returnedLength];
|
||||
if (returnedLength != ECCKeyLength) {
|
||||
OWSFailDebug(@"failure: wrong length for public key.");
|
||||
return nil;
|
||||
}
|
||||
NSData *publicKeyData = [NSData dataWithBytes:returnedBuffer length:returnedLength];
|
||||
|
||||
// De-serialize private key
|
||||
returnedBuffer = [coder decodeBytesForKey:TSECKeyPairPrivateKey returnedLength:&returnedLength];
|
||||
if (returnedLength != ECCKeyLength) {
|
||||
OWSFailDebug(@"failure: wrong length for private key.");
|
||||
return nil;
|
||||
}
|
||||
NSData *privateKeyData = [NSData dataWithBytes:returnedBuffer length:returnedLength];
|
||||
|
||||
NSError *error;
|
||||
ECKeyPair *keyPair = [self initWithPublicKeyData:publicKeyData
|
||||
privateKeyData:privateKeyData
|
||||
error:&error];
|
||||
if (error != nil) {
|
||||
OWSFailDebug(@"error: %@", error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a keypair from existing key data.
|
||||
* If you need a *new* keypair, user `generateKeyPair` instead.
|
||||
*/
|
||||
- (nullable instancetype)initWithPublicKeyData:(NSData *)publicKeyData
|
||||
privateKeyData:(NSData *)privateKeyData
|
||||
error:(NSError **)error
|
||||
{
|
||||
if (self = [super init]) {
|
||||
if (publicKeyData.length != ECCKeyLength || privateKeyData.length != ECCKeyLength) {
|
||||
*error = [NSError errorWithDomain:Curve25519KitErrorDomain
|
||||
code:Curve25519KitError_InvalidKeySize
|
||||
userInfo:nil];
|
||||
-(id)initWithCoder:(NSCoder *)coder {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
NSUInteger returnedLength = 0;
|
||||
const uint8_t *returnedBuffer = NULL;
|
||||
// De-serialize public key
|
||||
returnedBuffer = [coder decodeBytesForKey:TSECKeyPairPublicKey returnedLength:&returnedLength];
|
||||
if (returnedLength != ECCKeyLength) {
|
||||
return nil;
|
||||
}
|
||||
_publicKey = publicKeyData;
|
||||
_privateKey = privateKeyData;
|
||||
memcpy(self->publicKey, returnedBuffer, ECCKeyLength);
|
||||
|
||||
// De-serialize private key
|
||||
returnedBuffer = [coder decodeBytesForKey:TSECKeyPairPrivateKey returnedLength:&returnedLength];
|
||||
if (returnedLength != ECCKeyLength) {
|
||||
return nil;
|
||||
}
|
||||
memcpy(self->privateKey, returnedBuffer, ECCKeyLength);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (ECKeyPair *)generateKeyPair
|
||||
{
|
||||
// Generate key pair as described in
|
||||
// https://code.google.com/p/curve25519-donna/
|
||||
NSMutableData *privateKey = [[Randomness generateRandomBytes:ECCKeyLength] mutableCopy];
|
||||
uint8_t *privateKeyBytes = privateKey.mutableBytes;
|
||||
privateKeyBytes[0] &= 248;
|
||||
privateKeyBytes[31] &= 127;
|
||||
privateKeyBytes[31] |= 64;
|
||||
|
||||
static const uint8_t basepoint[ECCKeyLength] = { 9 };
|
||||
|
||||
NSMutableData *publicKey = [NSMutableData dataWithLength:ECCKeyLength];
|
||||
if (!publicKey) {
|
||||
OWSFail(@"Could not allocate buffer");
|
||||
}
|
||||
|
||||
curve25519_donna(publicKey.mutableBytes, privateKey.mutableBytes, basepoint);
|
||||
|
||||
ECKeyPair *keyPair = [[ECKeyPair alloc] initWithPublicKeyData:[publicKey copy]
|
||||
privateKeyData:[privateKey copy]
|
||||
error:nil];
|
||||
OWSAssert(keyPair != nil);
|
||||
|
||||
+(ECKeyPair*)generateKeyPair{
|
||||
ECKeyPair* keyPair =[[ECKeyPair alloc] init];
|
||||
|
||||
// Generate key pair as described in https://code.google.com/p/curve25519-donna/
|
||||
memcpy(keyPair->privateKey, [[Randomness generateRandomBytes:32] bytes], 32);
|
||||
keyPair->privateKey[0] &= 248;
|
||||
keyPair->privateKey[31] &= 127;
|
||||
keyPair->privateKey[31] |= 64;
|
||||
|
||||
static const uint8_t basepoint[ECCKeyLength] = {9};
|
||||
curve25519_donna(keyPair->publicKey, keyPair->privateKey, basepoint);
|
||||
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
- (NSData *)throws_sign:(NSData *)data
|
||||
{
|
||||
if (!data) {
|
||||
OWSRaiseException(NSInvalidArgumentException, @"Missing data.");
|
||||
}
|
||||
|
||||
NSMutableData *signatureData = [NSMutableData dataWithLength:ECCSignatureLength];
|
||||
if (!signatureData) {
|
||||
OWSFail(@"Could not allocate buffer");
|
||||
}
|
||||
-(NSData*) publicKey {
|
||||
return [NSData dataWithBytes:self->publicKey length:32];
|
||||
}
|
||||
|
||||
-(NSData*) sign:(NSData*)data{
|
||||
Byte signatureBuffer[ECCSignatureLength];
|
||||
NSData *randomBytes = [Randomness generateRandomBytes:64];
|
||||
|
||||
if (curve25519_sign(
|
||||
signatureData.mutableBytes, self.privateKey.bytes, [data bytes], [data length], [randomBytes bytes])
|
||||
== -1) {
|
||||
OWSRaiseException(NSInternalInconsistencyException, @"Message couldn't be signed.");
|
||||
|
||||
if(curve25519_sign(signatureBuffer, self->privateKey, [data bytes], [data length], [randomBytes bytes]) == -1 ){
|
||||
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Message couldn't be signed." userInfo:nil];
|
||||
}
|
||||
|
||||
NSData *signature = [NSData dataWithBytes:signatureBuffer length:ECCSignatureLength];
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
return [signatureData copy];
|
||||
-(NSData*) generateSharedSecretFromPublicKey:(NSData*)theirPublicKey {
|
||||
unsigned char *sharedSecret = NULL;
|
||||
|
||||
if ([theirPublicKey length] != 32) {
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"The supplied public key does not contain 32 bytes" userInfo:nil];
|
||||
}
|
||||
|
||||
sharedSecret = malloc(32);
|
||||
|
||||
if (sharedSecret == NULL) {
|
||||
free(sharedSecret);
|
||||
return nil;
|
||||
}
|
||||
|
||||
curve25519_donna(sharedSecret,self->privateKey, [theirPublicKey bytes]);
|
||||
|
||||
NSData *sharedSecretData = [NSData dataWithBytes:sharedSecret length:32];
|
||||
|
||||
free(sharedSecret);
|
||||
|
||||
return sharedSecretData;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation Curve25519
|
||||
|
||||
+ (ECKeyPair *)generateKeyPair
|
||||
{
|
||||
+(ECKeyPair*)generateKeyPair{
|
||||
return [ECKeyPair generateKeyPair];
|
||||
}
|
||||
|
||||
+ (NSData *)throws_generateSharedSecretFromPublicKey:(NSData *)theirPublicKey andKeyPair:(ECKeyPair *)keyPair
|
||||
{
|
||||
if (!keyPair) {
|
||||
OWSRaiseException(NSInvalidArgumentException, @"Missing key pair.");
|
||||
}
|
||||
|
||||
return [self throws_generateSharedSecretFromPublicKey:theirPublicKey privateKey:keyPair.privateKey];
|
||||
}
|
||||
|
||||
+ (nullable NSData *)generateSharedSecretFromPublicKey:(NSData *)publicKey
|
||||
privateKey:(NSData *)privateKey
|
||||
error:(NSError **)outError
|
||||
{
|
||||
@try {
|
||||
return [self throws_generateSharedSecretFromPublicKey:publicKey privateKey:privateKey];
|
||||
} @catch (NSException *exception) {
|
||||
*outError = SCKExceptionWrapperErrorMake(exception);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSData *)throws_generateSharedSecretFromPublicKey:(NSData *)publicKey privateKey:(NSData *)privateKey
|
||||
{
|
||||
if (publicKey.length != ECCKeyLength) {
|
||||
OWSRaiseException(
|
||||
NSInvalidArgumentException, @"Public key has unexpected length: %lu", (unsigned long)publicKey.length);
|
||||
}
|
||||
if (privateKey.length != ECCKeyLength) {
|
||||
OWSRaiseException(
|
||||
NSInvalidArgumentException, @"Private key has unexpected length: %lu", (unsigned long)privateKey.length);
|
||||
}
|
||||
|
||||
NSMutableData *sharedSecretData = [NSMutableData dataWithLength:32];
|
||||
if (!sharedSecretData) {
|
||||
OWSFail(@"Could not allocate buffer");
|
||||
}
|
||||
|
||||
curve25519_donna(sharedSecretData.mutableBytes, privateKey.bytes, publicKey.bytes);
|
||||
|
||||
return [sharedSecretData copy];
|
||||
+(NSData*)generateSharedSecretFromPublicKey:(NSData *)theirPublicKey andKeyPair:(ECKeyPair *)keyPair{
|
||||
return [keyPair generateSharedSecretFromPublicKey:theirPublicKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalCoreKit
|
||||
|
||||
public extension ECKeyPair {
|
||||
// TODO: Rename to publicKey(), rename existing publicKey() method to publicKeyData().
|
||||
func ecPublicKey() throws -> ECPublicKey {
|
||||
guard publicKey.count == ECCKeyLength else {
|
||||
throw OWSAssertionError("\(logTag) public key has invalid length")
|
||||
}
|
||||
|
||||
// NOTE: we don't use ECPublicKey(serializedKeyData:) since the
|
||||
// key data should not have a type byte.
|
||||
return try ECPublicKey(keyData: publicKey)
|
||||
}
|
||||
|
||||
// TODO: Rename to privateKey(), rename existing privateKey() method to privateKeyData().
|
||||
func ecPrivateKey() throws -> ECPrivateKey {
|
||||
guard privateKey.count == ECCKeyLength else {
|
||||
throw OWSAssertionError("\(logTag) private key has invalid length")
|
||||
}
|
||||
|
||||
return try ECPrivateKey(keyData: privateKey)
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalCoreKit
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/87fae0f98332e98a32bbb82515428b4edeb4181f/java/src/main/java/org/whispersystems/libsignal/ecc/ECPrivateKey.java
|
||||
@objc public class ECPrivateKey: NSObject {
|
||||
|
||||
@objc
|
||||
public let keyData: Data
|
||||
|
||||
@objc
|
||||
public init(keyData: Data) throws {
|
||||
guard keyData.count == ECCKeyLength else {
|
||||
throw OWSAssertionError("\(ECPrivateKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData
|
||||
}
|
||||
|
||||
open override func isEqual(_ object: Any?) -> Bool {
|
||||
if let object = object as? ECPrivateKey {
|
||||
return keyData == object.keyData
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public override var hash: Int {
|
||||
return keyData.hashValue
|
||||
}
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalCoreKit
|
||||
|
||||
public enum ECKeyError: Error {
|
||||
case assertionError(description: String)
|
||||
}
|
||||
|
||||
// See:
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/87fae0f98332e98a32bbb82515428b4edeb4181f/java/src/main/java/org/whispersystems/libsignal/ecc/DjbECPublicKey.java
|
||||
@objc public class ECPublicKey: NSObject {
|
||||
|
||||
@objc
|
||||
public static let keyTypeDJB: UInt8 = 0x05
|
||||
|
||||
@objc
|
||||
public let keyData: Data
|
||||
|
||||
@objc
|
||||
public init(keyData: Data) throws {
|
||||
guard keyData.count == ECCKeyLength else {
|
||||
throw ECKeyError.assertionError(description: "\(ECPublicKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData
|
||||
}
|
||||
|
||||
// https://github.com/signalapp/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/ecc/Curve.java#L30
|
||||
@objc
|
||||
public init(serializedKeyData: Data) throws {
|
||||
let parser = OWSDataParser(data: serializedKeyData)
|
||||
|
||||
let typeByte = try parser.nextByte(name: "type byte")
|
||||
guard typeByte == ECPublicKey.keyTypeDJB else {
|
||||
throw ECKeyError.assertionError(description: "\(ECPublicKey.logTag) key data has invalid type byte")
|
||||
}
|
||||
|
||||
let keyData = try parser.remainder(name: "key data")
|
||||
guard keyData.count == ECCKeyLength else {
|
||||
throw ECKeyError.assertionError(description: "\(ECPublicKey.logTag) key has invalid length")
|
||||
}
|
||||
|
||||
self.keyData = keyData
|
||||
}
|
||||
|
||||
@objc public var serialized: Data {
|
||||
return Data([ECPublicKey.keyTypeDJB] + keyData)
|
||||
}
|
||||
|
||||
open override func isEqual(_ object: Any?) -> Bool {
|
||||
if let object = object as? ECPublicKey {
|
||||
return keyData == object.keyData
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public override var hash: Int {
|
||||
return keyData.hashValue
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Ed25519.h
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/07/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ECKeyPair;
|
||||
|
||||
@interface Ed25519 : NSObject
|
||||
@ -18,43 +19,19 @@
|
||||
*
|
||||
* @return The ed25519 64-bytes signature.
|
||||
*/
|
||||
+ (NSData *)throws_sign:(NSData *)data withKeyPair:(ECKeyPair *)keyPair NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
+ (nullable NSData *)sign:(NSData *)data withKeyPair:(ECKeyPair *)keyPair error:(NSError **)outError;
|
||||
|
||||
+(NSData*)sign:(NSData*)data withKeyPair:(ECKeyPair*)keyPair;
|
||||
|
||||
/**
|
||||
* Verify ed25519 signature with 32-bytes Curve25519 key pair. Throws an NSInvalid
|
||||
*
|
||||
* @param signature ed25519 64-byte signature.
|
||||
* @param publicKey public key of the signer.
|
||||
* @param pubKey public key of the signer.
|
||||
* @param data data to be checked against the signature.
|
||||
*
|
||||
* @return Returns TRUE if the signature is valid, false if it's not.
|
||||
*/
|
||||
+ (BOOL)throws_verifySignature:(NSData *)signature
|
||||
publicKey:(NSData *)publicKey
|
||||
data:(NSData *)data NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
|
||||
/**
|
||||
* Verify ed25519 signature with 32-bytes Curve25519 key pair. Throws an NSInvalid
|
||||
*
|
||||
* @param signature ed25519 64-byte signature.
|
||||
* @param publicKey public key of the signer.
|
||||
* @param data data to be checked against the signature.
|
||||
* @param didVerify whether or not the signature was verified.
|
||||
*
|
||||
* @return Returns YES if no error was encountered
|
||||
* Returns NO if an error was encountered while verifying signature.
|
||||
*
|
||||
* NOTE: In line with convention's required for Swift interop, the return value does *not* indicate
|
||||
* whether or not the signature was verified - check `didVerify` for that. The return value only
|
||||
* indicates whether an error was encountered.
|
||||
*/
|
||||
+ (BOOL)verifySignature:(NSData *)signature
|
||||
publicKey:(NSData *)publicKey
|
||||
data:(NSData *)data
|
||||
didVerify:(BOOL *)didVerify
|
||||
error:(NSError **)outError NS_REFINED_FOR_SWIFT;
|
||||
+(BOOL)verifySignature:(NSData*)signature publicKey:(NSData*)pubKey data:(NSData*)data;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,92 +1,50 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Ed25519.m
|
||||
// BuildTests
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/07/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Ed25519.h"
|
||||
#import "Curve25519.h"
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalCoreKit/SCKExceptionWrapper.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern int curve25519_verify(const unsigned char *signature, /* 64 bytes */
|
||||
const unsigned char *curve25519_pubkey, /* 32 bytes */
|
||||
const unsigned char *msg,
|
||||
const unsigned long msg_len);
|
||||
|
||||
@interface ECKeyPair ()
|
||||
|
||||
- (NSData *)throws_sign:(NSData *)data;
|
||||
|
||||
-(NSData*) sign:(NSData*)data;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
extern int curve25519_verify(const unsigned char* signature, /* 64 bytes */
|
||||
const unsigned char* curve25519_pubkey, /* 32 bytes */
|
||||
const unsigned char* msg, const unsigned long msg_len);
|
||||
|
||||
@implementation Ed25519
|
||||
|
||||
+ (nullable NSData *)sign:(NSData *)data withKeyPair:(ECKeyPair *)keyPair error:(NSError **)outError
|
||||
{
|
||||
@try {
|
||||
return [self throws_sign:data withKeyPair:keyPair];
|
||||
} @catch (NSException *exception) {
|
||||
*outError = SCKExceptionWrapperErrorMake(exception);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSData *)throws_sign:(NSData *)data withKeyPair:(ECKeyPair *)keyPair
|
||||
{
|
||||
+(NSData*)sign:(NSData*)data withKeyPair:(ECKeyPair*)keyPair{
|
||||
|
||||
if ([data length] < 1) {
|
||||
OWSRaiseException(NSInvalidArgumentException, @"Data needs to be at least one byte");
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Data needs to be at least one byte" userInfo:nil];
|
||||
}
|
||||
if (!keyPair) {
|
||||
OWSRaiseException(NSInvalidArgumentException, @"Missing key pair.");
|
||||
}
|
||||
|
||||
return [keyPair throws_sign:data];
|
||||
|
||||
return [keyPair sign:data];
|
||||
}
|
||||
|
||||
+ (BOOL)verifySignature:(NSData *)signature
|
||||
publicKey:(NSData *)publicKey
|
||||
data:(NSData *)data
|
||||
didVerify:(BOOL *)didVerify
|
||||
error:(NSError **)outError;
|
||||
{
|
||||
@try {
|
||||
*didVerify = [self throws_verifySignature:signature publicKey:publicKey data:data];
|
||||
// TODO this seems potentially unintuitive for the caller.
|
||||
// Instead of returning YES, should we remove didVerify and return an error when verification fails? (but no
|
||||
// exception was thrown)
|
||||
return YES;
|
||||
} @catch (NSException *exception) {
|
||||
*outError = SCKExceptionWrapperErrorMake(exception);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)throws_verifySignature:(NSData *)signature publicKey:(NSData *)pubKey data:(NSData *)data
|
||||
{
|
||||
+(BOOL)verifySignature:(NSData*)signature publicKey:(NSData*)pubKey data:(NSData*)data{
|
||||
|
||||
if ([data length] < 1) {
|
||||
OWSRaiseException(NSInvalidArgumentException, @"Data needs to be at least one byte");
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Data needs to be at least one byte" userInfo:nil];
|
||||
}
|
||||
if ([data length] >= ULONG_MAX) {
|
||||
OWSRaiseException(NSInvalidArgumentException, @"Data is too long.");
|
||||
}
|
||||
|
||||
|
||||
if ([pubKey length] != ECCKeyLength) {
|
||||
OWSRaiseException(
|
||||
NSInvalidArgumentException, @"Public Key has unexpected length: %lu", (unsigned long)pubKey.length);
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Public Key isn't 32 bytes" userInfo:nil];
|
||||
}
|
||||
|
||||
|
||||
if ([signature length] != ECCSignatureLength) {
|
||||
OWSRaiseException(
|
||||
NSInvalidArgumentException, @"Signature has unexpected length: %lu", (unsigned long)signature.length);
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Signature isn't 64 bytes" userInfo:nil];
|
||||
}
|
||||
|
||||
|
||||
BOOL success = (curve25519_verify([signature bytes], [pubKey bytes], [data bytes], [data length]) == 0);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Ed25519 {
|
||||
class func verifySignature(_ signature: Data, publicKey: Data, data: Data) throws -> Bool {
|
||||
var didVerify: ObjCBool = false
|
||||
try __verifySignature(signature, publicKey: publicKey, data: data, didVerify: &didVerify)
|
||||
|
||||
return didVerify.boolValue
|
||||
}
|
||||
}
|
||||
24
Classes/Randomness.h
Normal file
24
Classes/Randomness.h
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// Randomness.h
|
||||
// AxolotlKit
|
||||
//
|
||||
// Created by Frederic Jacobs on 21/07/14.
|
||||
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface Randomness : NSObject
|
||||
|
||||
/**
|
||||
* Generates a given number of cryptographically secure bytes using SecRandomCopyBytes.
|
||||
*
|
||||
* @param numberBytes The number of bytes to be generated.
|
||||
*
|
||||
* @return Random Bytes.
|
||||
*/
|
||||
|
||||
+(NSData*) generateRandomBytes:(int)numberBytes;
|
||||
|
||||
|
||||
@end
|
||||
24
Classes/Randomness.m
Normal file
24
Classes/Randomness.m
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// Randomness.m
|
||||
// AxolotlKit
|
||||
//
|
||||
// Created by Frederic Jacobs on 21/07/14.
|
||||
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Randomness.h"
|
||||
|
||||
@implementation Randomness
|
||||
|
||||
+(NSData*) generateRandomBytes:(int)numberBytes {
|
||||
/* used to generate db master key, and to generate signaling key, both at install */
|
||||
NSMutableData* randomBytes = [NSMutableData dataWithLength:numberBytes];
|
||||
int err = 0;
|
||||
err = SecRandomCopyBytes(kSecRandomDefault,numberBytes,[randomBytes mutableBytes]);
|
||||
if(err != noErr && [randomBytes length] != numberBytes) {
|
||||
@throw [NSException exceptionWithName:@"random problem" reason:@"problem generating the random " userInfo:nil];
|
||||
}
|
||||
return [NSData dataWithData:randomBytes];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -11,19 +11,10 @@ Pod::Spec.new do |spec|
|
||||
Curve25519 is a fast and secure curve used for key agreement. Unfortunately, it does not support signing out of the box. This pod translates the point curves to do ed25519 signing with curve25519 keys.
|
||||
DESC
|
||||
|
||||
spec.source = { :git => 'https://github.com/signalapp/Curve25519Kit.git', :tag => "#{spec.version}" }
|
||||
spec.source_files = 'Classes/*.{h,m,swift}', 'Sources/Curve25519/curve25519-donna.c', 'Sources/ed25519/*.{c,h}', 'Sources/ed25519/additions/*.{c,h}', 'Sources/ed25519/nacl_sha512/*.{c,h}', 'Sources/ed25519/nacl_includes/*.{c,h}', 'Private/*.{h,m}'
|
||||
spec.public_header_files = 'Classes/**/*.h'
|
||||
spec.source = { :git => 'https://github.com/WhisperSystems/Curve25519Kit.git', :tag => "#{spec.version}" }
|
||||
spec.source_files = 'Classes/*.{h,m}', 'Sources/Curve25519/curve25519-donna.c', 'Sources/ed25519/*.{c,h}', 'Sources/ed25519/additions/*.{c,h}', 'Sources/ed25519/nacl_sha512/*.{c,h}', 'Sources/ed25519/nacl_includes/*.{c,h}'
|
||||
#spec.private_header_files = 'Sources/ed25519/nacl_includes/*.h','Sources/ed25519/additions/*.h', 'Sources/ed25519/nacl_sha512/*.h'
|
||||
spec.framework = 'Security'
|
||||
spec.public_header_files = "Classes/*.h"
|
||||
spec.requires_arc = true
|
||||
spec.ios.deployment_target = "10.0"
|
||||
|
||||
spec.dependency 'CocoaLumberjack'
|
||||
spec.dependency 'SignalCoreKit'
|
||||
|
||||
spec.test_spec 'Tests' do |test_spec|
|
||||
test_spec.source_files = 'BuildTests/BuildTestsTests/**/*.{h,m,swift}'
|
||||
end
|
||||
end
|
||||
|
||||
@ -63,7 +63,7 @@ int curve25519_sign(unsigned char* signature_out,
|
||||
signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */
|
||||
signature_out[63] |= sign_bit;
|
||||
|
||||
free(sigbuf);
|
||||
//free(sigbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user