- Upgrade to 1.0

This commit is contained in:
giuseppenuc committed 2016-12-28 18:49:02 +01:00
1 parent 4e66c377fd
commit 0c2b3f1c25
452 files changed
+33888 -16806

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014 Gabriel Handford
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+19
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+189
View File
@@ -0,0 +1,189 @@
NAChloride
===========
This project wraps [libsodium](https://github.com/jedisct1/libsodium) for:
* Secure Memory
* Random Data
* Secret-Key
* Authenticated Encryption
* Authentication
* AEAD
* Public-Key
* Authenticated Encryption
* One-Time Authentication
* Password Hashing: *Scrypt*
* Stream Ciphers: *XSalsa20*
More wrappers are coming soon.
Do you want to work on crypto at Keybase? [We're hiring](https://keybase.io/jobs).
If you are looking for other non-libsodium related crypto (that used to be here), see [NACrypto](https://github.com/gabriel/NACrypto).
# Podfile
```ruby
pod "NAChloride"
```
# Init
You should call `NAChlorideInit()` to initialize on app start. It is thread safe and multiple calls are ignored. We automatically call this as well as a safety measure.
```objc
NAChlorideInit();
```
# Secure Memory
See [Securing Memory Allocations](https://download.libsodium.org/doc/helpers/memory_management.html).
```objc
NASecureData *secureData = [NASecureData secureReadOnlyDataWithLength:length completion:^(void *bytes, NSUInteger length) {
// Set the bytes here. After this it will be read-only.
}];
// After the block executes, secureData is read-only. You can set it to no access (or read/write).
// If you set it to no access and secureData.bytes is accessed, it will SIGABRT. For example,
// secureData.protection = NASecureDataProtectionNoAccess;
```
Some classes like NASecretBox, NABox and NAAEAD have an option to enable secureMemory (on decrypt).
NASecureData subclasses NSMutableData for compatibility and usage with other APIs.
# Generating Random Data
See [Generating Random Data](https://download.libsodium.org/doc/generating_random_data/index.html).
```objc
NSData *data = [NARandom randomData:32]; // 32 bytes of random data
NSData *data = [NARandom randomSecureReadOnlyData:32]; // 32 bytes of random, secure, read-only data
```
# Secret-Key Cryptography
## Authenticated Encryption
Encrypts and authenticates a message using a shared key and nonce.
See [Authenticated Encryption](https://download.libsodium.org/doc/secret-key_cryptography/authenticated_encryption.html).
```objc
NSData *key = [NARandom randomData:NASecretBoxKeySize];
NSData *nonce = [NARandom randomData:NASecretBoxNonceSize];
NSData *message = [@"This is a secret message" dataUsingEncoding:NSUTF8StringEncoding];
NASecretBox *secretBox = [[NASecretBox alloc] init];
NSError *error = nil;
NSData *encrypted = [secretBox encrypt:message nonce:nonce key:key error:&error];
// If an error occurred encrypted will be nil and error set
NSData *decrypted = [secretBox decrypt:encrypted nonce:nonce key:key error:&error];
```
## Authentication
See [Authentication](https://download.libsodium.org/doc/secret-key_cryptography/secret-key_authentication.html).
```objc
NSData *key = [NARandom randomData:NAAuthKeySize];
NSData *message = [@"This is a message" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NAAuth *auth = [[NAAuth alloc] init];
NSData *authData = [auth auth:message key:key &error];
BOOL verified = [auth verify:authData data:message key:key error:&error];
```
## AEAD
See [Authenticated Encryption with Additional Data](https://download.libsodium.org/doc/secret-key_cryptography/aead.html).
```objc
NSData *key = [NARandom randomData:NAAEADKeySize];
NSData *nonce = [NARandom randomData:NAAEADNonceSize];
NSData *message = [@"This is a secret message" dataUsingEncoding:NSUTF8StringEncoding];
NSData *additionalData = [@"Additional data" dataUsingEncoding:NSUTF8StringEncoding];
NAAEAD *AEAD = [[NAAEAD alloc] init];
NSError *error = nil;
NSData *encryptedData = [AEAD encryptChaCha20Poly1305:message nonce:nonce key:key additionalData:additionalData error:&error];
NSData *decryptedData = [AEAD decryptChaCha20Poly1305:encryptedData nonce:nonce key:key additionalData:additionalData error:&error];
```
# Public-Key Cryptography
## Authenticated Encryption
See [Authenticated Encryption](https://download.libsodium.org/doc/public-key_cryptography/authenticated_encryption.html).
```objc
NSError *error = nil;
NABoxKeypair *keypair = [NABoxKeypair generate:&error];
NSData *nonce = [NARandom randomData:NABoxNonceSize];
NSData *message = [@"This is a secret message" dataUsingEncoding:NSUTF8StringEncoding];
NABox *box = [[NABox alloc] init];
NSData *encryptedData = [box encrypt:message nonce:nonce keypair:keypair error:&error];
NSData *decryptedData = [box decrypt:encryptedData nonce:nonce keypair:keypair error:&error];
```
# Password Hashing
See [Password Hashing](https://download.libsodium.org/doc/password_hashing/index.html).
```objc
NSData *key = [@"toomanysecrets" dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt = [NARandom randomData:NAScryptSaltSize];
NSError *error = nil;
NSData *data = [NAScrypt scrypt:key salt:salt error:&error];
```
# Advanced
## One-Time Authentication
Generates a MAC for a given message and shared key using Poly1305 algorithm.
Key may NOT be reused across messages.
See [One-Time Authentication](https://download.libsodium.org/doc/advanced/poly1305.html).
```objc
NSData *key = [NARandom randomData:NAOneTimeAuthKeySize];
NSData *message = [@"This is a message" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NAOneTimeAuth *oneTimeAuth = [[NAOneTimeAuth alloc] init];
NSData *auth = [oneTimeAuth auth:message key:key error:&error];
BOOL verified = [oneTimeAuth verify:auth data:message key:key error:&error];
```
## Stream Ciphers
See [XSalsa20](https://download.libsodium.org/doc/advanced/xsalsa20.html).
```objc
NSData *key = [NARandom randomData:NAStreamKeySize];
NSData *nonce = [NARandom randomData:NAStreamNonceSize];
NAStream *stream = [[NAStream alloc] init];
NSError *error = nil;
NSData *encrypted = [stream xor:message nonce:nonce key:key error:&error];
NSData *decrypted = [stream xor:encrypted nonce:nonce key:key error:&error];
```
## Dispatch
There is a helper to dispatch these operations on a queue:
```objc
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NADispatch(queue, ^id(NSError **error) {
return [NAScrypt scrypt:password salt:salt error:error];
}, ^(NSError *error, NSData *data) {
// This is on the main queue.
// Error is set if it failed.
});
```