2020-03-12 09:10:33 +08:00
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2016 - 2018 The TokTok team .
* Copyright © 2013 Tox project .
2017-01-14 23:46:31 +08:00
*/
/*
2020-03-12 09:10:33 +08:00
* Batch encryption functions .
2014-09-10 01:23:09 +08:00
*/
2014-09-11 07:25:42 +08:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2018-01-29 05:30:39 +08:00
# include "../toxcore/ccompat.h"
2014-09-11 07:12:58 +08:00
# include "../toxcore/crypto_core.h"
2016-09-01 07:33:20 +08:00
# include "defines.h"
# include "toxencryptsave.h"
2018-07-05 18:31:29 +08:00
# define SET_ERROR_PARAMETER(param, x) do { if (param) { *param = x; } } while (0)
2014-09-11 07:12:58 +08:00
# ifdef VANILLA_NACL
2017-01-06 03:05:10 +08:00
# include <crypto_box.h>
2014-09-14 11:08:16 +08:00
# include <crypto_hash_sha256.h>
2016-09-01 07:33:20 +08:00
# include "crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h"
2017-01-06 03:05:10 +08:00
# define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
2016-12-19 23:27:46 +08:00
# else
2016-12-19 10:47:42 +08:00
# include <sodium.h>
2016-12-19 23:27:46 +08:00
# endif
2018-02-27 10:07:59 +08:00
# include <stdlib.h>
2016-12-19 23:27:46 +08:00
# include <string.h>
2014-09-10 01:23:09 +08:00
2021-12-07 02:41:27 +08:00
//!TOKSTYLE-
static_assert ( TOX_PASS_SALT_LENGTH = = crypto_pwhash_scryptsalsa208sha256_SALTBYTES ,
" TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES " ) ;
static_assert ( TOX_PASS_KEY_LENGTH = = CRYPTO_SHARED_KEY_SIZE ,
" TOX_PASS_KEY_LENGTH is assumed to be equal to CRYPTO_SHARED_KEY_SIZE " ) ;
static_assert ( TOX_PASS_ENCRYPTION_EXTRA_LENGTH = = ( crypto_box_MACBYTES + crypto_box_NONCEBYTES +
crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH ) ,
" 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) " ) ;
//!TOKSTYLE+
2014-10-23 17:19:18 +08:00
2017-03-31 04:18:00 +08:00
uint32_t tox_pass_salt_length ( void )
{
return TOX_PASS_SALT_LENGTH ;
}
uint32_t tox_pass_key_length ( void )
{
return TOX_PASS_KEY_LENGTH ;
}
uint32_t tox_pass_encryption_extra_length ( void )
{
return TOX_PASS_ENCRYPTION_EXTRA_LENGTH ;
}
2016-12-10 19:21:22 +08:00
struct Tox_Pass_Key {
uint8_t salt [ TOX_PASS_SALT_LENGTH ] ;
uint8_t key [ TOX_PASS_KEY_LENGTH ] ;
} ;
void tox_pass_key_free ( Tox_Pass_Key * pass_key )
{
free ( pass_key ) ;
}
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
2016-12-10 19:21:22 +08:00
* tox_pass_key_derive_with_salt to produce the same key as was previously used . Any encrpyted
2014-10-23 17:19:18 +08:00
* 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
*/
2018-10-09 05:05:14 +08:00
bool tox_get_salt ( const uint8_t * data , uint8_t * salt , Tox_Err_Get_Salt * error )
2014-10-23 17:19:18 +08:00
{
2016-12-10 19:21:22 +08:00
if ( ! data | | ! salt ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_GET_SALT_NULL ) ;
return false ;
}
2016-09-01 02:12:19 +08:00
if ( memcmp ( data , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ! = 0 ) {
2016-12-10 19:21:22 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_GET_SALT_BAD_FORMAT ) ;
return false ;
2016-09-01 02:12:19 +08:00
}
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 ) ;
2016-12-10 19:21:22 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_GET_SALT_OK ) ;
return true ;
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
*/
2016-12-16 11:00:55 +08:00
Tox_Pass_Key * tox_pass_key_derive ( const uint8_t * passphrase , size_t pplength ,
2018-10-09 05:05:14 +08:00
Tox_Err_Key_Derivation * error )
2014-10-23 17:19:18 +08:00
{
uint8_t salt [ crypto_pwhash_scryptsalsa208sha256_SALTBYTES ] ;
2021-12-07 02:41:27 +08:00
random_bytes ( salt , sizeof ( salt ) ) ;
2016-12-16 11:00:55 +08:00
return tox_pass_key_derive_with_salt ( passphrase , pplength , salt , 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
*/
2016-12-16 11:00:55 +08:00
Tox_Pass_Key * tox_pass_key_derive_with_salt ( const uint8_t * passphrase , size_t pplength ,
2018-10-09 05:05:14 +08:00
const uint8_t * salt , Tox_Err_Key_Derivation * error )
2014-09-10 01:23:09 +08:00
{
2016-12-16 11:00:55 +08:00
if ( ! salt | | ( ! passphrase & & pplength ! = 0 ) ) {
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_KEY_DERIVATION_NULL ) ;
2018-01-29 05:30:39 +08:00
return nullptr ;
2015-04-01 07:15:59 +08:00
}
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
2016-12-19 10:47:42 +08:00
uint8_t key [ CRYPTO_SHARED_KEY_SIZE ] ;
2014-10-23 17:19:18 +08:00
2021-12-07 02:41:27 +08:00
// 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 */
2014-09-10 01:23:09 +08:00
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 ) ;
2018-01-29 05:30:39 +08:00
return nullptr ;
2014-09-10 01:23:09 +08:00
}
2014-09-14 09:29:33 +08:00
2018-06-26 01:26:05 +08:00
crypto_memzero ( passkey , crypto_hash_sha256_BYTES ) ; /* wipe plaintext pw */
2016-12-16 11:00:55 +08:00
Tox_Pass_Key * out_key = ( Tox_Pass_Key * ) malloc ( sizeof ( Tox_Pass_Key ) ) ;
if ( ! out_key ) {
SET_ERROR_PARAMETER ( error , TOX_ERR_KEY_DERIVATION_FAILED ) ;
2018-01-29 05:30:39 +08:00
return nullptr ;
2016-12-16 11:00:55 +08:00
}
2015-04-01 10:16:04 +08:00
memcpy ( out_key - > salt , salt , crypto_pwhash_scryptsalsa208sha256_SALTBYTES ) ;
2016-12-19 10:47:42 +08:00
memcpy ( out_key - > key , key , CRYPTO_SHARED_KEY_SIZE ) ;
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_KEY_DERIVATION_OK ) ;
2016-12-16 11:00:55 +08:00
return out_key ;
2014-10-10 09:16:05 +08:00
}
2014-09-10 01:23:09 +08:00
2021-12-07 02:41:27 +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
*/
2016-12-10 19:21:22 +08:00
bool tox_pass_key_encrypt ( const Tox_Pass_Key * key , const uint8_t * data , size_t data_len , uint8_t * out ,
2018-10-09 05:05:14 +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 ;
}
2021-12-07 02:41:27 +08:00
// the output data consists of, in order:
// salt, nonce, mac, enc_data
// where the mac is automatically prepended by the encrypt()
// the salt+nonce is called the prefix
// 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-09-10 01:23:09 +08:00
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
2016-12-10 19:21:22 +08:00
* to tox_derive_key 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 ,
2018-10-09 05:05:14 +08:00
Tox_Err_Encryption * error )
2014-09-10 01:23:09 +08:00
{
2021-12-07 02:41:27 +08:00
Tox_Err_Key_Derivation err ;
Tox_Pass_Key * key = tox_pass_key_derive ( passphrase , pplength , & err ) ;
2014-09-12 08:29:18 +08:00
2016-12-16 11:00:55 +08:00
if ( ! key ) {
2021-12-07 02:41:27 +08:00
if ( err = = TOX_ERR_KEY_DERIVATION_NULL ) {
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_ENCRYPTION_NULL ) ;
2021-12-07 02:41:27 +08:00
} else if ( err = = TOX_ERR_KEY_DERIVATION_FAILED ) {
2015-04-01 07:15:59 +08:00
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
2016-12-16 11:00:55 +08:00
bool result = tox_pass_key_encrypt ( key , data , data_len , out , error ) ;
tox_pass_key_free ( key ) ;
return result ;
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
2016-12-10 19:21:22 +08:00
* tox_derive_key .
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
*/
2016-12-10 19:21:22 +08:00
bool tox_pass_key_decrypt ( const Tox_Pass_Key * key , const uint8_t * data , size_t length , uint8_t * out ,
2018-10-09 05:05:14 +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 ,
2018-10-09 05:05:14 +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 */
2018-01-29 05:30:39 +08:00
Tox_Pass_Key * key = tox_pass_key_derive_with_salt ( passphrase , pplength , salt , nullptr ) ;
2014-09-14 09:29:33 +08:00
2016-12-16 11:00:55 +08:00
if ( ! key ) {
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
2016-12-16 11:00:55 +08:00
bool result = tox_pass_key_decrypt ( key , data , length , out , error ) ;
tox_pass_key_free ( key ) ;
return result ;
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
{
2016-09-01 02:12:19 +08:00
if ( memcmp ( data , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) = = 0 ) {
2014-09-12 08:29:18 +08:00
return 1 ;
2016-09-01 02:12:19 +08:00
}
2016-09-01 03:40:20 +08:00
return 0 ;
2014-09-12 08:29:18 +08:00
}