- Upgrade to 1.0
This commit is contained in:
1 parent
4e66c377fd
commit
0c2b3f1c25
452 files changed
+33888
-16806
No files matched your search
+19
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// NAAEAD.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NAAEAD : NSObject
|
||||
|
||||
@property (getter=isSecureDataEnabled) BOOL secureDataEnabled;
|
||||
|
||||
- (NSData *)encryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error;
|
||||
|
||||
- (NSData *)decryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error;
|
||||
|
||||
@end
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// NAAEAD.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NAAEAD.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
#import "NASecureData.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NAAEAD
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (NSData *)encryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error {
|
||||
if (!nonce || [nonce length] != NAAEADNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!additionalData) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidAdditionalData, @"Invalid additional data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!key || [key length] != NAAEADKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:[data length] + NAAEADASize];
|
||||
|
||||
unsigned long long outLength;
|
||||
int retval = crypto_aead_chacha20poly1305_encrypt([outData mutableBytes], &outLength,
|
||||
[data bytes], [data length],
|
||||
[additionalData bytes], [additionalData length],
|
||||
NULL,
|
||||
[nonce bytes],
|
||||
[key bytes]);
|
||||
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"AEAD encrypt failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
- (NSData *)decryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error {
|
||||
if (!nonce || [nonce length] != NAAEADNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!additionalData) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidAdditionalData, @"Invalid additional data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!key || [key length] != NAAEADKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block unsigned long long outLength;
|
||||
__block int retval = -1;
|
||||
NSMutableData *outData = NAData(self.secureDataEnabled, data.length, ^(void *bytes, NSUInteger length) {
|
||||
retval = crypto_aead_chacha20poly1305_decrypt(bytes, &outLength,
|
||||
NULL,
|
||||
[data bytes], [data length],
|
||||
[additionalData bytes], [additionalData length],
|
||||
[nonce bytes],
|
||||
[key bytes]);
|
||||
});
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [outData na_truncate:outData.length - (NSUInteger)outLength];
|
||||
}
|
||||
|
||||
@end
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// NAAuth.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/16/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/*!
|
||||
Computes an authentication tag for a message and a secret key, and provides a way to verify that a given tag is valid for a given message and a key.
|
||||
*/
|
||||
@interface NAAuth : NSObject
|
||||
|
||||
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
/*!
|
||||
Returns YES if verifies OK.
|
||||
*/
|
||||
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
|
||||
@end
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// NAAuth.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/16/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NAAuth.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NAAuth
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||
if (!key || [key length] != NAAuthKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:NAAuthSize];
|
||||
|
||||
crypto_auth([outData mutableBytes], [data bytes], [data length], [key bytes]);
|
||||
return outData;
|
||||
}
|
||||
|
||||
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||
if (!key || [key length] != NAAuthKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!auth || [auth length] != NAAuthSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (crypto_auth_verify([auth bytes], [data bytes], [data length], [key bytes]) != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||
return NO; // Message forged!
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// NABox.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "NABoxKeypair.h"
|
||||
|
||||
@interface NABox : NSObject
|
||||
|
||||
@property (getter=isSecureDataEnabled) BOOL secureDataEnabled;
|
||||
|
||||
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error;
|
||||
|
||||
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error;
|
||||
|
||||
@end
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// NABox.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NABox.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NABox
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error {
|
||||
if (!nonce || [nonce length] != NABoxNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!keypair) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid keypair");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:[data length] + NABoxMACSize];
|
||||
|
||||
int retval = crypto_box_easy([outData mutableBytes],
|
||||
[data bytes], [data length],
|
||||
[nonce bytes],
|
||||
[keypair.publicKey bytes],
|
||||
[keypair.secretKey bytes]);
|
||||
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"Encrypt (box) failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error {
|
||||
if (!nonce || [nonce length] != NABoxNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block int retval = -1;
|
||||
NSMutableData *outData = NAData(self.secureDataEnabled, data.length, ^(void *bytes, NSUInteger length) {
|
||||
retval = crypto_box_open_easy(bytes,
|
||||
[data bytes], [data length],
|
||||
[nonce bytes],
|
||||
[keypair.publicKey bytes],
|
||||
[keypair.secretKey bytes]);
|
||||
});
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [outData na_truncate:NABoxMACSize];
|
||||
}
|
||||
|
||||
@end
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NABoxKeypair.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "NASecureData.h"
|
||||
|
||||
@interface NABoxKeypair : NSObject
|
||||
|
||||
@property (readonly) NSData *publicKey;
|
||||
@property (readonly) NASecureData *secretKey;
|
||||
|
||||
- (instancetype)initWithPublicKey:(NSData *)publicKey secretKey:(NASecureData *)secretKey error:(NSError **)error;
|
||||
|
||||
+ (instancetype)generate:(NSError **)error;
|
||||
|
||||
@end
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// NABoxKeypair.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NABoxKeypair.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
#import "NASecureData.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@interface NABoxKeypair ()
|
||||
@property NSData *publicKey;
|
||||
@property NASecureData *secretKey;
|
||||
@end
|
||||
|
||||
@implementation NABoxKeypair
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (instancetype)initWithPublicKey:(NSData *)publicKey secretKey:(NASecureData *)secretKey error:(NSError **)error {
|
||||
if ((self = [super init])) {
|
||||
|
||||
if (!publicKey || [publicKey length] != NABoxPublicKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid public key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!secretKey || [secretKey length] != NABoxPublicKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid secret key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
_publicKey = publicKey;
|
||||
_secretKey = secretKey;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)generate:(NSError **)error {
|
||||
NSMutableData *publicKey = [NSMutableData dataWithLength:NABoxPublicKeySize];
|
||||
__block int retval = -1;
|
||||
NASecureData *secretKey = [NASecureData secureReadOnlyDataWithLength:NABoxSecretKeySize completion:^(void *bytes, NSUInteger length) {
|
||||
retval = crypto_box_keypair([publicKey mutableBytes], bytes);
|
||||
}];
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"Keypair generate failed");
|
||||
return nil;
|
||||
}
|
||||
return [[NABoxKeypair alloc] initWithPublicKey:publicKey secretKey:secretKey error:error];
|
||||
}
|
||||
|
||||
@end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// NAChloride.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel Handford on 1/16/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for NAChloride.
|
||||
FOUNDATION_EXPORT double NAChlorideVersionNumber;
|
||||
|
||||
//! Project version string for NAChloride.
|
||||
FOUNDATION_EXPORT const unsigned char NAChlorideVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <NAChloride/PublicHeader.h>
|
||||
|
||||
#import <NAChloride/NAInterface.h>
|
||||
|
||||
#import <NAChloride/NASecretBox.h>
|
||||
#import <NAChloride/NABox.h>
|
||||
#import <NAChloride/NABoxKeypair.h>
|
||||
#import <NAChloride/NAAuth.h>
|
||||
#import <NAChloride/NAAEAD.h>
|
||||
#import <NAChloride/NAOneTimeAuth.h>
|
||||
#import <NAChloride/NAScrypt.h>
|
||||
#import <NAChloride/NAStream.h>
|
||||
#import <NAChloride/NARandom.h>
|
||||
#import <NAChloride/NASecureData.h>
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// NAInterface.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/25/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM (NSInteger, NAErrorCode) {
|
||||
NAErrorCodeFailure = 1, // Generic failure
|
||||
|
||||
NAErrorCodeInvalidNonce = 100,
|
||||
NAErrorCodeInvalidKey = 101,
|
||||
NAErrorCodeInvalidData = 102,
|
||||
NAErrorCodeInvalidSalt = 103,
|
||||
NAErrorCodeInvalidAdditionalData = 104, // For AEAD
|
||||
|
||||
NAErrorCodeVerificationFailed = 205, // Verification failed
|
||||
};
|
||||
|
||||
extern const size_t NASecretBoxKeySize;
|
||||
extern const size_t NASecretBoxNonceSize;
|
||||
extern const size_t NASecretBoxMACSize;
|
||||
|
||||
extern const size_t NABoxPublicKeySize;
|
||||
extern const size_t NABoxSecretKeySize;
|
||||
extern const size_t NABoxNonceSize;
|
||||
extern const size_t NABoxMACSize;
|
||||
|
||||
extern const size_t NAAuthKeySize;
|
||||
extern const size_t NAAuthSize;
|
||||
|
||||
extern const size_t NAOneTimeAuthKeySize;
|
||||
extern const size_t NAOneTimeAuthSize;
|
||||
|
||||
extern const size_t NAScryptSaltSize;
|
||||
|
||||
extern const size_t NAStreamKeySize;
|
||||
extern const size_t NAStreamNonceSize;
|
||||
|
||||
extern const size_t NAXSalsaKeySize;
|
||||
extern const size_t NAXSalsaNonceSize;
|
||||
|
||||
extern const size_t NAAEADKeySize;
|
||||
extern const size_t NAAEADNonceSize;
|
||||
extern const size_t NAAEADASize;
|
||||
|
||||
|
||||
// Thread safe libsodium init
|
||||
void NAChlorideInit(void);
|
||||
|
||||
// Don't call this directly (use NAChlorideInit). This is made accessible for testing.
|
||||
int NASodiumInit(void);
|
||||
|
||||
|
||||
typedef id (^NAWork)(NSError **error);
|
||||
typedef void (^NACompletion)(NSError *error, id output);
|
||||
void NADispatch(dispatch_queue_t queue, NAWork work, NACompletion completion);
|
||||
|
||||
#define NAError(CODE, DESC) [NSError errorWithDomain:@"NAChloride" code:CODE userInfo:@{NSLocalizedDescriptionKey: DESC}];
|
||||
|
||||
typedef void (^NADataCompletion)(void *bytes, NSUInteger length);
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// NAInterface.m
|
||||
// NACL
|
||||
//
|
||||
// Created by Gabriel Handford on 1/16/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
const size_t NASecretBoxKeySize = crypto_secretbox_KEYBYTES;
|
||||
const size_t NASecretBoxNonceSize = crypto_secretbox_NONCEBYTES;
|
||||
const size_t NASecretBoxMACSize = crypto_secretbox_MACBYTES;
|
||||
|
||||
const size_t NABoxPublicKeySize = crypto_box_PUBLICKEYBYTES;
|
||||
const size_t NABoxSecretKeySize = crypto_box_SECRETKEYBYTES;
|
||||
const size_t NABoxNonceSize = crypto_box_NONCEBYTES;
|
||||
const size_t NABoxMACSize = crypto_box_MACBYTES;
|
||||
|
||||
const size_t NAAuthKeySize = crypto_auth_KEYBYTES;
|
||||
const size_t NAAuthSize = crypto_auth_BYTES;
|
||||
|
||||
const size_t NAOneTimeAuthKeySize = crypto_onetimeauth_KEYBYTES;
|
||||
const size_t NAOneTimeAuthSize = crypto_onetimeauth_BYTES;
|
||||
|
||||
const size_t NAScryptSaltSize = crypto_pwhash_scryptsalsa208sha256_SALTBYTES;
|
||||
|
||||
const size_t NAStreamKeySize = crypto_stream_KEYBYTES;
|
||||
const size_t NAStreamNonceSize = crypto_stream_NONCEBYTES;
|
||||
|
||||
const size_t NAXSalsaKeySize = crypto_stream_xsalsa20_KEYBYTES;
|
||||
const size_t NAXSalsaNonceSize = crypto_stream_xsalsa20_NONCEBYTES;
|
||||
|
||||
const size_t NAAEADKeySize = crypto_aead_chacha20poly1305_KEYBYTES;
|
||||
const size_t NAAEADNonceSize = crypto_aead_chacha20poly1305_NPUBBYTES;
|
||||
const size_t NAAEADASize = crypto_aead_chacha20poly1305_ABYTES;
|
||||
|
||||
|
||||
void NAChlorideInit(void) {
|
||||
static dispatch_once_t sodiumInit;
|
||||
dispatch_once(&sodiumInit, ^{ NASodiumInit(); });
|
||||
}
|
||||
|
||||
int NASodiumInit(void) {
|
||||
return sodium_init();
|
||||
}
|
||||
|
||||
void NADispatch(dispatch_queue_t queue, NAWork work, NACompletion completion) {
|
||||
dispatch_async(queue, ^{
|
||||
|
||||
NSError *error = nil;
|
||||
id output = work(&error);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(error, output);
|
||||
});
|
||||
});
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// NAOneTimeAuth.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 9/24/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/*!
|
||||
Generates a MAC for a given message and shared key using Poly1305 algorithm
|
||||
(key may NOT be reused across messages).
|
||||
*/
|
||||
@interface NAOneTimeAuth : NSObject
|
||||
|
||||
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
/*!
|
||||
Returns YES if verifies OK.
|
||||
*/
|
||||
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
@end
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// NAOneTimeAuth.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 9/24/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NAOneTimeAuth.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NAOneTimeAuth
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||
if (!key || [key length] != NAOneTimeAuthKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:NAOneTimeAuthSize];
|
||||
|
||||
crypto_onetimeauth([outData mutableBytes], [data bytes], [data length], [key bytes]);
|
||||
return outData;
|
||||
}
|
||||
|
||||
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||
if (!key || [key length] != NAOneTimeAuthKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!auth || [auth length] != NAOneTimeAuthSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (crypto_onetimeauth_verify([auth bytes], [data bytes], [data length], [key bytes]) != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||
return NO; // Message forged!
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// NARandom.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/16/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "NASecureData.h"
|
||||
|
||||
@interface NARandom : NSObject
|
||||
|
||||
/*!
|
||||
Random data of length bytes.
|
||||
*/
|
||||
+ (NSData *)randomData:(NSUInteger)length;
|
||||
|
||||
/*!
|
||||
Random & secure data of length bytes.
|
||||
*/
|
||||
+ (NASecureData *)randomSecureReadOnlyData:(NSUInteger)length;
|
||||
|
||||
@end
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// NARandom.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/16/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NARandom.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NARandom
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
+ (NSData *)randomData:(NSUInteger)length {
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:length];
|
||||
randombytes_buf([outData mutableBytes], length);
|
||||
return outData;
|
||||
}
|
||||
|
||||
+ (NASecureData *)randomSecureReadOnlyData:(NSUInteger)length {
|
||||
NASecureData *secureData = [NASecureData secureReadOnlyDataWithLength:length completion:^(void *bytes, NSUInteger length) {
|
||||
randombytes_buf(bytes, length);
|
||||
}];
|
||||
return secureData;
|
||||
}
|
||||
|
||||
@end
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// NAScrypt.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/19/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NAScrypt : NSObject
|
||||
|
||||
/*!
|
||||
Key derivation.
|
||||
|
||||
@param password Password
|
||||
@param salt Must be NAScryptSaltSize
|
||||
|
||||
Default opslimit is crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE.
|
||||
Default memlimit is crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE.
|
||||
*/
|
||||
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt error:(NSError **)error;
|
||||
|
||||
/*!
|
||||
Use the default scrypt. This is for advanced use only.
|
||||
*/
|
||||
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt N:(uint64_t)N r:(uint32_t)r p:(uint32_t)p length:(size_t)length error:(NSError **)error;
|
||||
|
||||
@end
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// NAScrypt.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/19/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NAScrypt.h"
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NAScrypt
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt error:(NSError **)error {
|
||||
if (!salt || [salt length] != NAScryptSaltSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidSalt, @"Invalid salt")
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *key = [NSMutableData dataWithLength:crypto_box_SEEDBYTES];
|
||||
|
||||
int retval = crypto_pwhash_scryptsalsa208sha256([key mutableBytes], key.length, password.bytes, password.length, salt.bytes, crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE, crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);
|
||||
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"Scrypt failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt N:(uint64_t)N r:(uint32_t)r p:(uint32_t)p length:(size_t)length error:(NSError **)error {
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:length];
|
||||
|
||||
int retval = crypto_pwhash_scryptsalsa208sha256_ll((uint8_t *)password.bytes, password.length, (uint8_t *)salt.bytes, salt.length, N, r, p, [outData mutableBytes], outData.length);
|
||||
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"Scrypt failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSAssert([outData length] == length, @"Mismatched output length");
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
@end
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NASecretBox.h
|
||||
// NACL
|
||||
//
|
||||
// Created by Gabriel Handford on 1/16/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/*!
|
||||
Encrypts and authenticates a message using a shared key and nonce.
|
||||
*/
|
||||
@interface NASecretBox : NSObject
|
||||
|
||||
@property (getter=isSecureDataEnabled) BOOL secureDataEnabled;
|
||||
|
||||
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
@end
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// NASecretBox.m
|
||||
// NACL
|
||||
//
|
||||
// Created by Gabriel Handford on 1/16/14.
|
||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NASecretBox.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
#import "NASecureData.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NASecretBox
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error {
|
||||
if (!nonce || [nonce length] != NASecretBoxNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!key || [key length] != NASecretBoxKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Add space for authentication tag of size MACBYTES
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:[data length] + NASecretBoxMACSize];
|
||||
|
||||
int retval = crypto_secretbox_easy([outData mutableBytes],
|
||||
[data bytes], [data length],
|
||||
[nonce bytes],
|
||||
[key bytes]);
|
||||
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"Encrypt (secret box) failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error {
|
||||
if (!nonce || [nonce length] != NASecretBoxNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!key || [key length] != NASecretBoxKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block int retval = -1;
|
||||
NSMutableData *outData = NAData(self.secureDataEnabled, data.length, ^(void *bytes, NSUInteger length) {
|
||||
retval = crypto_secretbox_open_easy(bytes,
|
||||
[data bytes], [data length],
|
||||
[nonce bytes], [key bytes]);
|
||||
});
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Remove MAC bytes from data
|
||||
return [outData na_truncate:NASecretBoxMACSize];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// NASecureData.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/19/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
typedef NS_ENUM (NSInteger, NASecureDataProtection) {
|
||||
NASecureDataProtectionReadWrite = 0, // Default no protection
|
||||
NASecureDataProtectionReadOnly,
|
||||
NASecureDataProtectionNoAccess,
|
||||
};
|
||||
|
||||
/*!
|
||||
Secure memory using libsodium.
|
||||
*/
|
||||
@interface NASecureData : NSMutableData // Subclassing for convienience
|
||||
|
||||
@property (nonatomic) NASecureDataProtection protection;
|
||||
|
||||
/*!
|
||||
Secure and read only data.
|
||||
*/
|
||||
+ (instancetype)secureReadOnlyDataWithLength:(NSUInteger)length completion:(NADataCompletion)completion;
|
||||
|
||||
/*!
|
||||
Secure data is has read/write protection in this block.
|
||||
*/
|
||||
- (void)readWrite:(void (^)(NASecureData *secureData))completion;
|
||||
|
||||
/*!
|
||||
Truncate.
|
||||
*/
|
||||
- (NASecureData *)truncate:(NSUInteger)length;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// Optional building of secure NSData
|
||||
NSMutableData *NAData(BOOL secure, NSUInteger length, NADataCompletion completion);
|
||||
|
||||
|
||||
@interface NSMutableData (NASecureData)
|
||||
|
||||
- (NSData *)na_truncate:(NSUInteger)length;
|
||||
|
||||
@end
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// NASecureData.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/19/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NASecureData.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@interface NASecureData ()
|
||||
@property void *secureBytes;
|
||||
@property NSUInteger secureLength;
|
||||
@end
|
||||
|
||||
@implementation NASecureData
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (instancetype)initWithLength:(NSUInteger)length {
|
||||
if ((self = [super init])) {
|
||||
NAChlorideInit(); // It's already init'ed, but just to be safe
|
||||
_secureLength = length;
|
||||
_secureBytes = sodium_malloc(length);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)secureReadOnlyDataWithLength:(NSUInteger)length completion:(NADataCompletion)completion {
|
||||
NASecureData *secureData = [[NASecureData alloc] initWithLength:length];
|
||||
completion(secureData.secureBytes, secureData.length);
|
||||
secureData.protection = NASecureDataProtectionReadOnly;
|
||||
return secureData;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
sodium_free(_secureBytes);
|
||||
}
|
||||
|
||||
- (void)setProtection:(NASecureDataProtection)protection {
|
||||
switch (protection) {
|
||||
// Keep these case statements order from most secure to least secure in case some jerk removes a break;
|
||||
case NASecureDataProtectionReadWrite: sodium_mprotect_readwrite(_secureBytes); break;
|
||||
case NASecureDataProtectionReadOnly: sodium_mprotect_readonly(_secureBytes); break;
|
||||
case NASecureDataProtectionNoAccess: sodium_mprotect_noaccess(_secureBytes); break;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)length {
|
||||
return _secureLength;
|
||||
}
|
||||
|
||||
- (const void *)bytes {
|
||||
return _secureBytes;
|
||||
}
|
||||
|
||||
- (void *)mutableBytes {
|
||||
return _secureBytes;
|
||||
}
|
||||
|
||||
- (void)readWrite:(void (^)(NASecureData *secureData))completion {
|
||||
NASecureDataProtection protection = self.protection;
|
||||
self.protection = NASecureDataProtectionReadWrite;
|
||||
completion(self);
|
||||
self.protection = protection;
|
||||
}
|
||||
|
||||
- (NASecureData *)truncate:(NSUInteger)length {
|
||||
if (length == 0) return self;
|
||||
return [NASecureData secureReadOnlyDataWithLength:(self.length - length) completion:^(void *bytes, NSUInteger length) {
|
||||
memcpy(bytes, self.bytes, length);
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSData *)na_truncate:(NSUInteger)length { return [self truncate:length]; }
|
||||
|
||||
@end
|
||||
|
||||
NSMutableData *NAData(BOOL secure, NSUInteger length, NADataCompletion completion) {
|
||||
if (!secure) {
|
||||
NSMutableData *data = [NSMutableData dataWithLength:length];
|
||||
completion([data mutableBytes], length);
|
||||
return data;
|
||||
} else {
|
||||
return [NASecureData secureReadOnlyDataWithLength:length completion:completion];
|
||||
}
|
||||
}
|
||||
|
||||
@implementation NSMutableData (NASecureData)
|
||||
|
||||
- (NSData *)na_truncate:(NSUInteger)length {
|
||||
if (length == 0) return self;
|
||||
return [NSData dataWithBytes:self.bytes length:self.length - length];
|
||||
}
|
||||
|
||||
@end
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// NAStream.h
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NAStream : NSObject
|
||||
|
||||
- (NSData *)xor:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error;
|
||||
|
||||
@end
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// NAStream.m
|
||||
// NAChloride
|
||||
//
|
||||
// Created by Gabriel on 6/18/15.
|
||||
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NAStream.h"
|
||||
|
||||
#import "NAInterface.h"
|
||||
|
||||
#import "sodium.h"
|
||||
|
||||
@implementation NAStream
|
||||
|
||||
+ (void)initialize { NAChlorideInit(); }
|
||||
|
||||
- (NSData *)xor:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error {
|
||||
if (!nonce || [nonce length] < NAStreamNonceSize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid stream nonce");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!key || [key length] != NAStreamKeySize) {
|
||||
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid stream key");
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *outData = [NSMutableData dataWithLength:[data length]];
|
||||
|
||||
int retval = crypto_stream_xor([outData mutableBytes], [data bytes], [data length], [nonce bytes], [key bytes]);
|
||||
if (retval != 0) {
|
||||
if (error) *error = NAError(NAErrorCodeFailure, @"Stream failed");
|
||||
return nil;
|
||||
}
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user