Line data Source code
1 : // Copyright (c) 2019 The Bitcoin Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include <crypto/chacha_poly_aead.h> 6 : 7 : #include <crypto/poly1305.h> 8 : #include <support/cleanse.h> 9 : 10 : #include <assert.h> 11 : #include <string.h> 12 : 13 : #include <cstdio> 14 : #include <limits> 15 : 16 : #ifndef HAVE_TIMINGSAFE_BCMP 17 : 18 3000 : int timingsafe_bcmp(const unsigned char* b1, const unsigned char* b2, size_t n) 19 : { 20 : const unsigned char *p1 = b1, *p2 = b2; 21 : int ret = 0; 22 : 23 51000 : for (; n > 0; n--) 24 48000 : ret |= *p1++ ^ *p2++; 25 3000 : return (ret != 0); 26 : } 27 : 28 : #endif // TIMINGSAFE_BCMP 29 : 30 10 : ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len) 31 5 : { 32 5 : assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN); 33 5 : assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN); 34 5 : m_chacha_main.SetKey(K_1, CHACHA20_POLY1305_AEAD_KEY_LEN); 35 5 : m_chacha_header.SetKey(K_2, CHACHA20_POLY1305_AEAD_KEY_LEN); 36 : 37 : // set the cached sequence number to uint64 max which hints for an unset cache. 38 : // we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB 39 5 : m_cached_aad_seqnr = std::numeric_limits<uint64_t>::max(); 40 10 : } 41 : 42 6516 : bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char* dest, size_t dest_len /* length of the output buffer for sanity checks */, const unsigned char* src, size_t src_len, bool is_encrypt) 43 : { 44 : // check buffer boundaries 45 : if ( 46 : // if we encrypt, make sure the source contains at least the expected AAD and the destination has at least space for the source + MAC 47 9516 : (is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN || dest_len < src_len + POLY1305_TAGLEN)) || 48 : // if we decrypt, make sure the source contains at least the expected AAD+MAC and the destination has at least space for the source - MAC 49 6515 : (!is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN || dest_len < src_len - POLY1305_TAGLEN))) { 50 1 : return false; 51 : } 52 : 53 6515 : unsigned char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; 54 6515 : memset(poly_key, 0, sizeof(poly_key)); 55 6515 : m_chacha_main.SetIV(seqnr_payload); 56 : 57 : // block counter 0 for the poly1305 key 58 : // use lower 32bytes for the poly1305 key 59 : // (throws away 32 unused bytes (upper 32) from this ChaCha20 round) 60 6515 : m_chacha_main.Seek(0); 61 6515 : m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key)); 62 : 63 : // if decrypting, verify the tag prior to decryption 64 6515 : if (!is_encrypt) { 65 3000 : const unsigned char* tag = src + src_len - POLY1305_TAGLEN; 66 3000 : poly1305_auth(expected_tag, src, src_len - POLY1305_TAGLEN, poly_key); 67 : 68 : // constant time compare the calculated MAC with the provided MAC 69 3000 : if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { 70 : memory_cleanse(expected_tag, sizeof(expected_tag)); 71 0 : memory_cleanse(poly_key, sizeof(poly_key)); 72 0 : return false; 73 : } 74 : memory_cleanse(expected_tag, sizeof(expected_tag)); 75 : // MAC has been successfully verified, make sure we don't covert it in decryption 76 : src_len -= POLY1305_TAGLEN; 77 3000 : } 78 : 79 : // calculate and cache the next 64byte keystream block if requested sequence number is not yet the cache 80 6515 : if (m_cached_aad_seqnr != seqnr_aad) { 81 164 : m_cached_aad_seqnr = seqnr_aad; 82 164 : m_chacha_header.SetIV(seqnr_aad); 83 164 : m_chacha_header.Seek(0); 84 164 : m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); 85 164 : } 86 : // crypt the AAD (3 bytes message length) with given position in AAD cipher instance keystream 87 6515 : dest[0] = src[0] ^ m_aad_keystream_buffer[aad_pos]; 88 6515 : dest[1] = src[1] ^ m_aad_keystream_buffer[aad_pos + 1]; 89 6515 : dest[2] = src[2] ^ m_aad_keystream_buffer[aad_pos + 2]; 90 : 91 : // Set the playload ChaCha instance block counter to 1 and crypt the payload 92 6515 : m_chacha_main.Seek(1); 93 6515 : m_chacha_main.Crypt(src + CHACHA20_POLY1305_AEAD_AAD_LEN, dest + CHACHA20_POLY1305_AEAD_AAD_LEN, src_len - CHACHA20_POLY1305_AEAD_AAD_LEN); 94 : 95 : // If encrypting, calculate and append tag 96 6515 : if (is_encrypt) { 97 : // the poly1305 tag expands over the AAD (3 bytes length) & encrypted payload 98 3515 : poly1305_auth(dest + src_len, dest, src_len, poly_key); 99 3515 : } 100 : 101 : // cleanse no longer required MAC and polykey 102 6515 : memory_cleanse(poly_key, sizeof(poly_key)); 103 6515 : return true; 104 6516 : } 105 : 106 3114 : bool ChaCha20Poly1305AEAD::GetLength(uint32_t* len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t* ciphertext) 107 : { 108 : // enforce valid aad position to avoid accessing outside of the 64byte keystream cache 109 : // (there is space for 21 times 3 bytes) 110 3114 : assert(aad_pos >= 0 && aad_pos < CHACHA20_ROUND_OUTPUT - CHACHA20_POLY1305_AEAD_AAD_LEN); 111 3114 : if (m_cached_aad_seqnr != seqnr_aad) { 112 : // we need to calculate the 64 keystream bytes since we reached a new aad sequence number 113 0 : m_cached_aad_seqnr = seqnr_aad; 114 0 : m_chacha_header.SetIV(seqnr_aad); // use LE for the nonce 115 0 : m_chacha_header.Seek(0); // block counter 0 116 0 : m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); // write keystream to the cache 117 0 : } 118 : 119 : // decrypt the ciphertext length by XORing the right position of the 64byte keystream cache with the ciphertext 120 9342 : *len24_out = (ciphertext[0] ^ m_aad_keystream_buffer[aad_pos + 0]) | 121 6228 : (ciphertext[1] ^ m_aad_keystream_buffer[aad_pos + 1]) << 8 | 122 3114 : (ciphertext[2] ^ m_aad_keystream_buffer[aad_pos + 2]) << 16; 123 : 124 3114 : return true; 125 : }