Skip to content
This repository has been archived by the owner on May 25, 2019. It is now read-only.

Commit

Permalink
add: reimplementation of toxencryptsave
Browse files Browse the repository at this point in the history
  • Loading branch information
kpp committed Feb 10, 2016
1 parent 14c932e commit 97b2c47
Show file tree
Hide file tree
Showing 13 changed files with 481 additions and 255 deletions.
8 changes: 7 additions & 1 deletion toxencryptsave/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
add_library(toxencryptsave toxencryptsave.cpp)
add_library(toxencryptsave
constants.cpp
key.cpp
reader.cpp
writer.cpp
toxencryptsave.cpp
)
target_link_libraries(toxencryptsave toxcore ${SODIUM_LIBRARIES})
21 changes: 21 additions & 0 deletions toxencryptsave/constants.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "constants.hpp"

#include <sodium.h>

const char* toxencryptsave::constants::magic = TOXENCRYPTSAVE_MAGIC_NUMBER;

#if TOXENCRYPTSAVE_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES
#error TOXENCRYPTSAVE_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES
#endif

#if TOXENCRYPTSAVE_KEY_LENGTH != crypto_box_BEFORENMBYTES
#error TOXENCRYPTSAVE_KEY_LENGTH is assumed to be equal to crypto_box_BEFORENMBYTES
#endif

#if TOXENCRYPTSAVE_NONCEBYTES != crypto_box_NONCEBYTES
#error TOXENCRYPTSAVE_NONCEBYTES is assumed to be equal to crypto_box_NONCEBYTES
#endif

#if TOXENCRYPTSAVE_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + TOXENCRYPTSAVE_NONCEBYTES + TOXENCRYPTSAVE_SALT_LENGTH + TOXENCRYPTSAVE_MAGIC_LENGTH)
#error TOXENCRYPTSAVE_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + TOXENCRYPTSAVE_NONCEBYTES + TOXENCRYPTSAVE_SALT_LENGTH + TOXENCRYPTSAVE_MAGIC_LENGTH)
#endif
31 changes: 31 additions & 0 deletions toxencryptsave/constants.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef TOXENCRYPTSAVE_CONSTANTS_H
#define TOXENCRYPTSAVE_CONSTANTS_H

#include <stddef.h>
#include <stdint.h>

// hardcoded constants
// if they change, userdata will be lost

#define TOXENCRYPTSAVE_MAGIC_NUMBER "toxEsave"
#define TOXENCRYPTSAVE_MAGIC_LENGTH 8U

#define TOXENCRYPTSAVE_SALT_LENGTH 32U
#define TOXENCRYPTSAVE_KEY_LENGTH 32U
#define TOXENCRYPTSAVE_NONCEBYTES 24U
#define TOXENCRYPTSAVE_ENCRYPTION_EXTRA_LENGTH 80U

namespace toxencryptsave
{
namespace constants
{
extern const char* magic;
static const size_t magic_len = TOXENCRYPTSAVE_MAGIC_LENGTH;
static const size_t salt_len = TOXENCRYPTSAVE_SALT_LENGTH;
static const size_t nonce_len = TOXENCRYPTSAVE_NONCEBYTES;
static const size_t pass_hash_len = TOXENCRYPTSAVE_KEY_LENGTH;
static const size_t encrypted_overhead = TOXENCRYPTSAVE_ENCRYPTION_EXTRA_LENGTH;
}
}

#endif
43 changes: 43 additions & 0 deletions toxencryptsave/data_description.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef TOXENCRYPTSAVE_DATA_DESCRIPTION_H
#define TOXENCRYPTSAVE_DATA_DESCRIPTION_H

#include "constants.hpp"

namespace toxencryptsave
{

namespace offsets
{
static const size_t base = 0;
static const size_t magic = base;
static const size_t salt = magic + constants::magic_len;
static const size_t nonce = salt + constants::salt_len;
static const size_t crypted_raw = nonce + constants::nonce_len;
};

template<class PointerT>
struct Data_Description /* encryptsave data offsets + length */
{
PointerT const base; // 0 offset from the given pointer to data
PointerT const magic;
PointerT const salt;
PointerT const nonce;
PointerT const crypted_raw;

explicit Data_Description(PointerT const data):
base( data + offsets::base ),
magic( data + offsets::magic ),
salt( data + offsets::salt ),
nonce( data + offsets::nonce ),
crypted_raw( data + offsets::crypted_raw )
{}

private:
Data_Description(); // = delete
Data_Description(const Data_Description&); // = delete
Data_Description& operator= (const Data_Description&); // = delete
};

}

#endif
64 changes: 64 additions & 0 deletions toxencryptsave/error_status.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#ifndef TOXENCRYPTSAVE_ERROR_STATUS_H
#define TOXENCRYPTSAVE_ERROR_STATUS_H

typedef enum TOX_ERR_KEY_DERIVATION {
TOX_ERR_KEY_DERIVATION_OK,
/**
* Some input data, or maybe the output pointer, was null.
*/
TOX_ERR_KEY_DERIVATION_NULL,
/**
* The crypto lib was unable to derive a key from the given passphrase,
* which is usually a lack of memory issue. The functions accepting keys
* do not produce this error.
*/
TOX_ERR_KEY_DERIVATION_FAILED
} TOX_ERR_KEY_DERIVATION;

typedef enum TOX_ERR_ENCRYPTION {
TOX_ERR_ENCRYPTION_OK,
/**
* Some input data, or maybe the output pointer, was null.
*/
TOX_ERR_ENCRYPTION_NULL,
/**
* The crypto lib was unable to derive a key from the given passphrase,
* which is usually a lack of memory issue. The functions accepting keys
* do not produce this error.
*/
TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED,
/**
* The encryption itself failed.
*/
TOX_ERR_ENCRYPTION_FAILED
} TOX_ERR_ENCRYPTION;

typedef enum TOX_ERR_DECRYPTION {
TOX_ERR_DECRYPTION_OK,
/**
* Some input data, or maybe the output pointer, was null.
*/
TOX_ERR_DECRYPTION_NULL,
/**
* The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes
*/
TOX_ERR_DECRYPTION_INVALID_LENGTH,
/**
* The input data is missing the magic number (i.e. wasn't created by this
* module, or is corrupted)
*/
TOX_ERR_DECRYPTION_BAD_FORMAT,
/**
* The crypto lib was unable to derive a key from the given passphrase,
* which is usually a lack of memory issue. The functions accepting keys
* do not produce this error.
*/
TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED,
/**
* The encrypted byte array could not be decrypted. Either the data was
* corrupt or the password/key was incorrect.
*/
TOX_ERR_DECRYPTION_FAILED
} TOX_ERR_DECRYPTION;

#endif
45 changes: 45 additions & 0 deletions toxencryptsave/key.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "key.hpp"

#include <sodium.h>
#include <string.h>

#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}}

bool TOX_PASS_KEY::derive_from_pass_with_salt(uint8_t* passphrase, size_t pplength, const uint8_t* new_salt, TOX_ERR_KEY_DERIVATION* error)
{
if (!new_salt || (!passphrase && pplength != 0)) {
SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL);
return false;
}

uint8_t passkey[toxencryptsave::constants::pass_hash_len];
crypto_hash_sha256(passkey, passphrase, pplength);
sodium_memzero(passphrase, pplength); /* wipe plaintext pw */
memmove(salt, new_salt, toxencryptsave::constants::salt_len);

/* Derive a key from the password */
/* http://doc.libsodium.org/key_derivation/README.html */
/* note that, according to the documentation, a generic pwhash interface will be created
* once the pwhash competition (https://password-hashing.net/) is over */
if (crypto_pwhash_scryptsalsa208sha256(
key, toxencryptsave::constants::pass_hash_len,
reinterpret_cast<char*>(passkey), sizeof(passkey),
salt,
crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */
crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) {
/* out of memory most likely */
SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED);
return false;
}

SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK);
return true;
}

bool TOX_PASS_KEY::derive_from_pass_with_random_salt(uint8_t* passphrase, size_t pplength, TOX_ERR_KEY_DERIVATION* error)
{
uint8_t salt[toxencryptsave::constants::salt_len];
randombytes(salt, sizeof salt);
return this->derive_from_pass_with_salt(passphrase, pplength, salt, error);
}

20 changes: 20 additions & 0 deletions toxencryptsave/key.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef TOXENCRYPTSAVE_KEY_H
#define TOXENCRYPTSAVE_KEY_H

#include "constants.hpp"
#include "error_status.hpp"

/* This key structure's internals should not be used by any client program, even
* if they are straightforward here.
*/

struct TOX_PASS_KEY
{
uint8_t salt[TOXENCRYPTSAVE_SALT_LENGTH];
uint8_t key[TOXENCRYPTSAVE_KEY_LENGTH];

bool derive_from_pass_with_salt(uint8_t* passphrase, size_t pplength, const uint8_t* salt, TOX_ERR_KEY_DERIVATION* error);
bool derive_from_pass_with_random_salt(uint8_t* passphrase, size_t pplength, TOX_ERR_KEY_DERIVATION* error);
};

#endif
95 changes: 95 additions & 0 deletions toxencryptsave/reader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "reader.hpp"

#include <sodium.h>
#include <string.h>

#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}}

#include <toxcore/crypto_core.hpp>

namespace toxencryptsave
{

bool Reader::magic_is_valid() const {
if (!ro_data.base)
return false;

return sodium_memcmp(ro_data.magic, constants::magic, constants::magic_len) == 0;
}

bool Reader::extract_salt_into(uint8_t*const out_salt) const {
if (!this->magic_is_valid() || !out_salt)
return false;

memcpy(out_salt, ro_data.salt, constants::salt_len);
return true;
}

bool Reader::extract_key_into(uint8_t* passphrase, size_t pplength, TOX_PASS_KEY* out_key, TOX_ERR_KEY_DERIVATION* error) const
{
if (!ro_data.base || !out_key || (!passphrase && pplength != 0)) {
SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL);
return false;
}

if ( !this->extract_salt_into(out_key->salt) ) {
SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED);
return false;
}

return out_key->derive_from_pass_with_salt(passphrase, pplength, out_key->salt, error);
}

bool Reader::decrypt_by_key(size_t data_length, const TOX_PASS_KEY* key, uint8_t* out, TOX_ERR_DECRYPTION* error) const
{
if (data_length <= constants::encrypted_overhead) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);
return false;
}

if (!ro_data.base || !key || !out) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL);
return false;
}

if (!this->magic_is_valid()) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT);
return false;
}

size_t decrypt_expected_length = data_length - constants::encrypted_overhead;
int decrypted_result = decrypt_data_symmetric(key->key, ro_data.nonce, ro_data.crypted_raw, decrypt_expected_length + crypto_box_MACBYTES, out);

if (decrypted_result == -1) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED);
return false;
}

SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK);
return true;
}

bool Reader::decrypt_by_passphrase(size_t data_length, uint8_t* passphrase, size_t pplength, uint8_t* out, TOX_ERR_DECRYPTION* error) const
{
if (!ro_data.base) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL);
return false;
}

if ( !this->magic_is_valid() ) {
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT);
return false;
}

/* extract the key */
TOX_PASS_KEY key;
if ( !this->extract_key_into(passphrase, pplength, &key, NULL)) {
/* out of memory most likely */
SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED);
return false;
}

return this->decrypt_by_key(data_length, &key, out, error);
}

}
34 changes: 34 additions & 0 deletions toxencryptsave/reader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef TOXENCRYPTSAVE_READER_H
#define TOXENCRYPTSAVE_READER_H

#include "data_description.hpp"
#include "key.hpp"

namespace toxencryptsave
{

struct Reader
{
Data_Description<const uint8_t*> const ro_data;

explicit Reader(const uint8_t* const raw_encryptsave_data):
ro_data( raw_encryptsave_data )
{}

bool magic_is_valid() const;

bool extract_salt_into(uint8_t* const out_salt) const;
bool extract_key_into(uint8_t* const passphrase, size_t pplength, TOX_PASS_KEY* const out_key, TOX_ERR_KEY_DERIVATION* error) const;

bool decrypt_by_key(size_t data_length, const TOX_PASS_KEY* key, uint8_t* out, TOX_ERR_DECRYPTION* error) const;
bool decrypt_by_passphrase(size_t data_length, uint8_t* passphrase, size_t pplength, uint8_t* out, TOX_ERR_DECRYPTION* error) const;

private:
Reader(); // = delete
Reader(const Reader&); // = delete
Reader& operator= (const Reader&); // = delete
};

}

#endif
Loading

0 comments on commit 97b2c47

Please sign in to comment.