mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-27 07:47:03 -05:00
Merge pull request #800 from sehraf/pr-openssl-chacha20
add support for openssl's chacha20-poly1305 implementation
This commit is contained in:
commit
f7f0d8ddd0
@ -44,6 +44,12 @@
|
||||
|
||||
//#define DEBUG_CHACHA20
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
|
||||
#define AEAD_chacha20_poly1305_openssl AEAD_chacha20_poly1305
|
||||
#else
|
||||
#define AEAD_chacha20_poly1305_rs AEAD_chacha20_poly1305
|
||||
#endif
|
||||
|
||||
namespace librs {
|
||||
namespace crypto {
|
||||
|
||||
@ -273,6 +279,7 @@ static void quotient(const uint256_32& n,const uint256_32& p,uint256_32& q,uint2
|
||||
q += m ;
|
||||
}
|
||||
}
|
||||
|
||||
static void remainder(const uint256_32& n,const uint256_32& p,uint256_32& r)
|
||||
{
|
||||
// simple algorithm: add up multiples of u while keeping below *this. Once done, substract.
|
||||
@ -356,7 +363,7 @@ static void print(const chacha20_state& s)
|
||||
}
|
||||
#endif
|
||||
|
||||
void chacha20_encrypt(uint8_t key[32], uint32_t block_counter, uint8_t nonce[12], uint8_t *data, uint32_t size)
|
||||
void chacha20_encrypt_rs(uint8_t key[32], uint32_t block_counter, uint8_t nonce[12], uint8_t *data, uint32_t size)
|
||||
{
|
||||
for(uint32_t i=0;i<size/64 + 1;++i)
|
||||
{
|
||||
@ -379,6 +386,50 @@ void chacha20_encrypt(uint8_t key[32], uint32_t block_counter, uint8_t nonce[12]
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
|
||||
void chacha20_encrypt_openssl(uint8_t key[32], uint32_t block_counter, uint8_t nonce[12], uint8_t *data, uint32_t size)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
int len;
|
||||
int tmp_len;
|
||||
uint8_t tmp[size];
|
||||
uint8_t iv[16];
|
||||
|
||||
// create iv with nonce and block counter
|
||||
memcpy(iv, &block_counter, 4);
|
||||
memcpy(iv + 4, nonce, 12);
|
||||
|
||||
/* Create and initialise the context */
|
||||
if(!(ctx = EVP_CIPHER_CTX_new())) return;
|
||||
|
||||
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
|
||||
* and IV size appropriate for your cipher
|
||||
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
|
||||
* IV size for *most* modes is the same as the block size. For AES this
|
||||
* is 128 bits */
|
||||
if(1 != EVP_EncryptInit_ex(ctx, EVP_chacha20(), NULL, key, iv)) goto out;
|
||||
|
||||
/* Provide the message to be encrypted, and obtain the encrypted output.
|
||||
* EVP_EncryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if(1 != EVP_EncryptUpdate(ctx, tmp, &len, data, size)) goto out;
|
||||
tmp_len = len;
|
||||
|
||||
/* Finalise the encryption. Further ciphertext bytes may be written at
|
||||
* this stage.
|
||||
*/
|
||||
if(1 != EVP_EncryptFinal_ex(ctx, tmp + len, &len)) goto out;
|
||||
tmp_len += len;
|
||||
|
||||
memcpy(data, tmp, tmp_len);
|
||||
|
||||
out:
|
||||
/* Clean up */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct poly1305_state
|
||||
{
|
||||
uint256_32 r ;
|
||||
@ -475,7 +526,7 @@ bool constant_time_memory_compare(const uint8_t *m1,const uint8_t *m2,uint32_t s
|
||||
return !CRYPTO_memcmp(m1,m2,size) ;
|
||||
}
|
||||
|
||||
bool AEAD_chacha20_poly1305(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint32_t data_size,uint8_t *aad,uint32_t aad_size,uint8_t tag[16],bool encrypt)
|
||||
bool AEAD_chacha20_poly1305_rs(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint32_t data_size,uint8_t *aad,uint32_t aad_size,uint8_t tag[16],bool encrypt)
|
||||
{
|
||||
// encrypt + tag. See RFC7539-2.8
|
||||
|
||||
@ -492,7 +543,7 @@ bool AEAD_chacha20_poly1305(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uin
|
||||
|
||||
if(encrypt)
|
||||
{
|
||||
chacha20_encrypt(key,1,nonce,data,data_size);
|
||||
chacha20_encrypt_rs(key,1,nonce,data,data_size);
|
||||
|
||||
poly1305_state pls ;
|
||||
|
||||
@ -520,19 +571,107 @@ bool AEAD_chacha20_poly1305(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uin
|
||||
|
||||
// decrypt
|
||||
|
||||
chacha20_encrypt(key,1,nonce,data,data_size);
|
||||
chacha20_encrypt_rs(key,1,nonce,data,data_size);
|
||||
|
||||
return constant_time_memory_compare(tag,computed_tag,16) ;
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
|
||||
#define errorOut {ret = false; goto out;}
|
||||
|
||||
bool AEAD_chacha20_poly1305_openssl(uint8_t key[32], uint8_t nonce[12], uint8_t *data, uint32_t data_size, uint8_t *aad, uint32_t aad_size, uint8_t tag[16], bool encrypt_or_decrypt)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
bool ret = true;
|
||||
int len;
|
||||
const uint8_t tag_len = 16;
|
||||
int tmp_len;
|
||||
uint8_t tmp[data_size];
|
||||
|
||||
/* Create and initialise the context */
|
||||
if(!(ctx = EVP_CIPHER_CTX_new())) return false;
|
||||
|
||||
if (encrypt_or_decrypt) {
|
||||
/* Initialise the encryption operation. */
|
||||
if(1 != EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL)) errorOut
|
||||
|
||||
/* Initialise key and IV */
|
||||
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce)) errorOut
|
||||
|
||||
/* Provide any AAD data. This can be called zero or more times as
|
||||
* required
|
||||
*/
|
||||
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_size)) errorOut
|
||||
|
||||
/* Provide the message to be encrypted, and obtain the encrypted output.
|
||||
* EVP_EncryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if(1 != EVP_EncryptUpdate(ctx, tmp, &len, data, data_size)) errorOut
|
||||
tmp_len = len;
|
||||
|
||||
/* Finalise the encryption. Normally ciphertext bytes may be written at
|
||||
* this stage, but this does not occur in GCM mode
|
||||
*/
|
||||
if(1 != EVP_EncryptFinal_ex(ctx, data + len, &len)) errorOut
|
||||
tmp_len += len;
|
||||
|
||||
/* Get the tag */
|
||||
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, tag)) errorOut
|
||||
} else {
|
||||
/* Initialise the decryption operation. */
|
||||
if(!EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key, nonce)) errorOut
|
||||
|
||||
/* Provide any AAD data. This can be called zero or more times as
|
||||
* required
|
||||
*/
|
||||
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_size)) errorOut
|
||||
|
||||
/* Provide the message to be decrypted, and obtain the plaintext output.
|
||||
* EVP_DecryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if(!EVP_DecryptUpdate(ctx, tmp, &len, data, data_size)) errorOut
|
||||
tmp_len = len;
|
||||
|
||||
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
|
||||
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag)) errorOut
|
||||
|
||||
/* Finalise the decryption. A positive return value indicates success,
|
||||
* anything else is a failure - the plaintext is not trustworthy.
|
||||
*/
|
||||
if(EVP_DecryptFinal_ex(ctx, tmp + len, &len) > 0) {
|
||||
/* Success */
|
||||
tmp_len += len;
|
||||
ret = true;
|
||||
} else {
|
||||
/* Verify failed */
|
||||
errorOut
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(data, tmp, tmp_len);
|
||||
|
||||
out:
|
||||
/* Clean up */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
#undef errorOut
|
||||
#endif
|
||||
|
||||
bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint32_t data_size,uint8_t *aad,uint32_t aad_size,uint8_t tag[16],bool encrypt)
|
||||
{
|
||||
// encrypt + tag. See RFC7539-2.8
|
||||
|
||||
if(encrypt)
|
||||
{
|
||||
chacha20_encrypt(key,1,nonce,data,data_size);
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
chacha20_encrypt_rs(key,1,nonce,data,data_size);
|
||||
#else
|
||||
chacha20_encrypt_openssl(key, 1, nonce, data, data_size);
|
||||
#endif
|
||||
|
||||
uint8_t computed_tag[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_size ;
|
||||
@ -594,7 +733,11 @@ bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint3
|
||||
|
||||
// decrypt
|
||||
|
||||
chacha20_encrypt(key,1,nonce,data,data_size);
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
chacha20_encrypt_rs(key,1,nonce,data,data_size);
|
||||
#else
|
||||
chacha20_encrypt_openssl(key, 1, nonce, data, data_size);
|
||||
#endif
|
||||
|
||||
return constant_time_memory_compare(tag,computed_tag,16) ;
|
||||
}
|
||||
@ -674,7 +817,7 @@ bool perform_tests()
|
||||
0x74, 0x2e
|
||||
};
|
||||
|
||||
chacha20_encrypt(key,1,nounce2,plaintext,7*16+2) ;
|
||||
chacha20_encrypt_rs(key,1,nounce2,plaintext,7*16+2) ;
|
||||
|
||||
#ifdef DEBUG_CHACHA20
|
||||
fprintf(stdout,"CipherText: \n") ;
|
||||
@ -1154,12 +1297,12 @@ bool perform_tests()
|
||||
uint8_t tag[16] ;
|
||||
uint8_t test_tag[16] = { 0x1a,0xe1,0x0b,0x59,0x4f,0x09,0xe2,0x6a,0x7e,0x90,0x2e,0xcb,0xd0,0x60,0x06,0x91 };
|
||||
|
||||
AEAD_chacha20_poly1305(key,nonce,msg,7*16+2,aad,12,tag,true) ;
|
||||
AEAD_chacha20_poly1305_rs(key,nonce,msg,7*16+2,aad,12,tag,true) ;
|
||||
|
||||
if(!constant_time_memory_compare(msg,test_msg,7*16+2)) return false ;
|
||||
if(!constant_time_memory_compare(tag,test_tag,16)) return false ;
|
||||
|
||||
bool res = AEAD_chacha20_poly1305(key,nonce,msg,7*16+2,aad,12,tag,false) ;
|
||||
bool res = AEAD_chacha20_poly1305_rs(key,nonce,msg,7*16+2,aad,12,tag,false) ;
|
||||
|
||||
if(!res) return false ;
|
||||
}
|
||||
@ -1197,7 +1340,7 @@ bool perform_tests()
|
||||
|
||||
uint8_t received_tag[16] = { 0xee,0xad,0x9d,0x67,0x89,0x0c,0xbb,0x22,0x39,0x23,0x36,0xfe,0xa1,0x85,0x1f,0x38 };
|
||||
|
||||
if(!AEAD_chacha20_poly1305(key,nonce,ciphertext,16*16+9,aad,12,received_tag,false))
|
||||
if(!AEAD_chacha20_poly1305_rs(key,nonce,ciphertext,16*16+9,aad,12,received_tag,false))
|
||||
return false ;
|
||||
|
||||
uint8_t cleartext[16*16+9] = {
|
||||
@ -1243,18 +1386,26 @@ bool perform_tests()
|
||||
|
||||
{
|
||||
RsScopeTimer s("AEAD1") ;
|
||||
chacha20_encrypt(key, 1, nonce, ten_megabyte_data,SIZE) ;
|
||||
chacha20_encrypt_rs(key, 1, nonce, ten_megabyte_data,SIZE) ;
|
||||
|
||||
std::cerr << " Chacha20 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
{
|
||||
RsScopeTimer s("AEAD2") ;
|
||||
AEAD_chacha20_poly1305(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
AEAD_chacha20_poly1305_rs(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/poly1305 encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
std::cerr << " AEAD/poly1305 own encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
|
||||
{
|
||||
RsScopeTimer s("AEAD3") ;
|
||||
AEAD_chacha20_poly1305_openssl(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/poly1305 openssl encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
RsScopeTimer s("AEAD4") ;
|
||||
AEAD_chacha20_sha256(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/sha256 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
|
Loading…
x
Reference in New Issue
Block a user