Repository: randombit/botan
Pull request #3752 (2023-10-11 13:18:18)

Split out allocator helpers to allocator.h
See #3715 for context

coveralls: 
[![Coverage Status](https://coveralls.io/builds/63416950/badge)](https://coveralls.io/builds/63416950)

coverage: 91.714% (-0.004%) from 91.718% when pulling **a6091cf7dc8ff1b92d98e3e8603ba27b6c037776 on jack/allocator-helper** into **0981814435c005c02ebfdc312642c1414492efd1 on master**.


Patch:
diff --git a/src/cli/sandbox.cpp b/src/cli/sandbox.cpp
index 783fb5f3b..f9e5c0fdb 100644
--- a/src/cli/sandbox.cpp
+++ b/src/cli/sandbox.cpp
@@ -5,7 +5,7 @@
 */
 
 #include "sandbox.h"
-#include <botan/mem_ops.h>
+#include <botan/allocator.h>
 
 #if defined(BOTAN_TARGET_OS_HAS_PLEDGE)
    #include <unistd.h>
diff --git a/src/cli/tss.cpp b/src/cli/tss.cpp
index 7c6561ecb..60e284ccf 100644
--- a/src/cli/tss.cpp
+++ b/src/cli/tss.cpp
@@ -8,6 +8,7 @@
 
 #if defined(BOTAN_HAS_THRESHOLD_SECRET_SHARING)
    #include <botan/hex.h>
+   #include <botan/mem_ops.h>
    #include <botan/rng.h>
    #include <botan/tss.h>
    #include <botan/internal/fmt.h>
diff --git a/src/lib/asn1/asn1_obj.cpp b/src/lib/asn1/asn1_obj.cpp
index f2ffe2e8a..0ac7c290b 100644
--- a/src/lib/asn1/asn1_obj.cpp
+++ b/src/lib/asn1/asn1_obj.cpp
@@ -9,6 +9,7 @@
 
 #include <botan/data_src.h>
 #include <botan/der_enc.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/fmt.h>
 #include <botan/internal/stl_util.h>
 #include <sstream>
diff --git a/src/lib/asn1/ber_dec.h b/src/lib/asn1/ber_dec.h
index 8cdbb1ca0..2f6cecd46 100644
--- a/src/lib/asn1/ber_dec.h
+++ b/src/lib/asn1/ber_dec.h
@@ -10,6 +10,7 @@
 
 #include <botan/asn1_obj.h>
 #include <botan/data_src.h>
+#include <botan/mem_ops.h>
 
 namespace Botan {
 
diff --git a/src/lib/base/buf_comp.h b/src/lib/base/buf_comp.h
index 1b8848093..256c4bd2e 100644
--- a/src/lib/base/buf_comp.h
+++ b/src/lib/base/buf_comp.h
@@ -9,6 +9,7 @@
 #define BOTAN_BUFFERED_COMPUTATION_H_
 
 #include <botan/concepts.h>
+#include <botan/mem_ops.h>
 #include <botan/secmem.h>
 #include <span>
 #include <string_view>
diff --git a/src/lib/base/secmem.h b/src/lib/base/secmem.h
index 4f257331c..284c5ae61 100644
--- a/src/lib/base/secmem.h
+++ b/src/lib/base/secmem.h
@@ -8,8 +8,8 @@
 #ifndef BOTAN_SECURE_MEMORY_BUFFERS_H_
 #define BOTAN_SECURE_MEMORY_BUFFERS_H_
 
-#include <botan/mem_ops.h>  // IWYU pragma: export
-#include <botan/types.h>    // IWYU pragma: export
+#include <botan/allocator.h>
+#include <botan/types.h>  // IWYU pragma: export
 #include <algorithm>
 #include <deque>
 #include <type_traits>
@@ -106,7 +106,7 @@ std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, const std::pair<T*
 */
 template <typename T, typename Alloc>
 void zeroise(std::vector<T, Alloc>& vec) {
-   clear_mem(vec.data(), vec.size());
+   std::fill(vec.begin(), vec.end(), static_cast<T>(0));
 }
 
 /**
diff --git a/src/lib/base/symkey.cpp b/src/lib/base/symkey.cpp
index 8bc10d920..5c910947e 100644
--- a/src/lib/base/symkey.cpp
+++ b/src/lib/base/symkey.cpp
@@ -8,6 +8,7 @@
 #include <botan/symkey.h>
 
 #include <botan/hex.h>
+#include <botan/mem_ops.h>
 #include <botan/rng.h>
 #include <algorithm>
 
diff --git a/src/lib/block/block_cipher.h b/src/lib/block/block_cipher.h
index 2b4752d7f..693dacb8c 100644
--- a/src/lib/block/block_cipher.h
+++ b/src/lib/block/block_cipher.h
@@ -8,6 +8,7 @@
 #ifndef BOTAN_BLOCK_CIPHER_H_
 #define BOTAN_BLOCK_CIPHER_H_
 
+#include <botan/mem_ops.h>
 #include <botan/sym_algo.h>
 #include <memory>
 #include <string>
diff --git a/src/lib/compat/sodium/sodium_aead.cpp b/src/lib/compat/sodium/sodium_aead.cpp
index e1eb6b3c8..9ecbc6d18 100644
--- a/src/lib/compat/sodium/sodium_aead.cpp
+++ b/src/lib/compat/sodium/sodium_aead.cpp
@@ -7,6 +7,7 @@
 #include <botan/sodium.h>
 
 #include <botan/aead.h>
+#include <botan/mem_ops.h>
 
 namespace Botan {
 
diff --git a/src/lib/compat/sodium/sodium_box.cpp b/src/lib/compat/sodium/sodium_box.cpp
index f56dd046f..fb3405a8b 100644
--- a/src/lib/compat/sodium/sodium_box.cpp
+++ b/src/lib/compat/sodium/sodium_box.cpp
@@ -6,6 +6,7 @@
 
 #include <botan/sodium.h>
 
+#include <botan/mem_ops.h>
 #include <botan/secmem.h>
 
 namespace Botan {
diff --git a/src/lib/compression/compress_utils.cpp b/src/lib/compression/compress_utils.cpp
index 67d98ce68..eac5add84 100644
--- a/src/lib/compression/compress_utils.cpp
+++ b/src/lib/compression/compress_utils.cpp
@@ -8,6 +8,7 @@
 #include <botan/internal/compress_utils.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/fmt.h>
 #include <botan/internal/safeint.h>
 #include <cstdlib>
diff --git a/src/lib/compression/compress_utils.h b/src/lib/compression/compress_utils.h
index 7b9fa581b..a3a61ef9d 100644
--- a/src/lib/compression/compress_utils.h
+++ b/src/lib/compression/compress_utils.h
@@ -9,6 +9,8 @@
 #define BOTAN_COMPRESSION_UTILS_H_
 
 #include <botan/compression.h>
+
+#include <botan/mem_ops.h>
 #include <memory>
 #include <unordered_map>
 
diff --git a/src/lib/filters/data_snk.cpp b/src/lib/filters/data_snk.cpp
index 110f82e75..0f639f43c 100644
--- a/src/lib/filters/data_snk.cpp
+++ b/src/lib/filters/data_snk.cpp
@@ -10,6 +10,7 @@
 #include <botan/data_snk.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/fmt.h>
 #include <ostream>
 
diff --git a/src/lib/filters/pipe.cpp b/src/lib/filters/pipe.cpp
index 855448a2f..ac9b26224 100644
--- a/src/lib/filters/pipe.cpp
+++ b/src/lib/filters/pipe.cpp
@@ -7,6 +7,7 @@
 
 #include <botan/pipe.h>
 
+#include <botan/mem_ops.h>
 #include <botan/internal/fmt.h>
 #include <botan/internal/out_buf.h>
 #include <botan/internal/secqueue.h>
diff --git a/src/lib/filters/pipe_io.cpp b/src/lib/filters/pipe_io.cpp
index 9599e9798..7ab7130bf 100644
--- a/src/lib/filters/pipe_io.cpp
+++ b/src/lib/filters/pipe_io.cpp
@@ -6,6 +6,8 @@
 */
 
 #include <botan/pipe.h>
+
+#include <botan/mem_ops.h>
 #include <istream>
 #include <ostream>
 
diff --git a/src/lib/filters/pipe_rw.cpp b/src/lib/filters/pipe_rw.cpp
index 6e0cf63a0..fbfa0e043 100644
--- a/src/lib/filters/pipe_rw.cpp
+++ b/src/lib/filters/pipe_rw.cpp
@@ -9,6 +9,7 @@
 #include <botan/pipe.h>
 
 #include <botan/filter.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/out_buf.h>
 
 namespace Botan {
diff --git a/src/lib/filters/secqueue.cpp b/src/lib/filters/secqueue.cpp
index 942d0a30c..558650e17 100644
--- a/src/lib/filters/secqueue.cpp
+++ b/src/lib/filters/secqueue.cpp
@@ -7,6 +7,8 @@
 */
 
 #include <botan/internal/secqueue.h>
+
+#include <botan/mem_ops.h>
 #include <algorithm>
 
 namespace Botan {
diff --git a/src/lib/kdf/kdf.h b/src/lib/kdf/kdf.h
index 7645728f5..d6e0e8bf1 100644
--- a/src/lib/kdf/kdf.h
+++ b/src/lib/kdf/kdf.h
@@ -10,6 +10,7 @@
 
 #include <botan/concepts.h>
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/secmem.h>
 #include <span>
 #include <string>
diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h
index 23febfac5..95cd91f59 100644
--- a/src/lib/math/bigint/bigint.h
+++ b/src/lib/math/bigint/bigint.h
@@ -10,6 +10,7 @@
 #define BOTAN_BIGINT_H_
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/secmem.h>
 #include <botan/types.h>
 #include <iosfwd>
diff --git a/src/lib/passhash/argon2fmt/argon2fmt.cpp b/src/lib/passhash/argon2fmt/argon2fmt.cpp
index 40c6bce97..aa771ac50 100644
--- a/src/lib/passhash/argon2fmt/argon2fmt.cpp
+++ b/src/lib/passhash/argon2fmt/argon2fmt.cpp
@@ -7,6 +7,7 @@
 #include <botan/argon2fmt.h>
 
 #include <botan/base64.h>
+#include <botan/mem_ops.h>
 #include <botan/pwdhash.h>
 #include <botan/rng.h>
 #include <botan/internal/ct_utils.h>
diff --git a/src/lib/permutations/keccak_perm/keccak_perm.h b/src/lib/permutations/keccak_perm/keccak_perm.h
index 858b1c4b5..6bfe893de 100644
--- a/src/lib/permutations/keccak_perm/keccak_perm.h
+++ b/src/lib/permutations/keccak_perm/keccak_perm.h
@@ -11,6 +11,7 @@
 #define BOTAN_KECCAK_PERM_H_
 
 #include <botan/secmem.h>
+#include <span>
 #include <string>
 
 namespace Botan {
diff --git a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
index d58b2750e..4fc9d33ba 100644
--- a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
+++ b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
@@ -8,6 +8,7 @@
 #include <botan/internal/eme_pkcs.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/rng.h>
 #include <botan/internal/ct_utils.h>
 #include <botan/internal/stl_util.h>
diff --git a/src/lib/pk_pad/emsa_raw/emsa_raw.cpp b/src/lib/pk_pad/emsa_raw/emsa_raw.cpp
index 9eb5ae995..e8acfb05a 100644
--- a/src/lib/pk_pad/emsa_raw/emsa_raw.cpp
+++ b/src/lib/pk_pad/emsa_raw/emsa_raw.cpp
@@ -8,6 +8,7 @@
 #include <botan/internal/emsa_raw.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/ct_utils.h>
 
 namespace Botan {
diff --git a/src/lib/prov/commoncrypto/commoncrypto_mode.cpp b/src/lib/prov/commoncrypto/commoncrypto_mode.cpp
index ccdb39d34..c777e87e0 100644
--- a/src/lib/prov/commoncrypto/commoncrypto_mode.cpp
+++ b/src/lib/prov/commoncrypto/commoncrypto_mode.cpp
@@ -8,6 +8,7 @@
 #include <botan/internal/commoncrypto.h>
 
 #include <botan/cipher_mode.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/commoncrypto_utils.h>
 #include <botan/internal/rounding.h>
 
diff --git a/src/lib/prov/commoncrypto/commoncrypto_utils.cpp b/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
index 780c5b6bf..f04e4d95e 100644
--- a/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
+++ b/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
@@ -8,6 +8,7 @@
 #include <botan/internal/commoncrypto.h>
 
 #include <botan/cipher_mode.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/commoncrypto_utils.h>
 #include <botan/internal/fmt.h>
 #include <botan/internal/parsing.h>
diff --git a/src/lib/prov/pkcs11/p11_mechanism.h b/src/lib/prov/pkcs11/p11_mechanism.h
index 5958ee663..96ea0dc15 100644
--- a/src/lib/prov/pkcs11/p11_mechanism.h
+++ b/src/lib/prov/pkcs11/p11_mechanism.h
@@ -11,6 +11,7 @@
 
 #include <botan/p11.h>
 
+#include <botan/mem_ops.h>
 #include <memory>
 #include <string>
 #include <utility>
diff --git a/src/lib/psk_db/psk_db.cpp b/src/lib/psk_db/psk_db.cpp
index 56fd0f464..c24327d18 100644
--- a/src/lib/psk_db/psk_db.cpp
+++ b/src/lib/psk_db/psk_db.cpp
@@ -10,10 +10,20 @@
 #include <botan/block_cipher.h>
 #include <botan/exceptn.h>
 #include <botan/mac.h>
+#include <botan/mem_ops.h>
 #include <botan/nist_keywrap.h>
 
 namespace Botan {
 
+std::string PSK_Database::get_str(std::string_view name) const {
+   secure_vector<uint8_t> psk = this->get(name);
+   return std::string(cast_uint8_ptr_to_char(psk.data()), psk.size());
+}
+
+void PSK_Database::set_str(std::string_view name, std::string_view psk) {
+   this->set(name, cast_char_ptr_to_uint8(psk.data()), psk.size());
+}
+
 Encrypted_PSK_Database::Encrypted_PSK_Database(const secure_vector<uint8_t>& master_key) {
    m_cipher = BlockCipher::create_or_throw("AES-256");
    m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
diff --git a/src/lib/psk_db/psk_db.h b/src/lib/psk_db/psk_db.h
index 8484490bd..eccdf51a3 100644
--- a/src/lib/psk_db/psk_db.h
+++ b/src/lib/psk_db/psk_db.h
@@ -55,14 +55,9 @@ class BOTAN_PUBLIC_API(2, 4) PSK_Database {
       /**
       * Get a PSK in the form of a string (eg if the PSK is a password)
       */
-      std::string get_str(std::string_view name) const {
-         secure_vector<uint8_t> psk = get(name);
-         return std::string(cast_uint8_ptr_to_char(psk.data()), psk.size());
-      }
+      std::string get_str(std::string_view name) const;
 
-      void set_str(std::string_view name, std::string_view psk) {
-         set(name, cast_char_ptr_to_uint8(psk.data()), psk.size());
-      }
+      void set_str(std::string_view name, std::string_view psk);
 
       template <typename Alloc>
       void set_vec(std::string_view name, const std::vector<uint8_t, Alloc>& psk) {
diff --git a/src/lib/pubkey/mce/goppa_code.cpp b/src/lib/pubkey/mce/goppa_code.cpp
index 88635b4a5..a8823f3ae 100644
--- a/src/lib/pubkey/mce/goppa_code.cpp
+++ b/src/lib/pubkey/mce/goppa_code.cpp
@@ -11,6 +11,7 @@
 
 #include <botan/internal/mce_internal.h>
 
+#include <botan/mem_ops.h>
 #include <botan/internal/code_based_util.h>
 
 namespace Botan {
diff --git a/src/lib/pubkey/mce/mceliece.cpp b/src/lib/pubkey/mce/mceliece.cpp
index d1aa15e4d..087a7915d 100644
--- a/src/lib/pubkey/mce/mceliece.cpp
+++ b/src/lib/pubkey/mce/mceliece.cpp
@@ -12,6 +12,7 @@
 #include <botan/internal/mce_internal.h>
 
 #include <botan/mceliece.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/bit_ops.h>
 #include <botan/internal/code_based_util.h>
 
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index ba37b2cb7..35c970b0e 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -9,6 +9,7 @@
 #include <botan/ber_dec.h>
 #include <botan/bigint.h>
 #include <botan/der_enc.h>
+#include <botan/mem_ops.h>
 #include <botan/rng.h>
 #include <botan/internal/ct_utils.h>
 #include <botan/internal/fmt.h>
@@ -214,6 +215,19 @@ size_t PK_Key_Agreement::agreed_value_size() const {
    return m_op->agreed_value_size();
 }
 
+SymmetricKey PK_Key_Agreement::derive_key(size_t key_len,
+                                          const uint8_t in[],
+                                          size_t in_len,
+                                          std::string_view params) const {
+   return this->derive_key(key_len, in, in_len, cast_char_ptr_to_uint8(params.data()), params.length());
+}
+
+SymmetricKey PK_Key_Agreement::derive_key(size_t key_len,
+                                          const std::span<const uint8_t> in,
+                                          std::string_view params) const {
+   return this->derive_key(key_len, in.data(), in.size(), cast_char_ptr_to_uint8(params.data()), params.length());
+}
+
 SymmetricKey PK_Key_Agreement::derive_key(
    size_t key_len, const uint8_t in[], size_t in_len, const uint8_t salt[], size_t salt_len) const {
    return SymmetricKey(m_op->agree(key_len, in, in_len, salt, salt_len));
@@ -257,6 +271,10 @@ PK_Signer::~PK_Signer() = default;
 PK_Signer::PK_Signer(PK_Signer&&) noexcept = default;
 PK_Signer& PK_Signer::operator=(PK_Signer&&) noexcept = default;
 
+void PK_Signer::update(std::string_view in) {
+   this->update(cast_char_ptr_to_uint8(in.data()), in.size());
+}
+
 void PK_Signer::update(const uint8_t in[], size_t length) {
    m_op->update(in, length);
 }
@@ -352,6 +370,10 @@ bool PK_Verifier::verify_message(const uint8_t msg[], size_t msg_length, const u
    return check_signature(sig, sig_length);
 }
 
+void PK_Verifier::update(std::string_view in) {
+   this->update(cast_char_ptr_to_uint8(in.data()), in.size());
+}
+
 void PK_Verifier::update(const uint8_t in[], size_t length) {
    m_op->update(in, length);
 }
diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h
index 5da1226bd..5f6d68022 100644
--- a/src/lib/pubkey/pubkey.h
+++ b/src/lib/pubkey/pubkey.h
@@ -221,7 +221,7 @@ class BOTAN_PUBLIC_API(2, 0) PK_Signer final {
       * Add a message part.
       * @param in the message part to add
       */
-      void update(std::string_view in) { update(cast_char_ptr_to_uint8(in.data()), in.size()); }
+      void update(std::string_view in);
 
       /**
       * Get the signature of the so far processed message (provided by the
@@ -352,7 +352,7 @@ class BOTAN_PUBLIC_API(2, 0) PK_Verifier final {
       * Add a message part of the message corresponding to the
       * signature to be verified.
       */
-      void update(std::string_view in) { update(cast_char_ptr_to_uint8(in.data()), in.size()); }
+      void update(std::string_view in);
 
       /**
       * Check the signature of the buffered message, i.e. the one build
@@ -448,9 +448,7 @@ class BOTAN_PUBLIC_API(2, 0) PK_Key_Agreement final {
       * @param in_len the length of in in bytes
       * @param params extra derivation params
       */
-      SymmetricKey derive_key(size_t key_len, const uint8_t in[], size_t in_len, std::string_view params = "") const {
-         return derive_key(key_len, in, in_len, cast_char_ptr_to_uint8(params.data()), params.length());
-      }
+      SymmetricKey derive_key(size_t key_len, const uint8_t in[], size_t in_len, std::string_view params = "") const;
 
       /**
       * Perform Key Agreement Operation
@@ -458,9 +456,7 @@ class BOTAN_PUBLIC_API(2, 0) PK_Key_Agreement final {
       * @param in the other parties key
       * @param params extra derivation params
       */
-      SymmetricKey derive_key(size_t key_len, const std::span<const uint8_t> in, std::string_view params = "") const {
-         return derive_key(key_len, in.data(), in.size(), cast_char_ptr_to_uint8(params.data()), params.length());
-      }
+      SymmetricKey derive_key(size_t key_len, const std::span<const uint8_t> in, std::string_view params = "") const;
 
       /**
       * Return the underlying size of the value that is agreed.
diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp
index 45ec020ff..99536db95 100644
--- a/src/lib/stream/rc4/rc4.cpp
+++ b/src/lib/stream/rc4/rc4.cpp
@@ -8,6 +8,7 @@
 #include <botan/internal/rc4.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 
 namespace Botan {
 
diff --git a/src/lib/stream/shake_cipher/shake_cipher.cpp b/src/lib/stream/shake_cipher/shake_cipher.cpp
index 3e47fc3bd..2a6fd23b7 100644
--- a/src/lib/stream/shake_cipher/shake_cipher.cpp
+++ b/src/lib/stream/shake_cipher/shake_cipher.cpp
@@ -9,6 +9,7 @@
 #include <botan/internal/shake_cipher.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 
 namespace Botan {
 
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
index 4eb6d1076..470396d86 100644
--- a/src/lib/stream/stream_cipher.cpp
+++ b/src/lib/stream/stream_cipher.cpp
@@ -133,4 +133,9 @@ size_t StreamCipher::default_iv_length() const {
    return 0;
 }
 
+void StreamCipher::generate_keystream(uint8_t out[], size_t len) {
+   clear_mem(out, len);
+   cipher1(out, len);
+}
+
 }  // namespace Botan
diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h
index a725d7693..e59575c9f 100644
--- a/src/lib/stream/stream_cipher.h
+++ b/src/lib/stream/stream_cipher.h
@@ -207,10 +207,7 @@ class BOTAN_PUBLIC_API(2, 0) StreamCipher : public SymmetricAlgorithm {
       /**
       * Write keystream bytes to a buffer
       */
-      virtual void generate_keystream(uint8_t out[], size_t len) {
-         clear_mem(out, len);
-         cipher1(out, len);
-      }
+      virtual void generate_keystream(uint8_t out[], size_t len);
 
       /**
       * Resync the cipher using the IV
diff --git a/src/lib/utils/alignment_buffer.h b/src/lib/utils/alignment_buffer.h
index 64b7bec1c..1da3b55f2 100644
--- a/src/lib/utils/alignment_buffer.h
+++ b/src/lib/utils/alignment_buffer.h
@@ -10,6 +10,7 @@
 #define BOTAN_ALIGNMENT_BUFFER_H_
 
 #include <botan/concepts.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/stl_util.h>
 
 #include <array>
diff --git a/src/lib/utils/allocator.cpp b/src/lib/utils/allocator.cpp
new file mode 100644
index 000000000..512e830a3
--- /dev/null
+++ b/src/lib/utils/allocator.cpp
@@ -0,0 +1,70 @@
+/*
+* (C) 2017,2023 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/allocator.h>
+
+#include <botan/mem_ops.h>
+#include <botan/internal/safeint.h>
+#include <cstdlib>
+#include <new>
+
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+   #include <botan/internal/locking_allocator.h>
+#endif
+
+namespace Botan {
+
+BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size) {
+   if(elems == 0 || elem_size == 0) {
+      return nullptr;
+   }
+
+   // Some calloc implementations do not check for overflow (?!?)
+
+   if(!BOTAN_CHECKED_MUL(elems, elem_size).has_value()) {
+      throw std::bad_alloc();
+   }
+
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+   if(void* p = mlock_allocator::instance().allocate(elems, elem_size)) {
+      return p;
+   }
+#endif
+
+#if defined(BOTAN_TARGET_OS_HAS_ALLOC_CONCEAL)
+   void* ptr = ::calloc_conceal(elems, elem_size);
+#else
+   void* ptr = std::calloc(elems, elem_size);  // NOLINT(*-no-malloc)
+#endif
+   if(!ptr) {
+      [[unlikely]] throw std::bad_alloc();
+   }
+   return ptr;
+}
+
+void deallocate_memory(void* p, size_t elems, size_t elem_size) {
+   if(p == nullptr) {
+      [[unlikely]] return;
+   }
+
+   secure_scrub_memory(p, elems * elem_size);
+
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+   if(mlock_allocator::instance().deallocate(p, elems, elem_size)) {
+      return;
+   }
+#endif
+
+   std::free(p);  // NOLINT(*-no-malloc)
+}
+
+void initialize_allocator() {
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+   mlock_allocator::instance();
+#endif
+}
+
+}  // namespace Botan
diff --git a/src/lib/utils/allocator.h b/src/lib/utils/allocator.h
new file mode 100644
index 000000000..6e5392f48
--- /dev/null
+++ b/src/lib/utils/allocator.h
@@ -0,0 +1,45 @@
+/*
+* (C) 2023 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ALLOCATOR_HELPERS_H_
+#define BOTAN_ALLOCATOR_HELPERS_H_
+
+#include <botan/types.h>
+#include <cstring>
+
+namespace Botan {
+
+/**
+* Allocate a memory buffer by some method. This should only be used for
+* primitive types (uint8_t, uint32_t, etc).
+*
+* @param elems the number of elements
+* @param elem_size the size of each element
+* @return pointer to allocated and zeroed memory, or throw std::bad_alloc on failure
+*/
+BOTAN_PUBLIC_API(2, 3) BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size);
+
+/**
+* Free a pointer returned by allocate_memory
+* @param p the pointer returned by allocate_memory
+* @param elems the number of elements, as passed to allocate_memory
+* @param elem_size the size of each element, as passed to allocate_memory
+*/
+BOTAN_PUBLIC_API(2, 3) void deallocate_memory(void* p, size_t elems, size_t elem_size);
+
+/**
+* Ensure the allocator is initialized
+*/
+void BOTAN_UNSTABLE_API initialize_allocator();
+
+class Allocator_Initializer final {
+   public:
+      Allocator_Initializer() { initialize_allocator(); }
+};
+
+}  // namespace Botan
+
+#endif
diff --git a/src/lib/utils/codec_base.h b/src/lib/utils/codec_base.h
index 36261c39a..8eae8f674 100644
--- a/src/lib/utils/codec_base.h
+++ b/src/lib/utils/codec_base.h
@@ -10,7 +10,7 @@
 #define BOTAN_BASE_CODEC_H_
 
 #include <botan/exceptn.h>
-#include <botan/secmem.h>
+#include <botan/mem_ops.h>
 #include <string>
 #include <vector>
 
@@ -129,8 +129,8 @@ size_t base_decode(Base&& base,
    for(size_t i = 0; i != input_length; ++i) {
       const uint8_t bin = base.lookup_binary_value(input[i]);
 
-      if(base.check_bad_char(bin, input[i], ignore_ws))  // May throw Invalid_Argument
-      {
+      // This call might throw Invalid_Argument
+      if(base.check_bad_char(bin, input[i], ignore_ws)) {
          decode_buf[decode_buf_pos] = bin;
          ++decode_buf_pos;
       }
diff --git a/src/lib/utils/data_src.cpp b/src/lib/utils/data_src.cpp
index 11d8167d2..6a83e60fa 100644
--- a/src/lib/utils/data_src.cpp
+++ b/src/lib/utils/data_src.cpp
@@ -9,6 +9,7 @@
 #include <botan/data_src.h>
 
 #include <botan/exceptn.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/fmt.h>
 #include <algorithm>
 #include <istream>
diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp
index d39825308..4c2dd35bd 100644
--- a/src/lib/utils/http_util/http_util.cpp
+++ b/src/lib/utils/http_util/http_util.cpp
@@ -9,6 +9,7 @@
 #include <botan/internal/http_util.h>
 
 #include <botan/hex.h>
+#include <botan/mem_ops.h>
 #include <botan/internal/fmt.h>
 #include <botan/internal/os_utils.h>
 #include <botan/internal/parsing.h>
diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt
index 20b874b7d..11374c0c8 100644
--- a/src/lib/utils/info.txt
+++ b/src/lib/utils/info.txt
@@ -11,6 +11,7 @@ load_on always
 
 <header:public>
 assert.h
+allocator.h
 compiler.h
 concepts.h
 data_src.h
diff --git a/src/lib/utils/mem_ops.cpp b/src/lib/utils/mem_ops.cpp
index 9abb2473a..9b0254946 100644
--- a/src/lib/utils/mem_ops.cpp
+++ b/src/lib/utils/mem_ops.cpp
@@ -7,66 +7,9 @@
 #include <botan/mem_ops.h>
 
 #include <botan/internal/ct_utils.h>
-#include <botan/internal/safeint.h>
-#include <cstdlib>
-#include <new>
-
-#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
-   #include <botan/internal/locking_allocator.h>
-#endif
 
 namespace Botan {
 
-BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size) {
-   if(elems == 0 || elem_size == 0) {
-      return nullptr;
-   }
-
-   // Some calloc implementations do not check for overflow (?!?)
-
-   if(!BOTAN_CHECKED_MUL(elems, elem_size).has_value()) {
-      throw std::bad_alloc();
-   }
-
-#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
-   if(void* p = mlock_allocator::instance().allocate(elems, elem_size)) {
-      return p;
-   }
-#endif
-
-#if defined(BOTAN_TARGET_OS_HAS_ALLOC_CONCEAL)
-   void* ptr = ::calloc_conceal(elems, elem_size);
-#else
-   void* ptr = std::calloc(elems, elem_size);  // NOLINT(*-no-malloc)
-#endif
-   if(!ptr) {
-      [[unlikely]] throw std::bad_alloc();
-   }
-   return ptr;
-}
-
-void deallocate_memory(void* p, size_t elems, size_t elem_size) {
-   if(p == nullptr) {
-      [[unlikely]] return;
-   }
-
-   secure_scrub_memory(p, elems * elem_size);
-
-#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
-   if(mlock_allocator::instance().deallocate(p, elems, elem_size)) {
-      return;
-   }
-#endif
-
-   std::free(p);  // NOLINT(*-no-malloc)
-}
-
-void initialize_allocator() {
-#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
-   mlock_allocator::instance();
-#endif
-}
-
 uint8_t ct_compare_u8(const uint8_t x[], const uint8_t y[], size_t len) {
    return CT::is_equal(x, y, len).value();
 }
diff --git a/src/lib/utils/mem_ops.h b/src/lib/utils/mem_ops.h
index f59098e7a..d1be40bf1 100644
--- a/src/lib/utils/mem_ops.h
+++ b/src/lib/utils/mem_ops.h
@@ -14,35 +14,18 @@
 #include <type_traits>
 #include <vector>
 
-namespace Botan {
-
-/**
-* Allocate a memory buffer by some method. This should only be used for
-* primitive types (uint8_t, uint32_t, etc).
-*
-* @param elems the number of elements
-* @param elem_size the size of each element
-* @return pointer to allocated and zeroed memory, or throw std::bad_alloc on failure
-*/
-BOTAN_PUBLIC_API(2, 3) BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size);
-
-/**
-* Free a pointer returned by allocate_memory
-* @param p the pointer returned by allocate_memory
-* @param elems the number of elements, as passed to allocate_memory
-* @param elem_size the size of each element, as passed to allocate_memory
-*/
-BOTAN_PUBLIC_API(2, 3) void deallocate_memory(void* p, size_t elems, size_t elem_size);
+/*
+The header mem_ops.h previously included the contents of allocator.h
 
-/**
-* Ensure the allocator is initialized
+Library code should always include allocator.h to see these
+declarations; however when we are not building the library continue to
+include the header here to avoid breaking application code.
 */
-void BOTAN_UNSTABLE_API initialize_allocator();
+#if !defined(BOTAN_IS_BEING_BUILT)
+   #include <botan/allocator.h>
+#endif
 
-class Allocator_Initializer final {
-   public:
-      Allocator_Initializer() { initialize_allocator(); }
-};
+namespace Botan {
 
 /**
 * Scrub memory contents in a way that a compiler should not elide,


Test patch:
diff --git a/src/tests/test_aead.cpp b/src/tests/test_aead.cpp
index bc319d3ce..49e27304b 100644
--- a/src/tests/test_aead.cpp
+++ b/src/tests/test_aead.cpp
@@ -9,6 +9,7 @@
 
 #if defined(BOTAN_HAS_AEAD_MODES)
    #include <botan/aead.h>
+   #include <botan/mem_ops.h>
 #endif
 
 namespace Botan_Tests {
diff --git a/src/tests/test_keccak_helpers.cpp b/src/tests/test_keccak_helpers.cpp
index ad3040d9d..b310f7ae7 100644
--- a/src/tests/test_keccak_helpers.cpp
+++ b/src/tests/test_keccak_helpers.cpp
@@ -10,11 +10,11 @@
 #if defined(BOTAN_HAS_KECCAK_PERM)
 
    #include <botan/hex.h>
+   #include <botan/mem_ops.h>
    #include <botan/internal/keccak_helpers.h>
    #include <botan/internal/keccak_perm.h>
 
    #if defined(BOTAN_HAS_SHAKE_XOF)
-      #include <botan/mem_ops.h>
       #include <botan/xof.h>
    #endif