Coverage Report

Created: 2024-08-21 05:08

/workdir/bitcoin/src/bip324.cpp
Line
Count
Source (jump to first uncovered line)
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
BIP324Cipher::BIP324Cipher(const CKey& key, Span<const std::byte> ent32) noexcept :
26
0
    m_key(key)
27
0
{
28
0
    m_our_pubkey = m_key.EllSwiftCreate(ent32);
29
0
}
30
31
BIP324Cipher::BIP324Cipher(const CKey& key, const EllSwiftPubKey& pubkey) noexcept :
32
0
    m_key(key), m_our_pubkey(pubkey) {}
33
34
void BIP324Cipher::Initialize(const EllSwiftPubKey& their_pubkey, bool initiator, bool self_decrypt) noexcept
35
0
{
36
    // Determine salt (fixed string + network magic bytes)
37
0
    const auto& message_header = Params().MessageStart();
38
0
    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
0
    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
0
    bool side = (initiator != self_decrypt);
45
0
    CHKDF_HMAC_SHA256_L32 hkdf(UCharCast(ecdh_secret.data()), ecdh_secret.size(), salt);
46
0
    std::array<std::byte, 32> hkdf_32_okm;
47
0
    hkdf.Expand32("initiator_L", UCharCast(hkdf_32_okm.data()));
48
0
    (side ? m_send_l_cipher : m_recv_l_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
  Branch (48:6): [True: 0, False: 0]
49
0
    hkdf.Expand32("initiator_P", UCharCast(hkdf_32_okm.data()));
50
0
    (side ? m_send_p_cipher : m_recv_p_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
  Branch (50:6): [True: 0, False: 0]
51
0
    hkdf.Expand32("responder_L", UCharCast(hkdf_32_okm.data()));
52
0
    (side ? m_recv_l_cipher : m_send_l_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
  Branch (52:6): [True: 0, False: 0]
53
0
    hkdf.Expand32("responder_P", UCharCast(hkdf_32_okm.data()));
54
0
    (side ? m_recv_p_cipher : m_send_p_cipher).emplace(hkdf_32_okm, REKEY_INTERVAL);
  Branch (54:6): [True: 0, False: 0]
55
56
    // Derive garbage terminators from shared secret.
57
0
    hkdf.Expand32("garbage_terminators", UCharCast(hkdf_32_okm.data()));
58
0
    std::copy(std::begin(hkdf_32_okm), std::begin(hkdf_32_okm) + GARBAGE_TERMINATOR_LEN,
59
0
        (initiator ? m_send_garbage_terminator : m_recv_garbage_terminator).begin());
  Branch (59:10): [True: 0, False: 0]
60
0
    std::copy(std::end(hkdf_32_okm) - GARBAGE_TERMINATOR_LEN, std::end(hkdf_32_okm),
61
0
        (initiator ? m_recv_garbage_terminator : m_send_garbage_terminator).begin());
  Branch (61:10): [True: 0, False: 0]
62
63
    // Derive session id from shared secret.
64
0
    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
0
    memory_cleanse(ecdh_secret.data(), ecdh_secret.size());
68
0
    memory_cleanse(hkdf_32_okm.data(), sizeof(hkdf_32_okm));
69
0
    memory_cleanse(&hkdf, sizeof(hkdf));
70
0
    m_key = CKey();
71
0
}
72
73
void BIP324Cipher::Encrypt(Span<const std::byte> contents, Span<const std::byte> aad, bool ignore, Span<std::byte> output) noexcept
74
0
{
75
0
    assert(output.size() == contents.size() + EXPANSION);
76
77
    // Encrypt length.
78
0
    std::byte len[LENGTH_LEN];
79
0
    len[0] = std::byte{(uint8_t)(contents.size() & 0xFF)};
80
0
    len[1] = std::byte{(uint8_t)((contents.size() >> 8) & 0xFF)};
81
0
    len[2] = std::byte{(uint8_t)((contents.size() >> 16) & 0xFF)};
82
0
    m_send_l_cipher->Crypt(len, output.first(LENGTH_LEN));
83
84
    // Encrypt plaintext.
85
0
    std::byte header[HEADER_LEN] = {ignore ? IGNORE_BIT : std::byte{0}};
  Branch (85:37): [True: 0, False: 0]
86
0
    m_send_p_cipher->Encrypt(header, contents, aad, output.subspan(LENGTH_LEN));
87
0
}
88
89
uint32_t BIP324Cipher::DecryptLength(Span<const std::byte> input) noexcept
90
0
{
91
0
    assert(input.size() == LENGTH_LEN);
92
93
0
    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
0
}
99
100
bool BIP324Cipher::Decrypt(Span<const std::byte> input, Span<const std::byte> aad, bool& ignore, Span<std::byte> contents) noexcept
101
0
{
102
0
    assert(input.size() + LENGTH_LEN == contents.size() + EXPANSION);
103
104
0
    std::byte header[HEADER_LEN];
105
0
    if (!m_recv_p_cipher->Decrypt(input, aad, header, contents)) return false;
  Branch (105:9): [True: 0, False: 0]
106
107
0
    ignore = (header[0] & IGNORE_BIT) == IGNORE_BIT;
108
0
    return true;
109
0
}