LCOV - code coverage report
Current view: top level - src - bip324.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 38 50 76.0 %
Date: 2023-10-05 12:38:51 Functions: 3 6 50.0 %
Branches: 52 116 44.8 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (c) 2023 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 <bip324.h>
       6                 :            : 
       7                 :            : #include <chainparams.h>
       8                 :            : #include <crypto/chacha20.h>
       9                 :            : #include <crypto/chacha20poly1305.h>
      10                 :            : #include <crypto/hkdf_sha256_32.h>
      11                 :            : #include <key.h>
      12                 :            : #include <pubkey.h>
      13                 :            : #include <random.h>
      14                 :            : #include <span.h>
      15                 :            : #include <support/cleanse.h>
      16                 :            : #include <uint256.h>
      17                 :            : 
      18                 :            : #include <algorithm>
      19                 :            : #include <assert.h>
      20                 :            : #include <cstdint>
      21                 :            : #include <cstddef>
      22                 :            : #include <iterator>
      23                 :            : #include <string>
      24                 :            : 
      25                 :       5054 : BIP324Cipher::BIP324Cipher(const CKey& key, Span<const std::byte> ent32) noexcept :
      26         [ +  - ]:       5054 :     m_key(key)
      27                 :            : {
      28         [ +  - ]:       5054 :     m_our_pubkey = m_key.EllSwiftCreate(ent32);
      29                 :       5054 : }
      30                 :            : 
      31                 :          0 : BIP324Cipher::BIP324Cipher(const CKey& key, const EllSwiftPubKey& pubkey) noexcept :
      32         [ #  # ]:          0 :     m_key(key), m_our_pubkey(pubkey) {}
      33                 :            : 
      34                 :        335 : void BIP324Cipher::Initialize(const EllSwiftPubKey& their_pubkey, bool initiator, bool self_decrypt) noexcept
      35                 :            : {
      36                 :            :     // Determine salt (fixed string + network magic bytes)
      37   [ +  -  +  - ]:        335 :     const auto& message_header = Params().MessageStart();
      38   [ +  -  +  -  :        335 :     std::string salt = std::string{"bitcoin_v2_shared_secret"} + std::string(std::begin(message_header), std::end(message_header));
          +  -  +  -  +  
                      - ]
      39                 :            : 
      40                 :            :     // Perform ECDH to derive shared secret.
      41         [ +  - ]:        335 :     ECDHSecret ecdh_secret = m_key.ComputeBIP324ECDHSecret(their_pubkey, m_our_pubkey, initiator);
      42                 :            : 
      43                 :            :     // Derive encryption keys from shared secret, and initialize stream ciphers and AEADs.
      44                 :        335 :     bool side = (initiator != self_decrypt);
      45   [ +  -  +  - ]:        335 :     CHKDF_HMAC_SHA256_L32 hkdf(UCharCast(ecdh_secret.data()), ecdh_secret.size(), salt);
      46                 :            :     std::array<std::byte, 32> hkdf_32_okm;
      47   [ +  -  +  -  :        335 :     hkdf.Expand32("initiator_L", UCharCast(hkdf_32_okm.data()));
                   +  - ]
      48   [ +  -  +  - ]:        335 :     (side ? m_send_l_cipher : m_recv_l_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
      49   [ +  -  +  -  :        335 :     hkdf.Expand32("initiator_P", UCharCast(hkdf_32_okm.data()));
                   +  - ]
      50   [ +  -  +  - ]:        335 :     (side ? m_send_p_cipher : m_recv_p_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
      51   [ +  -  +  -  :        335 :     hkdf.Expand32("responder_L", UCharCast(hkdf_32_okm.data()));
                   +  - ]
      52   [ +  -  +  - ]:        335 :     (side ? m_recv_l_cipher : m_send_l_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
      53   [ +  -  +  -  :        335 :     hkdf.Expand32("responder_P", UCharCast(hkdf_32_okm.data()));
                   +  - ]
      54   [ +  -  +  - ]:        335 :     (side ? m_recv_p_cipher : m_send_p_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
      55                 :            : 
      56                 :            :     // Derive garbage terminators from shared secret.
      57   [ +  -  +  -  :        335 :     hkdf.Expand32("garbage_terminators", UCharCast(hkdf_32_okm.data()));
                   +  - ]
      58   [ +  -  +  -  :        670 :     std::copy(std::begin(hkdf_32_okm), std::begin(hkdf_32_okm) + GARBAGE_TERMINATOR_LEN,
                   +  - ]
      59         [ +  - ]:        335 :         (initiator ? m_send_garbage_terminator : m_recv_garbage_terminator).begin());
      60   [ +  -  +  -  :        670 :     std::copy(std::end(hkdf_32_okm) - GARBAGE_TERMINATOR_LEN, std::end(hkdf_32_okm),
                   +  - ]
      61         [ +  - ]:        335 :         (initiator ? m_recv_garbage_terminator : m_send_garbage_terminator).begin());
      62                 :            : 
      63                 :            :     // Derive session id from shared secret.
      64   [ +  -  +  -  :        335 :     hkdf.Expand32("session_id", UCharCast(m_session_id.data()));
                   +  - ]
      65                 :            : 
      66                 :            :     // Wipe all variables that contain information which could be used to re-derive encryption keys.
      67         [ +  - ]:        335 :     memory_cleanse(ecdh_secret.data(), ecdh_secret.size());
      68         [ +  - ]:        335 :     memory_cleanse(hkdf_32_okm.data(), sizeof(hkdf_32_okm));
      69         [ +  - ]:        335 :     memory_cleanse(&hkdf, sizeof(hkdf));
      70                 :        335 :     m_key = CKey();
      71                 :        335 : }
      72                 :            : 
      73                 :        360 : void BIP324Cipher::Encrypt(Span<const std::byte> contents, Span<const std::byte> aad, bool ignore, Span<std::byte> output) noexcept
      74                 :            : {
      75         [ +  - ]:        360 :     assert(output.size() == contents.size() + EXPANSION);
      76                 :            : 
      77                 :            :     // Encrypt length.
      78                 :            :     std::byte len[LENGTH_LEN];
      79                 :        360 :     len[0] = std::byte{(uint8_t)(contents.size() & 0xFF)};
      80                 :        360 :     len[1] = std::byte{(uint8_t)((contents.size() >> 8) & 0xFF)};
      81                 :        360 :     len[2] = std::byte{(uint8_t)((contents.size() >> 16) & 0xFF)};
      82         [ +  - ]:        360 :     m_send_l_cipher->Crypt(len, output.first(LENGTH_LEN));
      83                 :            : 
      84                 :            :     // Encrypt plaintext.
      85                 :        360 :     std::byte header[HEADER_LEN] = {ignore ? IGNORE_BIT : std::byte{0}};
      86         [ +  - ]:        360 :     m_send_p_cipher->Encrypt(header, contents, aad, output.subspan(LENGTH_LEN));
      87                 :        360 : }
      88                 :            : 
      89                 :          0 : uint32_t BIP324Cipher::DecryptLength(Span<const std::byte> input) noexcept
      90                 :            : {
      91         [ #  # ]:          0 :     assert(input.size() == LENGTH_LEN);
      92                 :            : 
      93                 :            :     std::byte buf[LENGTH_LEN];
      94                 :            :     // Decrypt length
      95         [ #  # ]:          0 :     m_recv_l_cipher->Crypt(input, buf);
      96                 :            :     // Convert to number.
      97                 :          0 :     return uint32_t(buf[0]) + (uint32_t(buf[1]) << 8) + (uint32_t(buf[2]) << 16);
      98                 :            : }
      99                 :            : 
     100                 :          0 : bool BIP324Cipher::Decrypt(Span<const std::byte> input, Span<const std::byte> aad, bool& ignore, Span<std::byte> contents) noexcept
     101                 :            : {
     102         [ #  # ]:          0 :     assert(input.size() + LENGTH_LEN == contents.size() + EXPANSION);
     103                 :            : 
     104                 :            :     std::byte header[HEADER_LEN];
     105   [ #  #  #  # ]:          0 :     if (!m_recv_p_cipher->Decrypt(input, aad, header, contents)) return false;
     106                 :            : 
     107                 :          0 :     ignore = (header[0] & IGNORE_BIT) == IGNORE_BIT;
     108                 :          0 :     return true;
     109                 :          0 : }

Generated by: LCOV version 1.14