2014-09-10 01:23:09 +08:00
/* toxencryptsave.c
*
* The Tox encrypted save functions .
*
* Copyright ( C ) 2013 Tox project All Rights Reserved .
*
* This file is part of Tox .
*
* Tox is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Tox is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with Tox . If not , see < http : //www.gnu.org/licenses/>.
*
*/
2014-09-11 07:25:42 +08:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2014-09-10 01:23:09 +08:00
# include "toxencryptsave.h"
2015-02-15 12:00:12 +08:00
# include "defines.h"
2014-09-11 07:12:58 +08:00
# include "../toxcore/crypto_core.h"
2015-02-28 07:42:36 +08:00
# define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}}
2014-09-11 07:12:58 +08:00
# ifdef VANILLA_NACL
# include "crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h"
2014-09-14 11:08:16 +08:00
# include <crypto_hash_sha256.h>
2014-09-11 07:12:58 +08:00
# endif
2014-09-10 01:23:09 +08:00
2015-04-01 07:15:59 +08:00
# if TOX_PASS_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES
# error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES
# endif
2014-10-17 08:59:52 +08:00
2015-04-01 10:16:04 +08:00
# if TOX_PASS_KEY_LENGTH != crypto_box_KEYBYTES
# error TOX_PASS_KEY_LENGTH is assumed to be equal to crypto_box_KEYBYTES
2015-04-01 07:15:59 +08:00
# endif
2014-10-12 16:08:05 +08:00
2015-04-01 07:15:59 +08:00
# if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH)
# error TOX_PASS_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH)
# endif
2014-10-23 17:19:18 +08:00
2016-02-14 12:50:16 +08:00
uint32_t toxes_version_major ( void )
{
return TOXES_VERSION_MAJOR ;
}
uint32_t toxes_version_minor ( void )
{
return TOXES_VERSION_MINOR ;
}
uint32_t toxes_version_patch ( void )
{
return TOXES_VERSION_PATCH ;
}
bool toxes_version_is_compatible ( uint32_t major , uint32_t minor , uint32_t patch )
{
return ( TOXES_VERSION_MAJOR = = major & & /* Force the major version */
( TOXES_VERSION_MINOR > minor | | /* Current minor version must be newer than requested -- or -- */
( TOXES_VERSION_MINOR = = minor & & TOXES_VERSION_PATCH > = patch ) /* the patch must be the same or newer */
)
2016-02-14 12:53:30 +08:00
) ;
2016-02-14 12:50:16 +08:00
}
2015-04-01 07:15:59 +08:00
/* Clients should consider alerting their users that, unlike plain data, if even one bit
2014-09-10 01:23:09 +08:00
* becomes corrupted , the data will be entirely unrecoverable .
* Ditto if they forget their password , there is no way to recover the data .
*/
2014-10-23 17:19:18 +08:00
/* This retrieves the salt used to encrypt the given data, which can then be passed to
* derive_key_with_salt to produce the same key as was previously used . Any encrpyted
* data with this module can be used as input .
*
2015-04-01 07:15:59 +08:00
* returns true if magic number matches
* success does not say anything about the validity of the data , only that data of
* the appropriate size was copied
2014-10-23 17:19:18 +08:00
*/
2015-04-01 07:15:59 +08:00
bool tox_get_salt ( const uint8_t * data , uint8_t * salt )
2014-10-23 17:19:18 +08:00
{
if ( memcmp ( data , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ! = 0 )
2015-04-01 07:15:59 +08:00
return 0 ;
2014-10-24 09:09:02 +08:00
2014-10-23 17:19:18 +08:00
data + = TOX_ENC_SAVE_MAGIC_LENGTH ;
memcpy ( salt , data , crypto_pwhash_scryptsalsa208sha256_SALTBYTES ) ;
2015-04-01 07:15:59 +08:00
return 1 ;
2014-09-10 01:23:09 +08:00
}
2014-10-10 09:16:05 +08:00
/* Generates a secret symmetric key from the given passphrase. out_key must be at least
* TOX_PASS_KEY_LENGTH bytes long .
* Be sure to not compromise the key ! Only keep it in memory , do not write to disk .
* The password is zeroed after key derivation .
* The key should only be used with the other functions in this module , as it
* includes a salt .
2015-04-01 07:15:59 +08:00
* Note that this function is not deterministic ; to derive the same key from a
* password , you also must know the random salt that was used . See below .
2014-09-10 01:23:09 +08:00
*
2015-04-01 07:15:59 +08:00
* returns true on success
2014-09-10 01:23:09 +08:00
*/
2015-05-27 00:57:14 +08:00
bool tox_derive_key_from_pass ( const uint8_t * passphrase , size_t pplength , TOX_PASS_KEY * out_key ,
2015-04-02 07:57:31 +08:00
TOX_ERR_KEY_DERIVATION * error )
2014-10-23 17:19:18 +08:00
{
uint8_t salt [ crypto_pwhash_scryptsalsa208sha256_SALTBYTES ] ;
randombytes ( salt , sizeof salt ) ;
2015-04-01 07:15:59 +08:00
return tox_derive_key_with_salt ( passphrase , pplength , salt , out_key , error ) ;
2014-10-23 17:19:18 +08:00
}
/* Same as above, except with use the given salt for deterministic key derivation.
2015-04-01 08:30:09 +08:00
* The salt must be TOX_PASS_SALT_LENGTH bytes in length .
2014-10-23 17:19:18 +08:00
*/
2015-05-27 00:57:14 +08:00
bool tox_derive_key_with_salt ( const uint8_t * passphrase , size_t pplength , const uint8_t * salt , TOX_PASS_KEY * out_key ,
2015-04-01 07:44:51 +08:00
TOX_ERR_KEY_DERIVATION * error )
2014-09-10 01:23:09 +08:00
{
2015-05-28 07:54:04 +08:00
if ( ! salt | | ! out_key | | ( ! passphrase & & pplength ! = 0 ) ) {
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_KEY_DERIVATION_NULL ) ;
return 0 ;
}
2014-09-14 09:29:33 +08:00
2014-09-14 11:08:16 +08:00
uint8_t passkey [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( passkey , passphrase , pplength ) ;
2014-10-23 17:19:18 +08:00
uint8_t key [ crypto_box_KEYBYTES ] ;
/* Derive a key from the password */
2014-09-10 01:23:09 +08:00
/* 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 (
2015-01-16 10:00:45 +08:00
key , sizeof ( key ) , ( char * ) passkey , sizeof ( passkey ) , salt ,
2014-09-14 09:29:33 +08:00
crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2 , /* slightly stronger */
crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE ) ! = 0 ) {
2014-09-10 01:23:09 +08:00
/* out of memory most likely */
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_KEY_DERIVATION_FAILED ) ;
return 0 ;
2014-09-10 01:23:09 +08:00
}
2014-09-14 09:29:33 +08:00
2014-09-14 11:08:16 +08:00
sodium_memzero ( passkey , crypto_hash_sha256_BYTES ) ; /* wipe plaintext pw */
2015-04-01 10:16:04 +08:00
memcpy ( out_key - > salt , salt , crypto_pwhash_scryptsalsa208sha256_SALTBYTES ) ;
memcpy ( out_key - > key , key , crypto_box_KEYBYTES ) ;
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_KEY_DERIVATION_OK ) ;
return 1 ;
2014-10-10 09:16:05 +08:00
}
2014-09-10 01:23:09 +08:00
2015-04-01 07:15:59 +08:00
/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output
2014-10-10 09:16:05 +08:00
* array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long .
* key must be TOX_PASS_KEY_LENGTH bytes .
* If you already have a symmetric key from somewhere besides this module , simply
* call encrypt_data_symmetric in toxcore / crypto_core directly .
*
2015-04-01 07:15:59 +08:00
* returns true on success
2014-10-10 09:16:05 +08:00
*/
2015-04-01 10:16:04 +08:00
bool tox_pass_key_encrypt ( const uint8_t * data , size_t data_len , const TOX_PASS_KEY * key , uint8_t * out ,
2015-04-01 07:44:51 +08:00
TOX_ERR_ENCRYPTION * error )
2014-10-10 09:16:05 +08:00
{
2015-04-01 07:15:59 +08:00
if ( data_len = = 0 | | ! data | | ! key | | ! out ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_ENCRYPTION_NULL ) ;
return 0 ;
}
2014-09-12 08:29:18 +08:00
/* the output data consists of, in order:
2014-10-09 07:14:23 +08:00
* salt , nonce , mac , enc_data
2014-09-10 01:23:09 +08:00
* where the mac is automatically prepended by the encrypt ( )
2014-10-09 07:14:23 +08:00
* the salt + nonce is called the prefix
2014-09-10 01:23:09 +08:00
* I ' m not sure what else I ' m supposed to do with the salt and nonce , since we
* need them to decrypt the data
*/
2014-10-23 17:19:18 +08:00
/* first add the magic number */
memcpy ( out , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ;
out + = TOX_ENC_SAVE_MAGIC_LENGTH ;
2014-09-10 01:23:09 +08:00
2014-10-23 17:19:18 +08:00
/* then add the rest prefix */
2015-04-01 10:16:04 +08:00
memcpy ( out , key - > salt , crypto_pwhash_scryptsalsa208sha256_SALTBYTES ) ;
2014-10-09 07:14:23 +08:00
out + = crypto_pwhash_scryptsalsa208sha256_SALTBYTES ;
2014-10-23 17:19:18 +08:00
uint8_t nonce [ crypto_box_NONCEBYTES ] ;
random_nonce ( nonce ) ;
2014-10-09 07:14:23 +08:00
memcpy ( out , nonce , crypto_box_NONCEBYTES ) ;
out + = crypto_box_NONCEBYTES ;
2014-09-12 08:29:18 +08:00
/* now encrypt */
2015-04-01 10:16:04 +08:00
if ( encrypt_data_symmetric ( key - > key , nonce , data , data_len , out )
2014-10-09 07:14:23 +08:00
! = data_len + crypto_box_MACBYTES ) {
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_ENCRYPTION_FAILED ) ;
return 0 ;
2014-09-10 01:23:09 +08:00
}
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_ENCRYPTION_OK ) ;
return 1 ;
2014-09-10 01:23:09 +08:00
}
2014-10-10 09:16:05 +08:00
/* Encrypts the given data with the given passphrase. The output array must be
* at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long . This delegates
* to tox_derive_key_from_pass and tox_pass_key_encrypt .
2014-09-10 01:23:09 +08:00
*
2015-04-01 07:15:59 +08:00
* returns true on success
2014-09-10 01:23:09 +08:00
*/
2015-05-27 00:57:14 +08:00
bool tox_pass_encrypt ( const uint8_t * data , size_t data_len , const uint8_t * passphrase , size_t pplength , uint8_t * out ,
2015-04-01 07:44:51 +08:00
TOX_ERR_ENCRYPTION * error )
2014-09-10 01:23:09 +08:00
{
2015-04-01 10:16:04 +08:00
TOX_PASS_KEY key ;
2015-04-01 07:15:59 +08:00
TOX_ERR_KEY_DERIVATION _error ;
2014-09-12 08:29:18 +08:00
2015-04-01 10:16:04 +08:00
if ( ! tox_derive_key_from_pass ( passphrase , pplength , & key , & _error ) ) {
2015-04-01 07:15:59 +08:00
if ( _error = = TOX_ERR_KEY_DERIVATION_NULL ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_ENCRYPTION_NULL ) ;
} else if ( _error = = TOX_ERR_KEY_DERIVATION_FAILED ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED ) ;
}
2014-10-10 09:16:05 +08:00
2015-04-01 07:15:59 +08:00
return 0 ;
}
2014-10-17 19:02:15 +08:00
2015-04-01 10:16:04 +08:00
return tox_pass_key_encrypt ( data , data_len , & key , out , error ) ;
2014-10-17 19:02:15 +08:00
}
2014-10-10 09:16:05 +08:00
/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by
* tox_derive_key_from_pass .
2014-10-09 07:14:23 +08:00
*
2015-04-01 07:15:59 +08:00
* the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH
*
* returns true on success
2014-10-09 07:14:23 +08:00
*/
2015-04-01 10:16:04 +08:00
bool tox_pass_key_decrypt ( const uint8_t * data , size_t length , const TOX_PASS_KEY * key , uint8_t * out ,
2015-04-01 07:44:51 +08:00
TOX_ERR_DECRYPTION * error )
2014-10-09 07:14:23 +08:00
{
2015-04-01 07:15:59 +08:00
if ( length < = TOX_PASS_ENCRYPTION_EXTRA_LENGTH ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_INVALID_LENGTH ) ;
return 0 ;
}
2015-04-01 07:44:51 +08:00
2015-04-01 10:16:04 +08:00
if ( ! data | | ! key | | ! out ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_NULL ) ;
return 0 ;
}
2015-04-02 07:57:31 +08:00
2015-04-01 07:15:59 +08:00
if ( memcmp ( data , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ! = 0 ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_BAD_FORMAT ) ;
return 0 ;
}
2014-10-09 07:14:23 +08:00
2014-10-23 17:19:18 +08:00
data + = TOX_ENC_SAVE_MAGIC_LENGTH ;
2015-04-01 10:16:04 +08:00
data + = crypto_pwhash_scryptsalsa208sha256_SALTBYTES ; // salt only affects key derivation
2014-10-09 07:14:23 +08:00
2015-04-01 07:15:59 +08:00
size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH ;
2014-09-14 09:29:33 +08:00
2015-04-01 10:16:04 +08:00
uint8_t nonce [ crypto_box_NONCEBYTES ] ;
2014-09-12 08:29:18 +08:00
memcpy ( nonce , data , crypto_box_NONCEBYTES ) ;
data + = crypto_box_NONCEBYTES ;
2014-09-14 09:29:33 +08:00
2014-10-10 09:16:05 +08:00
/* decrypt the data */
2015-04-01 10:16:04 +08:00
if ( decrypt_data_symmetric ( key - > key , nonce , data , decrypt_length + crypto_box_MACBYTES , out )
2014-10-10 09:16:05 +08:00
! = decrypt_length ) {
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_FAILED ) ;
return 0 ;
2014-10-10 09:16:05 +08:00
}
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_OK ) ;
return 1 ;
2014-10-10 09:16:05 +08:00
}
/* Decrypts the given data with the given passphrase. The output array must be
2015-04-01 07:15:59 +08:00
* at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long . This delegates
* to tox_pass_key_decrypt .
*
* the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH
2014-10-10 09:16:05 +08:00
*
2015-04-01 07:15:59 +08:00
* returns true on success
2014-10-10 09:16:05 +08:00
*/
2015-05-27 00:57:14 +08:00
bool tox_pass_decrypt ( const uint8_t * data , size_t length , const uint8_t * passphrase , size_t pplength , uint8_t * out ,
2015-04-01 07:44:51 +08:00
TOX_ERR_DECRYPTION * error )
2014-10-10 09:16:05 +08:00
{
2015-05-28 07:54:04 +08:00
if ( length < = TOX_PASS_ENCRYPTION_EXTRA_LENGTH ) {
2015-04-01 08:30:09 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_INVALID_LENGTH ) ;
return 0 ;
}
2015-04-02 07:57:31 +08:00
2015-04-01 08:30:09 +08:00
if ( ! data | | ! passphrase | | ! out ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_NULL ) ;
return 0 ;
}
2015-04-02 07:57:31 +08:00
2015-04-01 07:15:59 +08:00
if ( memcmp ( data , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ! = 0 ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_BAD_FORMAT ) ;
return 0 ;
}
2014-10-10 09:16:05 +08:00
uint8_t salt [ crypto_pwhash_scryptsalsa208sha256_SALTBYTES ] ;
2014-10-24 09:09:02 +08:00
memcpy ( salt , data + TOX_ENC_SAVE_MAGIC_LENGTH , crypto_pwhash_scryptsalsa208sha256_SALTBYTES ) ;
2014-09-14 09:29:33 +08:00
2014-09-10 01:23:09 +08:00
/* derive the key */
2015-04-01 10:16:04 +08:00
TOX_PASS_KEY key ;
2014-09-14 09:29:33 +08:00
2015-04-01 10:16:04 +08:00
if ( ! tox_derive_key_with_salt ( passphrase , pplength , salt , & key , NULL ) ) {
2014-09-10 01:23:09 +08:00
/* out of memory most likely */
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED ) ;
return 0 ;
2014-09-10 01:23:09 +08:00
}
2014-09-14 09:29:33 +08:00
2015-04-01 10:16:04 +08:00
return tox_pass_key_decrypt ( data , length , & key , out , error ) ;
2014-10-17 19:02:15 +08:00
}
2014-09-12 08:29:18 +08:00
/* Determines whether or not the given data is encrypted (by checking the magic number)
*/
2015-04-01 07:15:59 +08:00
bool tox_is_data_encrypted ( const uint8_t * data )
2014-09-12 08:29:18 +08:00
{
if ( memcmp ( data , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) = = 0 )
return 1 ;
else
return 0 ;
}