Botan 3.6.1
Crypto and TLS for C&
Botan::Encrypted_PSK_Database Class Referenceabstract

#include <psk_db.h>

Inheritance diagram for Botan::Encrypted_PSK_Database:
Botan::PSK_Database Botan::Encrypted_PSK_Database_SQL

Public Member Functions

 Encrypted_PSK_Database (const secure_vector< uint8_t > &master_key)
 
secure_vector< uint8_t > get (std::string_view name) const override
 
std::string get_str (std::string_view name) const
 
bool is_encrypted () const override
 
std::set< std::string > list_names () const override
 
void remove (std::string_view name) override
 
void set (std::string_view name, const uint8_t psk[], size_t psk_len) override
 
void set_str (std::string_view name, std::string_view psk)
 
void set_vec (std::string_view name, std::span< const uint8_t > psk)
 
 ~Encrypted_PSK_Database () override
 

Protected Member Functions

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 void kv_set (std::string_view index, std::string_view value)=0
 

Detailed Description

A mixin for an encrypted PSK database.

Both names and values are encrypted using NIST key wrapping (see NIST SP800-38F) with AES-256. First the master key is used with HMAC(SHA-256) to derive two 256-bit keys, one for encrypting all names and the other to key an instance of HMAC(SHA-256). Values are each encrypted under an individual key created by hashing the encrypted name with HMAC. This associates the encrypted key with the name, and prevents an attacker with write access to the data store from taking an encrypted key associated with one entity and copying it to another entity.

Names and PSKs are both padded to the next multiple of 8 bytes, providing some obfuscation of the length.

Subclasses must implement the virtual calls to handle storing and getting raw (base64 encoded) values.

Definition at line 92 of file psk_db.h.

Constructor & Destructor Documentation

◆ Encrypted_PSK_Database()

Botan::Encrypted_PSK_Database::Encrypted_PSK_Database ( const secure_vector< uint8_t > & master_key)

Initializes or opens a PSK database. The master_key is used to secure the contents. It may be of any length. If encrypting PSKs under a passphrase, use a suitable key derivation scheme (such as Argon2id) to derive the secret key. If the master key is lost, all PSKs stored are unrecoverable.

One artifact of the names being encrypted is that is is possible to use multiple different master keys with the same underlying storage. Each master key will be responsible for a subset of the keys. An attacker who knows one of the keys will be able to tell there are other values encrypted under another key, but will not be able to tell how many other master keys are in use.

Parameters
master_keyspecifies the master key used to encrypt all keys and value. It can be of any length, but should be at least 256 bits.

Subkeys for the cryptographic algorithms used are derived from this master key. No key stretching is performed; if encrypting a PSK database using a password, it is recommended to use Argon2id to derive the database master key.

Definition at line 27 of file psk_db.cpp.

27 {
28 m_cipher = BlockCipher::create_or_throw("AES-256");
29 m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
30 m_hmac->set_key(master_key);
31
32 m_cipher->set_key(m_hmac->process("wrap"));
33 m_hmac->set_key(m_hmac->process("hmac"));
34}
static std::unique_ptr< BlockCipher > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition mac.cpp:148

References Botan::BlockCipher::create_or_throw(), and Botan::MessageAuthenticationCode::create_or_throw().

◆ ~Encrypted_PSK_Database()

Botan::Encrypted_PSK_Database::~Encrypted_PSK_Database ( )
overridedefault

Member Function Documentation

◆ get()

secure_vector< uint8_t > Botan::Encrypted_PSK_Database::get ( std::string_view name) const
overridevirtual
Returns
the value associated with the specified name or otherwise throw an exception.

Implements Botan::PSK_Database.

Definition at line 63 of file psk_db.cpp.

63 {
64 const std::vector<uint8_t> wrapped_name =
65 nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher);
66
67 const std::string val_base64 = kv_get(base64_encode(wrapped_name));
68
69 if(val_base64.empty()) {
70 throw Invalid_Argument("Named PSK not located");
71 }
72
73 const secure_vector<uint8_t> val = base64_decode(val_base64);
74
75 auto wrap_cipher = m_cipher->new_object();
76 wrap_cipher->set_key(m_hmac->process(wrapped_name));
77
78 return nist_key_unwrap_padded(val.data(), val.size(), *wrap_cipher);
79}
virtual std::string kv_get(std::string_view index) const =0
std::string name
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition base64.cpp:160
size_t base64_decode(uint8_t out[], const char in[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition base64.cpp:168
std::vector< uint8_t > nist_key_wrap_padded(const uint8_t input[], size_t input_len, const BlockCipher &bc)
secure_vector< uint8_t > nist_key_unwrap_padded(const uint8_t input[], size_t input_len, const BlockCipher &bc)
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition mem_ops.h:273

References Botan::base64_decode(), Botan::base64_encode(), Botan::cast_char_ptr_to_uint8(), kv_get(), name, Botan::nist_key_unwrap_padded(), and Botan::nist_key_wrap_padded().

◆ get_str()

std::string Botan::PSK_Database::get_str ( std::string_view name) const
inherited

Get a PSK in the form of a string (eg if the PSK is a password)

Definition at line 18 of file psk_db.cpp.

18 {
19 secure_vector<uint8_t> psk = this->get(name);
20 return std::string(cast_uint8_ptr_to_char(psk.data()), psk.size());
21}
virtual secure_vector< uint8_t > get(std::string_view name) const =0
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition mem_ops.h:277

References Botan::cast_uint8_ptr_to_char(), and Botan::PSK_Database::get().

◆ is_encrypted()

bool Botan::Encrypted_PSK_Database::is_encrypted ( ) const
inlineoverridevirtual
Returns
true if the values in the PSK database are encrypted. If false, saved values are being stored in plaintext.

Implements Botan::PSK_Database.

Definition at line 128 of file psk_db.h.

128{ return true; }

◆ kv_del()

virtual void Botan::Encrypted_PSK_Database::kv_del ( std::string_view index)
protectedpure virtual

Remove an index

Referenced by remove().

◆ kv_get()

virtual std::string Botan::Encrypted_PSK_Database::kv_get ( std::string_view index) const
protectedpure virtual

Get a value previously saved with kv_set(). Should return an empty string if index is not found.

Referenced by get().

◆ kv_get_all()

virtual std::set< std::string > Botan::Encrypted_PSK_Database::kv_get_all ( ) const
protectedpure virtual

Return all indexes in the table (ie values for which kv_get will return a non-empty string)

Referenced by list_names().

◆ kv_set()

virtual void Botan::Encrypted_PSK_Database::kv_set ( std::string_view index,
std::string_view value )
protectedpure virtual

Save a encrypted (name/value) pair to the database. Both will be base64 encoded strings.

Referenced by set().

◆ list_names()

std::set< std::string > Botan::Encrypted_PSK_Database::list_names ( ) const
overridevirtual
Returns
the set of names for which get() will return a value.

Implements Botan::PSK_Database.

Definition at line 38 of file psk_db.cpp.

38 {
39 const std::set<std::string> encrypted_names = kv_get_all();
40
41 std::set<std::string> names;
42
43 for(const auto& enc_name : encrypted_names) {
44 try {
45 const secure_vector<uint8_t> raw_name = base64_decode(enc_name);
46 const secure_vector<uint8_t> name_bits = nist_key_unwrap_padded(raw_name.data(), raw_name.size(), *m_cipher);
47
48 std::string pt_name(cast_uint8_ptr_to_char(name_bits.data()), name_bits.size());
49 names.insert(pt_name);
50 } catch(Invalid_Authentication_Tag&) {}
51 }
52
53 return names;
54}
virtual std::set< std::string > kv_get_all() const =0

References Botan::base64_decode(), Botan::cast_uint8_ptr_to_char(), kv_get_all(), and Botan::nist_key_unwrap_padded().

◆ remove()

void Botan::Encrypted_PSK_Database::remove ( std::string_view name)
overridevirtual

Remove the PSK with the given name from the database

Implements Botan::PSK_Database.

Definition at line 56 of file psk_db.cpp.

56 {
57 const std::vector<uint8_t> wrapped_name =
58 nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher);
59
60 this->kv_del(base64_encode(wrapped_name));
61}
virtual void kv_del(std::string_view index)=0

References Botan::base64_encode(), Botan::cast_char_ptr_to_uint8(), kv_del(), name, and Botan::nist_key_wrap_padded().

◆ set()

void Botan::Encrypted_PSK_Database::set ( std::string_view name,
const uint8_t psk[],
size_t psk_len )
overridevirtual

Set a value that can later be accessed with get(). If name already exists in the database, the old value will be overwritten.

Implements Botan::PSK_Database.

Definition at line 81 of file psk_db.cpp.

81 {
82 /*
83 * Both as a basic precaution wrt key seperation, and specifically to prevent
84 * cut-and-paste attacks against the database, each PSK is encrypted with a
85 * distinct key which is derived by hashing the wrapped key name with HMAC.
86 */
87 const std::vector<uint8_t> wrapped_name =
88 nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), name.size(), *m_cipher);
89
90 auto wrap_cipher = m_cipher->new_object();
91 wrap_cipher->set_key(m_hmac->process(wrapped_name));
92 const std::vector<uint8_t> wrapped_key = nist_key_wrap_padded(val, len, *wrap_cipher);
93
94 this->kv_set(base64_encode(wrapped_name), base64_encode(wrapped_key));
95}
virtual void kv_set(std::string_view index, std::string_view value)=0

References Botan::base64_encode(), Botan::cast_char_ptr_to_uint8(), kv_set(), name, and Botan::nist_key_wrap_padded().

◆ set_str()

void Botan::PSK_Database::set_str ( std::string_view name,
std::string_view psk )
inherited

Like set() but accepts the PSK as a string (eg for a password).

Definition at line 23 of file psk_db.cpp.

23 {
24 this->set(name, cast_char_ptr_to_uint8(psk.data()), psk.size());
25}
virtual void set(std::string_view name, const uint8_t psk[], size_t psk_len)=0

References Botan::cast_char_ptr_to_uint8(), and Botan::PSK_Database::set().

◆ set_vec()

void Botan::PSK_Database::set_vec ( std::string_view name,
std::span< const uint8_t > psk )
inlineinherited

Like set() but accepting an arbitrary contiguous byte array.

Definition at line 69 of file psk_db.h.

69{ set(name, psk.data(), psk.size()); }

References name.


The documentation for this class was generated from the following files: