mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
added new encryption/authentication format AEAD_chacha20_sha256
This commit is contained in:
parent
c87ca67120
commit
8486346368
@ -28,6 +28,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
@ -38,6 +40,8 @@
|
||||
|
||||
#define rotl(x,n) { x = (x << n) | (x >> (-n & 31)) ;}
|
||||
|
||||
//#define DEBUG_CHACHA20
|
||||
|
||||
namespace librs {
|
||||
namespace crypto {
|
||||
|
||||
@ -47,9 +51,9 @@ namespace crypto {
|
||||
*/
|
||||
struct uint256_32
|
||||
{
|
||||
uint64_t b[8] ;
|
||||
uint32_t b[8] ;
|
||||
|
||||
uint256_32() { memset(&b[0],0,8*sizeof(uint64_t)) ; }
|
||||
uint256_32() { memset(&b[0],0,8*sizeof(uint32_t)) ; }
|
||||
|
||||
uint256_32(uint32_t b7,uint32_t b6,uint32_t b5,uint32_t b4,uint32_t b3,uint32_t b2,uint32_t b1,uint32_t b0)
|
||||
{
|
||||
@ -87,33 +91,26 @@ struct uint256_32
|
||||
//
|
||||
void operator +=(const uint256_32& u)
|
||||
{
|
||||
b[0] += u.b[0];
|
||||
b[1] += u.b[1] + (b[0]>>32);
|
||||
b[2] += u.b[2] + (b[1]>>32);
|
||||
b[3] += u.b[3] + (b[2]>>32);
|
||||
b[4] += u.b[4] + (b[3]>>32);
|
||||
b[5] += u.b[5] + (b[4]>>32);
|
||||
b[6] += u.b[6] + (b[5]>>32);
|
||||
b[7] += u.b[7] + (b[6]>>32);
|
||||
uint64_t v(0) ;
|
||||
|
||||
b[0] = (uint32_t) b[0];
|
||||
b[1] = (uint32_t) b[1];
|
||||
b[2] = (uint32_t) b[2];
|
||||
b[3] = (uint32_t) b[3];
|
||||
b[4] = (uint32_t) b[4];
|
||||
b[5] = (uint32_t) b[5];
|
||||
b[6] = (uint32_t) b[6];
|
||||
b[7] = (uint32_t) b[7];
|
||||
v += (uint64_t)b[0] + (uint64_t)u.b[0] ; b[0] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[1] + (uint64_t)u.b[1] ; b[1] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[2] + (uint64_t)u.b[2] ; b[2] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[3] + (uint64_t)u.b[3] ; b[3] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[4] + (uint64_t)u.b[4] ; b[4] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[5] + (uint64_t)u.b[5] ; b[5] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[6] + (uint64_t)u.b[6] ; b[6] = (uint32_t)v ; v >>= 32;
|
||||
v += (uint64_t)b[7] + (uint64_t)u.b[7] ; b[7] = (uint32_t)v ;
|
||||
}
|
||||
void operator -=(const uint256_32& u)
|
||||
{
|
||||
*this += ~u ;
|
||||
++(*this) ;
|
||||
++*this ;
|
||||
}
|
||||
void operator++()
|
||||
{
|
||||
for(int i=0;i<8;++i)
|
||||
if( (++b[i]) &= 0xffffffff)
|
||||
if( ++b[i] )
|
||||
break ;
|
||||
}
|
||||
|
||||
@ -132,14 +129,14 @@ struct uint256_32
|
||||
{
|
||||
uint256_32 r(*this) ;
|
||||
|
||||
r.b[0] = (~b[0]) & 0xffffffff ;
|
||||
r.b[1] = (~b[1]) & 0xffffffff ;
|
||||
r.b[2] = (~b[2]) & 0xffffffff ;
|
||||
r.b[3] = (~b[3]) & 0xffffffff ;
|
||||
r.b[4] = (~b[4]) & 0xffffffff ;
|
||||
r.b[5] = (~b[5]) & 0xffffffff ;
|
||||
r.b[6] = (~b[6]) & 0xffffffff ;
|
||||
r.b[7] = (~b[7]) & 0xffffffff ;
|
||||
r.b[0] = ~b[0] ;
|
||||
r.b[1] = ~b[1] ;
|
||||
r.b[2] = ~b[2] ;
|
||||
r.b[3] = ~b[3] ;
|
||||
r.b[4] = ~b[4] ;
|
||||
r.b[5] = ~b[5] ;
|
||||
r.b[6] = ~b[6] ;
|
||||
r.b[7] = ~b[7] ;
|
||||
|
||||
return r ;
|
||||
}
|
||||
@ -161,7 +158,7 @@ struct uint256_32
|
||||
for(int j=0;j<8;++j)
|
||||
if(i+j < 8)
|
||||
{
|
||||
uint64_t s = u.b[j]*b[i] ;
|
||||
uint64_t s = (uint64_t)u.b[j]*(uint64_t)b[i] ;
|
||||
|
||||
uint256_32 partial ;
|
||||
partial.b[i+j] = (s & 0xffffffff) ;
|
||||
@ -172,17 +169,6 @@ struct uint256_32
|
||||
r += partial;
|
||||
}
|
||||
*this = r;
|
||||
|
||||
#ifdef DEBUG_CHACHA20
|
||||
if(!(!(b[0] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[1] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[2] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[3] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[4] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[5] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[6] & 0xffffffff00000000))) throw() ;
|
||||
if(!(!(b[7] & 0xffffffff00000000))) throw() ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print(const uint256_32& s)
|
||||
@ -217,7 +203,7 @@ struct uint256_32
|
||||
|
||||
if(p > 0)
|
||||
for(int i=7;i>=0;--i)
|
||||
b[i] = (i>=p)?b[i-p]:0 ;
|
||||
b[i] = (i>=(int)p)?b[i-p]:0 ;
|
||||
|
||||
uint32_t r = 0 ;
|
||||
|
||||
@ -235,14 +221,14 @@ struct uint256_32
|
||||
uint32_t r ;
|
||||
uint32_t r1 ;
|
||||
|
||||
r1 = (b[0] >> 31) ; b[0] = (b[0] << 1) & 0xffffffff; r = r1 ;
|
||||
r1 = (b[1] >> 31) ; b[1] = (b[1] << 1) & 0xffffffff; b[1] += r ; r = r1 ;
|
||||
r1 = (b[2] >> 31) ; b[2] = (b[2] << 1) & 0xffffffff; b[2] += r ; r = r1 ;
|
||||
r1 = (b[3] >> 31) ; b[3] = (b[3] << 1) & 0xffffffff; b[3] += r ; r = r1 ;
|
||||
r1 = (b[4] >> 31) ; b[4] = (b[4] << 1) & 0xffffffff; b[4] += r ; r = r1 ;
|
||||
r1 = (b[5] >> 31) ; b[5] = (b[5] << 1) & 0xffffffff; b[5] += r ; r = r1 ;
|
||||
r1 = (b[6] >> 31) ; b[6] = (b[6] << 1) & 0xffffffff; b[6] += r ; r = r1 ;
|
||||
b[7] = (b[7] << 1) & 0xffffffff; b[7] += r ;
|
||||
r1 = (b[0] >> 31) ; b[0] <<= 1; r = r1 ;
|
||||
r1 = (b[1] >> 31) ; b[1] <<= 1; b[1] += r ; r = r1 ;
|
||||
r1 = (b[2] >> 31) ; b[2] <<= 1; b[2] += r ; r = r1 ;
|
||||
r1 = (b[3] >> 31) ; b[3] <<= 1; b[3] += r ; r = r1 ;
|
||||
r1 = (b[4] >> 31) ; b[4] <<= 1; b[4] += r ; r = r1 ;
|
||||
r1 = (b[5] >> 31) ; b[5] <<= 1; b[5] += r ; r = r1 ;
|
||||
r1 = (b[6] >> 31) ; b[6] <<= 1; b[6] += r ; r = r1 ;
|
||||
b[7] <<= 1; b[7] += r ;
|
||||
}
|
||||
void rshift()
|
||||
{
|
||||
@ -538,6 +524,37 @@ bool AEAD_chacha20_poly1305(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uin
|
||||
}
|
||||
}
|
||||
|
||||
bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12], uint8_t *data, uint32_t data_size, uint8_t tag[16], bool encrypt)
|
||||
{
|
||||
// encrypt + tag. See RFC7539-2.8
|
||||
|
||||
if(encrypt)
|
||||
{
|
||||
chacha20_encrypt(key,1,nonce,data,data_size);
|
||||
|
||||
uint8_t computed_tag[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_size ;
|
||||
HMAC(EVP_sha256(),key,32,data,data_size,computed_tag,&md_size) ;
|
||||
|
||||
memcpy(tag,computed_tag,16) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t computed_tag[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_size ;
|
||||
HMAC(EVP_sha256(),key,32,data,data_size,computed_tag,&md_size) ;
|
||||
|
||||
// decrypt
|
||||
|
||||
chacha20_encrypt(key,1,nonce,data,data_size);
|
||||
|
||||
return constant_time_memory_compare(tag,computed_tag,16) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool perform_tests()
|
||||
{
|
||||
// RFC7539 - 2.1.1
|
||||
@ -647,6 +664,7 @@ bool perform_tests()
|
||||
|
||||
{ uint256_32 uu(0,0,0,0,0,0,0,0 ) ; ++uu ; if(!(uu == uint256_32(0,0,0,0,0,0,0,1))) return false ; }
|
||||
{ uint256_32 uu(0,0,0,0,0,0,0,0xffffffff) ; ++uu ; if(!(uu == uint256_32(0,0,0,0,0,0,1,0))) return false ; }
|
||||
{ uint256_32 uu(0,0,0,0,0,0,0,0) ; uu = ~uu;++uu ; if(!(uu == uint256_32(0,0,0,0,0,0,0,0))) return false ; }
|
||||
|
||||
std::cerr << " operator++ on 256bits numbers OK" << std::endl;
|
||||
|
||||
@ -684,7 +702,19 @@ bool perform_tests()
|
||||
|
||||
if(!(a == a)) return false ;
|
||||
if(!(c == a)) return false ;
|
||||
|
||||
uint256_32 vv(0,0,0,0,0,0,0,1) ;
|
||||
vv -= a ;
|
||||
vv += a ;
|
||||
|
||||
if(!(vv == uint256_32(0,0,0,0,0,0,0,1))) return false ;
|
||||
|
||||
}
|
||||
uint256_32 vv(0,0,0,0,0,0,0,0) ;
|
||||
uint256_32 ww(0,0,0,0,0,0,0,1) ;
|
||||
vv -= ww ;
|
||||
if(!(vv == ~uint256_32(0,0,0,0,0,0,0,0))) return false;
|
||||
|
||||
std::cerr << " Sums / diffs of 256bits numbers OK" << std::endl;
|
||||
|
||||
// check that (a-b)*(c-d) = ac - bc - ad + bd
|
||||
@ -753,7 +783,7 @@ bool perform_tests()
|
||||
|
||||
quotient(n1,p1,q1,r1) ;
|
||||
#ifdef DEBUG_CHACHA20
|
||||
fprintf(stdout,"result: q=") ; chacha20::uint256_32::print(q1) ; fprintf(stdout," r=") ; chacha20::uint256_32::print(r1) ; fprintf(stdout,"\n") ;
|
||||
fprintf(stdout,"result: q=") ; uint256_32::print(q1) ; fprintf(stdout," r=") ; uint256_32::print(r1) ; fprintf(stdout,"\n") ;
|
||||
#endif
|
||||
|
||||
uint256_32 res(q1) ;
|
||||
@ -1164,16 +1194,22 @@ bool perform_tests()
|
||||
uint8_t received_tag[16] ;
|
||||
|
||||
{
|
||||
RsScopeTimer s("AEAD") ;
|
||||
RsScopeTimer s("AEAD1") ;
|
||||
chacha20_encrypt(key, 1, nonce, ten_megabyte_data,SIZE) ;
|
||||
|
||||
std::cerr << " Chacha20 encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
std::cerr << " Chacha20 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
{
|
||||
RsScopeTimer s("AEAD") ;
|
||||
RsScopeTimer s("AEAD2") ;
|
||||
AEAD_chacha20_poly1305(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
std::cerr << " AEAD/poly1305 encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
{
|
||||
RsScopeTimer s("AEAD3") ;
|
||||
AEAD_chacha20_sha256(key,nonce,ten_megabyte_data,SIZE,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/sha256 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
|
||||
free(ten_megabyte_data) ;
|
||||
|
@ -59,9 +59,11 @@ namespace librs
|
||||
* 16-padded AAD (additional authenticated data) and its size, authenticated using poly1305.
|
||||
*
|
||||
* \param key key that is used to derive a one time secret key for poly1305 and that is also used to encrypt the data
|
||||
* \param nonce nonce. *Should be unique* in order to make the poly1305 key unique.
|
||||
* \param data data that is encrypted.
|
||||
* \param nonce nonce. *Should be unique* in order to make the chacha20 stream cipher unique.
|
||||
* \param data data that is encrypted/decrypted in place.
|
||||
* \param size size of the data
|
||||
* \param aad additional authenticated data. Can be used to authenticate the nonce.
|
||||
* \param aad_size
|
||||
* \param tag generated poly1305 tag.
|
||||
* \param encrypt true to encrypt, false to decrypt and check the tag.
|
||||
* \return
|
||||
@ -70,6 +72,22 @@ namespace librs
|
||||
*/
|
||||
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_or_decrypt) ;
|
||||
|
||||
/*!
|
||||
* \brief AEAD_chacha20_sha256
|
||||
* Provides authenticated encryption using a simple construction that associates chacha20 encryption with HMAC authentication using
|
||||
* the same 32 bytes key. The authenticated tag is the 16 first bytes of the sha256 HMAC.
|
||||
*
|
||||
* \param key encryption/authentication key
|
||||
* \param nonce nonce. *Should be unique* in order to make chacha20 stream cipher unique.
|
||||
* \param data data that is encrypted/decrypted in place
|
||||
* \param data_size size of data to encrypt/authenticate
|
||||
* \param tag 16 bytes authentication tag result
|
||||
* \param encrypt true to encrypt, false to decrypt and check the tag.
|
||||
* \return
|
||||
* always true for encryption.
|
||||
* authentication result for decryption. data is *always* xored to the cipher stream whatever the authentication result is.
|
||||
*/
|
||||
bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint32_t data_size,uint8_t tag[16],bool encrypt);
|
||||
/*!
|
||||
* \brief constant_time_memcmp
|
||||
* Provides a constant time comparison of two memory chunks. Calls CRYPTO_memcmp.
|
||||
|
@ -1023,7 +1023,8 @@ bool ftServer::sendData(const RsPeerId& peerId, const RsFileHash& hash, uint64_t
|
||||
//
|
||||
//
|
||||
// Encryption format:
|
||||
// ae ad 00 01 : encryption using AEAD, format 00, version 01
|
||||
// ae ad 01 01 : encryption using AEAD, format 01 (authed with Poly1305 ), version 01
|
||||
// ae ad 02 01 : encryption using AEAD, format 02 (authed with HMAC Sha256), version 01
|
||||
//
|
||||
//
|
||||
|
||||
@ -1045,6 +1046,10 @@ static const uint32_t ENCRYPTED_FT_AUTHENTICATION_TAG_SIZE = 16 ;
|
||||
static const uint32_t ENCRYPTED_FT_HEADER_SIZE = 4 ;
|
||||
static const uint32_t ENCRYPTED_FT_EDATA_SIZE = 4 ;
|
||||
|
||||
static const uint8_t ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_POLY1305 = 0x01 ;
|
||||
static const uint8_t ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256 = 0x02 ;
|
||||
|
||||
|
||||
bool ftServer::encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHash& hash,RsTurtleGenericDataItem *& encrypted_item)
|
||||
{
|
||||
uint8_t initialization_vector[ENCRYPTED_FT_INITIALIZATION_VECTOR_SIZE] ;
|
||||
@ -1072,7 +1077,7 @@ bool ftServer::encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHas
|
||||
|
||||
edata[0] = 0xae ;
|
||||
edata[1] = 0xad ;
|
||||
edata[2] = 0x00 ;
|
||||
edata[2] = ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256 ; // means AEAD_chacha20_sha256
|
||||
edata[3] = 0x01 ;
|
||||
|
||||
offset += ENCRYPTED_FT_HEADER_SIZE;
|
||||
@ -1103,7 +1108,12 @@ bool ftServer::encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHas
|
||||
uint8_t encryption_key[32] ;
|
||||
deriveEncryptionKey(hash,encryption_key) ;
|
||||
|
||||
librs::crypto::AEAD_chacha20_poly1305(encryption_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],true) ;
|
||||
if(edata[2] == ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_POLY1305)
|
||||
librs::crypto::AEAD_chacha20_poly1305(encryption_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],true) ;
|
||||
else if(edata[2] == ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256)
|
||||
librs::crypto::AEAD_chacha20_sha256(encryption_key,initialization_vector,&edata[aad_offset],edata_size+ENCRYPTED_FT_INITIALIZATION_VECTOR_SIZE+ENCRYPTED_FT_EDATA_SIZE, &edata[authentication_tag_offset],true) ;
|
||||
else
|
||||
return false ;
|
||||
|
||||
std::cerr << " encryption key : " << RsUtil::BinToHex(encryption_key,32) << std::endl;
|
||||
std::cerr << " authen. tag : " << RsUtil::BinToHex(&edata[authentication_tag_offset],ENCRYPTED_FT_AUTHENTICATION_TAG_SIZE) << std::endl;
|
||||
@ -1126,7 +1136,7 @@ bool ftServer::decryptItem(RsTurtleGenericDataItem *encrypted_item,const RsFileH
|
||||
|
||||
if(edata[0] != 0xae) return false ;
|
||||
if(edata[1] != 0xad) return false ;
|
||||
if(edata[2] != 0x00) return false ;
|
||||
if(edata[2] != ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_POLY1305 && edata[2] != ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256) return false ;
|
||||
if(edata[3] != 0x01) return false ;
|
||||
|
||||
offset += ENCRYPTED_FT_HEADER_SIZE ;
|
||||
@ -1155,11 +1165,23 @@ bool ftServer::decryptItem(RsTurtleGenericDataItem *encrypted_item,const RsFileH
|
||||
uint32_t authentication_tag_offset = offset + edata_size ;
|
||||
std::cerr << " authen. tag : " << RsUtil::BinToHex(&edata[authentication_tag_offset],ENCRYPTED_FT_AUTHENTICATION_TAG_SIZE) << std::endl;
|
||||
|
||||
if(!librs::crypto::AEAD_chacha20_poly1305(encryption_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],false))
|
||||
return false;
|
||||
bool result ;
|
||||
|
||||
std::cerr << " authen. result : ok" << std::endl;
|
||||
std::cerr << " decrypted daya : ok" << RsUtil::BinToHex(&edata[clear_item_offset],std::min(50u,edata_size)) << "(...)" << std::endl;
|
||||
if(edata[2] == ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_POLY1305)
|
||||
result = librs::crypto::AEAD_chacha20_poly1305(encryption_key,initialization_vector,&edata[clear_item_offset],edata_size, &edata[aad_offset],aad_size, &edata[authentication_tag_offset],false) ;
|
||||
else if(edata[2] == ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256)
|
||||
result = librs::crypto::AEAD_chacha20_sha256(encryption_key,initialization_vector,&edata[aad_offset],edata_size+ENCRYPTED_FT_INITIALIZATION_VECTOR_SIZE+ENCRYPTED_FT_EDATA_SIZE, &edata[authentication_tag_offset],false) ;
|
||||
else
|
||||
return false ;
|
||||
|
||||
std::cerr << " authen. result : " << result << std::endl;
|
||||
std::cerr << " decrypted daya : " << RsUtil::BinToHex(&edata[clear_item_offset],std::min(50u,edata_size)) << "(...)" << std::endl;
|
||||
|
||||
if(!result)
|
||||
{
|
||||
std::cerr << "(EE) decryption/authentication went wrong." << std::endl;
|
||||
return false ;
|
||||
}
|
||||
|
||||
decrypted_item = deserialiseItem(&edata[clear_item_offset],edata_size) ;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user