Botan 3.6.0
Crypto and TLS for C&
psk_db.h
Go to the documentation of this file.
1/*
2* (C) 2017 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_PSK_DB_H_
8#define BOTAN_PSK_DB_H_
9
10#include <botan/secmem.h>
11#include <memory>
12#include <set>
13#include <span>
14#include <string>
15
16namespace Botan {
17
18class BlockCipher;
19class MessageAuthenticationCode;
20
21/**
22* This is an interface to a generic PSK (pre-shared key) database.
23* It might be implemented as a plaintext storage or via some mechanism
24* that encrypts the keys and/or values.
25*/
27 public:
28 /**
29 * @returns the set of names for which get() will return a value.
30 */
31 virtual std::set<std::string> list_names() const = 0;
32
33 /**
34 * @returns the value associated with the specified @p name or otherwise
35 * throw an exception.
36 */
37 virtual secure_vector<uint8_t> get(std::string_view name) const = 0;
38
39 /**
40 * Set a value that can later be accessed with get().
41 * If name already exists in the database, the old value will be overwritten.
42 */
43 virtual void set(std::string_view name, const uint8_t psk[], size_t psk_len) = 0;
44
45 /**
46 * Remove the PSK with the given @p name from the database
47 */
48 virtual void remove(std::string_view name) = 0;
49
50 /**
51 * @returns true if the values in the PSK database are encrypted. If false,
52 * saved values are being stored in plaintext.
53 */
54 virtual bool is_encrypted() const = 0;
55
56 /**
57 * Get a PSK in the form of a string (eg if the PSK is a password)
58 */
59 std::string get_str(std::string_view name) const;
60
61 /**
62 * Like set() but accepts the PSK as a string (eg for a password).
63 */
64 void set_str(std::string_view name, std::string_view psk);
65
66 /**
67 * Like set() but accepting an arbitrary contiguous byte array.
68 */
69 void set_vec(std::string_view name, std::span<const uint8_t> psk) { set(name, psk.data(), psk.size()); }
70
71 virtual ~PSK_Database() = default;
72};
73
74/**
75* A mixin for an encrypted PSK database.
76*
77* Both names and values are encrypted using NIST key wrapping (see NIST
78* SP800-38F) with AES-256. First the master key is used with HMAC(SHA-256) to
79* derive two 256-bit keys, one for encrypting all names and the other to key an
80* instance of HMAC(SHA-256). Values are each encrypted under an individual key
81* created by hashing the encrypted name with HMAC. This associates the encrypted
82* key with the name, and prevents an attacker with write access to the data
83* store from taking an encrypted key associated with one entity and copying it
84* to another entity.
85*
86* Names and PSKs are both padded to the next multiple of 8 bytes, providing some
87* obfuscation of the length.
88*
89* Subclasses must implement the virtual calls to handle storing and getting raw
90* (base64 encoded) values.
91*/
93 public:
94 /**
95 * Initializes or opens a PSK database. The @p master_key is used to secure
96 * the contents. It may be of any length. If encrypting PSKs under a
97 * passphrase, use a suitable key derivation scheme (such as Argon2id) to
98 * derive the secret key. If the master key is lost, all PSKs stored are
99 * unrecoverable.
100 *
101 * One artifact of the names being encrypted is that is is possible to use
102 * multiple different master keys with the same underlying storage. Each
103 * master key will be responsible for a subset of the keys. An attacker who
104 * knows one of the keys will be able to tell there are other values
105 * encrypted under another key, but will not be able to tell how many other
106 * master keys are in use.
107 *
108 * @param master_key specifies the master key used to encrypt all
109 * keys and value. It can be of any length, but should be at least 256 bits.
110 *
111 * Subkeys for the cryptographic algorithms used are derived from this
112 * master key. No key stretching is performed; if encrypting a PSK database
113 * using a password, it is recommended to use Argon2id to derive the database
114 * master key.
115 */
117
119
120 std::set<std::string> list_names() const override;
121
122 secure_vector<uint8_t> get(std::string_view name) const override;
123
124 void set(std::string_view name, const uint8_t psk[], size_t psk_len) override;
125
126 void remove(std::string_view name) override;
127
128 bool is_encrypted() const override { return true; }
129
130 protected:
131 /**
132 * Save a encrypted (name/value) pair to the database. Both will be base64
133 * encoded strings.
134 */
135 virtual void kv_set(std::string_view index, std::string_view value) = 0;
136
137 /**
138 * Get a value previously saved with kv_set(). Should return an empty
139 * string if @p index is not found.
140 */
141 virtual std::string kv_get(std::string_view index) const = 0;
142
143 /**
144 * Remove an @p index
145 */
146 virtual void kv_del(std::string_view index) = 0;
147
148 /**
149 * Return all indexes in the table (ie values for which ``kv_get`` will
150 * return a non-empty string)
151 */
152 virtual std::set<std::string> kv_get_all() const = 0;
153
154 private:
155 std::unique_ptr<BlockCipher> m_cipher;
156 std::unique_ptr<MessageAuthenticationCode> m_hmac;
157 secure_vector<uint8_t> m_wrap_key;
158};
159
160class SQL_Database;
161
163 public:
164 /**
165 * Creates or uses the named table in @p db. The SQL schema of the table is
166 * `(psk_name TEXT PRIMARY KEY, psk_value TEXT)`.
167 */
169 std::shared_ptr<SQL_Database> db,
170 std::string_view table_name);
171
173
174 private:
175 void kv_set(std::string_view index, std::string_view value) override;
176 std::string kv_get(std::string_view index) const override;
177 void kv_del(std::string_view index) override;
178 std::set<std::string> kv_get_all() const override;
179
180 std::shared_ptr<SQL_Database> m_db;
181 const std::string m_table_name;
182};
183
184} // namespace Botan
185
186#endif
bool is_encrypted() const override
Definition psk_db.h:128
virtual void kv_set(std::string_view index, std::string_view value)=0
virtual void kv_del(std::string_view index)=0
virtual std::string kv_get(std::string_view index) const =0
virtual std::set< std::string > kv_get_all() const =0
virtual std::set< std::string > list_names() const =0
virtual void set(std::string_view name, const uint8_t psk[], size_t psk_len)=0
void set_vec(std::string_view name, std::span< const uint8_t > psk)
Definition psk_db.h:69
virtual bool is_encrypted() const =0
virtual ~PSK_Database()=default
virtual secure_vector< uint8_t > get(std::string_view name) const =0
virtual void remove(std::string_view name)=0
std::string name
#define BOTAN_PUBLIC_API(maj, min)
Definition compiler.h:31
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61