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
*/
2022-02-05 07:19:58 +08:00
/**
2020-03-12 09:10:33 +08:00
* Batch encryption functions .
2014-09-10 01:23:09 +08:00
*/
2016-09-01 07:33:20 +08:00
# include "toxencryptsave.h"
2014-09-11 07:12:58 +08:00
2016-12-19 10:47:42 +08:00
# include <sodium.h>
2016-12-19 23:27:46 +08:00
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
2022-01-18 01:12:05 +08:00
# include "../toxcore/ccompat.h"
# include "../toxcore/crypto_core.h"
# include "defines.h"
2021-12-07 02:41:27 +08:00
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) " ) ;
2014-10-23 17:19:18 +08:00
2021-12-10 05:13:49 +08:00
# define SET_ERROR_PARAMETER(param, x) \
do { \
2022-02-18 02:34:39 +08:00
if ( param ! = nullptr ) { \
2021-12-10 05:13:49 +08:00
* param = x ; \
} \
} while ( 0 )
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 ] ;
} ;
2022-02-21 21:24:00 +08:00
void tox_pass_key_free ( Tox_Pass_Key * key )
2016-12-10 19:21:22 +08:00
{
2022-02-21 21:24:00 +08:00
free ( key ) ;
2016-12-10 19:21:22 +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
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
*/
2022-02-21 21:24:00 +08:00
bool tox_get_salt ( const uint8_t * ciphertext , uint8_t * salt , Tox_Err_Get_Salt * error )
2014-10-23 17:19:18 +08:00
{
2022-02-21 21:24:00 +08:00
if ( ciphertext = = nullptr | | salt = = nullptr ) {
2016-12-10 19:21:22 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_GET_SALT_NULL ) ;
return false ;
}
2022-02-21 21:24:00 +08:00
if ( memcmp ( ciphertext , 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
2022-02-21 21:24:00 +08:00
ciphertext + = TOX_ENC_SAVE_MAGIC_LENGTH ;
memcpy ( salt , ciphertext , 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
*/
2022-02-21 21:24:00 +08:00
Tox_Pass_Key * tox_pass_key_derive ( const uint8_t * passphrase , size_t passphrase_len ,
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 ) ) ;
2022-02-21 21:24:00 +08:00
return tox_pass_key_derive_with_salt ( passphrase , passphrase_len , 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
*/
2022-02-21 21:24:00 +08:00
Tox_Pass_Key * tox_pass_key_derive_with_salt ( const uint8_t * passphrase , size_t passphrase_len ,
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
{
2022-02-21 21:24:00 +08:00
if ( salt = = nullptr | | ( passphrase = = nullptr & & passphrase_len ! = 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 ] ;
2022-02-21 21:24:00 +08:00
crypto_hash_sha256 ( passkey , passphrase , passphrase_len ) ;
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
2022-01-10 06:38:57 +08:00
Tox_Pass_Key * out_key = ( Tox_Pass_Key * ) calloc ( 1 , sizeof ( Tox_Pass_Key ) ) ;
2016-12-16 11:00:55 +08:00
2022-02-18 10:05:44 +08:00
if ( out_key = = nullptr ) {
2016-12-16 11:00:55 +08:00
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
/**
2021-12-22 01:54:02 +08:00
* Encrypt a plain text with a key produced by tox_pass_key_derive or tox_pass_key_derive_with_salt .
2014-10-10 09:16:05 +08:00
*
2021-12-22 01:54:02 +08:00
* The output array must be at least ` plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH `
* bytes long .
*
* @ param plaintext A byte array of length ` plaintext_len ` .
* @ param plaintext_len The length of the plain text array . Bigger than 0.
* @ param ciphertext The cipher text array to write the encrypted data to .
*
* @ return true on success .
2014-10-10 09:16:05 +08:00
*/
2021-12-22 01:54:02 +08:00
bool tox_pass_key_encrypt ( const Tox_Pass_Key * key , const uint8_t * plaintext , size_t plaintext_len ,
uint8_t * ciphertext , Tox_Err_Encryption * error )
2014-10-10 09:16:05 +08:00
{
2022-02-21 22:10:31 +08:00
if ( plaintext_len = = 0 | | plaintext = = nullptr | | key = = nullptr | | ciphertext = = nullptr ) {
2015-04-01 07:15:59 +08:00
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 */
2021-12-22 01:54:02 +08:00
memcpy ( ciphertext , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ;
ciphertext + = 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 */
2021-12-22 01:54:02 +08:00
memcpy ( ciphertext , key - > salt , crypto_pwhash_scryptsalsa208sha256_SALTBYTES ) ;
ciphertext + = crypto_pwhash_scryptsalsa208sha256_SALTBYTES ;
2014-10-23 17:19:18 +08:00
uint8_t nonce [ crypto_box_NONCEBYTES ] ;
random_nonce ( nonce ) ;
2021-12-22 01:54:02 +08:00
memcpy ( ciphertext , nonce , crypto_box_NONCEBYTES ) ;
ciphertext + = crypto_box_NONCEBYTES ;
2014-09-12 08:29:18 +08:00
/* now encrypt */
2021-12-22 01:54:02 +08:00
if ( encrypt_data_symmetric ( key - > key , nonce , plaintext , plaintext_len , ciphertext )
! = plaintext_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
*/
2022-02-21 21:24:00 +08:00
bool tox_pass_encrypt ( const uint8_t * plaintext , size_t plaintext_len , const uint8_t * passphrase , size_t passphrase_len ,
uint8_t * ciphertext , 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 ;
2022-02-21 21:24:00 +08:00
Tox_Pass_Key * key = tox_pass_key_derive ( passphrase , passphrase_len , & err ) ;
2014-09-12 08:29:18 +08:00
2022-02-18 10:05:44 +08:00
if ( key = = nullptr ) {
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
2022-02-21 21:24:00 +08:00
bool result = tox_pass_key_encrypt ( key , plaintext , plaintext_len , ciphertext , error ) ;
2016-12-16 11:00:55 +08:00
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
*/
2022-02-21 21:24:00 +08:00
bool tox_pass_key_decrypt ( const Tox_Pass_Key * key , const uint8_t * ciphertext , size_t length , uint8_t * plaintext ,
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
2022-02-21 21:24:00 +08:00
if ( ciphertext = = nullptr | | key = = nullptr | | plaintext = = nullptr ) {
2015-04-01 10:16:04 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_NULL ) ;
return 0 ;
}
2015-04-02 07:57:31 +08:00
2022-02-21 21:24:00 +08:00
if ( memcmp ( ciphertext , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ! = 0 ) {
2015-04-01 07:15:59 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_BAD_FORMAT ) ;
return 0 ;
}
2014-10-09 07:14:23 +08:00
2022-02-21 21:24:00 +08:00
ciphertext + = TOX_ENC_SAVE_MAGIC_LENGTH ;
ciphertext + = 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 ] ;
2022-02-21 21:24:00 +08:00
memcpy ( nonce , ciphertext , crypto_box_NONCEBYTES ) ;
ciphertext + = crypto_box_NONCEBYTES ;
2014-09-14 09:29:33 +08:00
2022-02-21 21:24:00 +08:00
/* decrypt the ciphertext */
if ( decrypt_data_symmetric ( key - > key , nonce , ciphertext , decrypt_length + crypto_box_MACBYTES , plaintext )
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
*/
2022-02-21 21:24:00 +08:00
bool tox_pass_decrypt ( const uint8_t * ciphertext , size_t ciphertext_len , const uint8_t * passphrase ,
size_t passphrase_len , uint8_t * plaintext , Tox_Err_Decryption * error )
2014-10-10 09:16:05 +08:00
{
2022-02-21 21:24:00 +08:00
if ( ciphertext_len < = 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
2022-02-21 21:24:00 +08:00
if ( ciphertext = = nullptr | | passphrase = = nullptr | | plaintext = = nullptr ) {
2015-04-01 08:30:09 +08:00
SET_ERROR_PARAMETER ( error , TOX_ERR_DECRYPTION_NULL ) ;
return 0 ;
}
2015-04-02 07:57:31 +08:00
2022-02-21 21:24:00 +08:00
if ( memcmp ( ciphertext , TOX_ENC_SAVE_MAGIC_NUMBER , TOX_ENC_SAVE_MAGIC_LENGTH ) ! = 0 ) {
2015-04-01 07:15:59 +08:00
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 ] ;
2022-02-21 21:24:00 +08:00
memcpy ( salt , ciphertext + 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 */
2022-02-21 21:24:00 +08:00
Tox_Pass_Key * key = tox_pass_key_derive_with_salt ( passphrase , passphrase_len , salt , nullptr ) ;
2014-09-14 09:29:33 +08:00
2022-02-18 10:05:44 +08:00
if ( key = = nullptr ) {
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
2022-02-21 21:24:00 +08:00
bool result = tox_pass_key_decrypt ( key , ciphertext , ciphertext_len , plaintext , error ) ;
2016-12-16 11:00:55 +08:00
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
}