LCOV - code coverage report
Current view: top level - src/crypto - chacha_poly_aead.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 50 57 87.7 %
Date: 2020-09-26 01:30:44 Functions: 5 5 100.0 %

          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             : }

Generated by: LCOV version 1.15