Sparkplug B C++ Library 1.0.0
Modern C++-23 implementation of Eclipse Sparkplug B 2.2 specification
Loading...
Searching...
No Matches
secure_buffer.hpp
1// include/sparkplug/detail/secure_buffer.hpp
2#pragma once
3
4#include <string>
5#include <string_view>
6#include <utility>
7#include <vector>
8
9namespace sparkplug::detail {
10
11// NUL-terminated buffer for secrets that zeroes its memory on clear, move,
12// and destruction — std::string never scrubs freed memory (CWE-316).
13// The volatile writes cannot be removed by dead-store elimination.
14class SecureBuffer {
15public:
16 SecureBuffer() = default;
17 explicit SecureBuffer(std::string_view value) {
18 assign(value);
19 }
20
21 SecureBuffer(const SecureBuffer&) = delete;
22 SecureBuffer& operator=(const SecureBuffer&) = delete;
23
24 SecureBuffer(SecureBuffer&& other) noexcept : data_(std::move(other.data_)) {
25 other.scrub();
26 other.data_.clear();
27 }
28
29 SecureBuffer& operator=(SecureBuffer&& other) noexcept {
30 if (this != &other) {
31 clear();
32 data_ = std::move(other.data_);
33 other.scrub();
34 other.data_.clear();
35 }
36 return *this;
37 }
38
39 ~SecureBuffer() {
40 scrub();
41 }
42
43 void assign(std::string_view value) {
44 clear();
45 if (!value.empty()) {
46 data_.reserve(value.size() + 1);
47 data_.assign(value.begin(), value.end());
48 data_.push_back('\0');
49 }
50 }
51
52 void clear() {
53 scrub();
54 data_.clear();
55 }
56
57 // Stable pointer valid until the next assign/clear/destruction; nullptr when empty.
58 [[nodiscard]] const char* c_str() const noexcept {
59 return data_.empty() ? nullptr : data_.data();
60 }
61
62 [[nodiscard]] bool empty() const noexcept {
63 return data_.empty();
64 }
65
66 // Zeroes a std::string's storage in place; call before its buffer is freed.
67 static void scrub_string(std::string& s) {
68 if (!s.empty()) {
69 volatile char* p = s.data();
70 for (size_t i = 0; i < s.size(); ++i) {
71 p[i] = 0;
72 }
73 }
74 s.clear();
75 }
76
77private:
78 void scrub() {
79 if (!data_.empty()) {
80 volatile char* p = data_.data();
81 for (size_t i = 0; i < data_.size(); ++i) {
82 p[i] = 0;
83 }
84 }
85 }
86
87 std::vector<char> data_;
88};
89
90} // namespace sparkplug::detail