Repository: randombit/botan
Pull request #2689 (2021-04-03 20:35:23)

Replace T::clone with T::new_object
which returns a `unique_ptr<T>` instead of a `T*`


Patch:
diff --git a/src/lib/block/aes/aes.h b/src/lib/block/aes/aes.h
index f454fd857..908a9a7ae 100644
--- a/src/lib/block/aes/aes.h
+++ b/src/lib/block/aes/aes.h
@@ -25,7 +25,7 @@ class AES_128 final : public Block_Cipher_Fixed_Params<16, 16>
 
       std::string provider() const override;
       std::string name() const override { return "AES-128"; }
-      BlockCipher* clone() const override { return new AES_128; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<AES_128>(); }
       size_t parallelism() const override;
 
    private:
@@ -62,7 +62,7 @@ class AES_192 final : public Block_Cipher_Fixed_Params<16, 24>
 
       std::string provider() const override;
       std::string name() const override { return "AES-192"; }
-      BlockCipher* clone() const override { return new AES_192; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<AES_192>(); }
       size_t parallelism() const override;
 
    private:
@@ -100,7 +100,7 @@ class AES_256 final : public Block_Cipher_Fixed_Params<16, 32>
       std::string provider() const override;
 
       std::string name() const override { return "AES-256"; }
-      BlockCipher* clone() const override { return new AES_256; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<AES_256>(); }
       size_t parallelism() const override;
 
    private:
diff --git a/src/lib/block/aria/aria.h b/src/lib/block/aria/aria.h
index fc0522275..f3bf69de3 100644
--- a/src/lib/block/aria/aria.h
+++ b/src/lib/block/aria/aria.h
@@ -31,7 +31,7 @@ class ARIA_128 final : public Block_Cipher_Fixed_Params<16, 16>
 
       void clear() override;
       std::string name() const override { return "ARIA-128"; }
-      BlockCipher* clone() const override { return new ARIA_128; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<ARIA_128>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
@@ -50,7 +50,7 @@ class ARIA_192 final : public Block_Cipher_Fixed_Params<16, 24>
 
       void clear() override;
       std::string name() const override { return "ARIA-192"; }
-      BlockCipher* clone() const override { return new ARIA_192; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<ARIA_192>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
@@ -69,7 +69,7 @@ class ARIA_256 final : public Block_Cipher_Fixed_Params<16, 32>
 
       void clear() override;
       std::string name() const override { return "ARIA-256"; }
-      BlockCipher* clone() const override { return new ARIA_256; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<ARIA_256>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
diff --git a/src/lib/block/block_cipher.cpp b/src/lib/block/block_cipher.cpp
index f89bbcb7f..8c47d6a65 100644
--- a/src/lib/block/block_cipher.cpp
+++ b/src/lib/block/block_cipher.cpp
@@ -269,7 +269,7 @@ BlockCipher::create(const std::string& algo,
       std::unique_ptr<BlockCipher> c2 = BlockCipher::create(req.arg(1));
 
       if(c1 && c2)
-         return std::make_unique<Cascade_Cipher>(c1.release(), c2.release());
+         return std::make_unique<Cascade_Cipher>(std::move(c1), std::move(c2));
       }
 #endif
 
@@ -282,7 +282,7 @@ BlockCipher::create(const std::string& algo,
       if(hash && stream)
          {
          const size_t block_size = req.arg_as_integer(2, 1024);
-         return std::make_unique<Lion>(hash.release(), stream.release(), block_size);
+         return std::make_unique<Lion>(std::move(hash), std::move(stream), block_size);
          }
       }
 #endif
diff --git a/src/lib/block/block_cipher.h b/src/lib/block/block_cipher.h
index 68cdd1afe..2d1258cfc 100644
--- a/src/lib/block/block_cipher.h
+++ b/src/lib/block/block_cipher.h
@@ -193,7 +193,12 @@ class BOTAN_PUBLIC_API(2,0) BlockCipher : public SymmetricAlgorithm
       /**
       * @return new object representing the same algorithm as *this
       */
-      virtual BlockCipher* clone() const = 0;
+      virtual std::unique_ptr<BlockCipher> new_object() const = 0;
+
+      BlockCipher* clone() const
+         {
+         return this->new_object().release();
+         }
 
       virtual ~BlockCipher() = default;
    };
diff --git a/src/lib/block/blowfish/blowfish.h b/src/lib/block/blowfish/blowfish.h
index 8ead03e51..71f545531 100644
--- a/src/lib/block/blowfish/blowfish.h
+++ b/src/lib/block/blowfish/blowfish.h
@@ -30,7 +30,7 @@ class BOTAN_TEST_API Blowfish final : public Block_Cipher_Fixed_Params<8, 1, 56>
 
       void clear() override;
       std::string name() const override { return "Blowfish"; }
-      BlockCipher* clone() const override { return new Blowfish; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Blowfish>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
diff --git a/src/lib/block/camellia/camellia.h b/src/lib/block/camellia/camellia.h
index 421b1ed7c..f8ac9d2b7 100644
--- a/src/lib/block/camellia/camellia.h
+++ b/src/lib/block/camellia/camellia.h
@@ -23,7 +23,7 @@ class Camellia_128 final : public Block_Cipher_Fixed_Params<16, 16>
 
       void clear() override;
       std::string name() const override { return "Camellia-128"; }
-      BlockCipher* clone() const override { return new Camellia_128; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Camellia_128>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
@@ -41,7 +41,7 @@ class Camellia_192 final : public Block_Cipher_Fixed_Params<16, 24>
 
       void clear() override;
       std::string name() const override { return "Camellia-192"; }
-      BlockCipher* clone() const override { return new Camellia_192; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Camellia_192>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
@@ -59,7 +59,7 @@ class Camellia_256 final : public Block_Cipher_Fixed_Params<16, 32>
 
       void clear() override;
       std::string name() const override { return "Camellia-256"; }
-      BlockCipher* clone() const override { return new Camellia_256; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Camellia_256>(); }
    private:
       void key_schedule(const uint8_t key[], size_t length) override;
 
diff --git a/src/lib/block/cascade/cascade.cpp b/src/lib/block/cascade/cascade.cpp
index 8dbc850fe..641dd192d 100644
--- a/src/lib/block/cascade/cascade.cpp
+++ b/src/lib/block/cascade/cascade.cpp
@@ -48,10 +48,10 @@ std::string Cascade_Cipher::name() const
    return "Cascade(" + m_cipher1->name() + "," + m_cipher2->name() + ")";
    }
 
-BlockCipher* Cascade_Cipher::clone() const
+std::unique_ptr<BlockCipher> Cascade_Cipher::new_object() const
    {
-   return new Cascade_Cipher(m_cipher1->clone(),
-                             m_cipher2->clone());
+   return std::make_unique<Cascade_Cipher>(m_cipher1->new_object(),
+                                           m_cipher2->new_object());
    }
 
 namespace {
@@ -80,13 +80,14 @@ size_t block_size_for_cascade(size_t bs, size_t bs2)
 
 }
 
-Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) :
-   m_cipher1(c1), m_cipher2(c2)
+Cascade_Cipher::Cascade_Cipher(std::unique_ptr<BlockCipher> cipher1,
+                               std::unique_ptr<BlockCipher> cipher2) :
+   m_cipher1(std::move(cipher1)),
+   m_cipher2(std::move(cipher2)),
+   m_block_size(block_size_for_cascade(m_cipher1->block_size(), m_cipher2->block_size()))
    {
-   m_block = block_size_for_cascade(c1->block_size(), c2->block_size());
-
-   BOTAN_ASSERT(m_block % c1->block_size() == 0 &&
-                m_block % c2->block_size() == 0,
+   BOTAN_ASSERT(m_block_size % m_cipher1->block_size() == 0 &&
+                m_block_size % m_cipher2->block_size() == 0,
                 "Combined block size is a multiple of each ciphers block");
    }
 
diff --git a/src/lib/block/cascade/cascade.h b/src/lib/block/cascade/cascade.h
index b5f9b5653..6021bfc73 100644
--- a/src/lib/block/cascade/cascade.h
+++ b/src/lib/block/cascade/cascade.h
@@ -21,7 +21,7 @@ class Cascade_Cipher final : public BlockCipher
       void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override;
       void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override;
 
-      size_t block_size() const override { return m_block; }
+      size_t block_size() const override { return m_block_size; }
 
       Key_Length_Specification key_spec() const override
          {
@@ -31,22 +31,23 @@ class Cascade_Cipher final : public BlockCipher
 
       void clear() override;
       std::string name() const override;
-      BlockCipher* clone() const override;
+      std::unique_ptr<BlockCipher> new_object() const override;
 
       /**
       * Create a cascade of two block ciphers
       * @param cipher1 the first cipher
       * @param cipher2 the second cipher
       */
-      Cascade_Cipher(BlockCipher* cipher1, BlockCipher* cipher2);
+      Cascade_Cipher(std::unique_ptr<BlockCipher> cipher1,
+                     std::unique_ptr<BlockCipher> cipher2);
 
       Cascade_Cipher(const Cascade_Cipher&) = delete;
       Cascade_Cipher& operator=(const Cascade_Cipher&) = delete;
    private:
       void key_schedule(const uint8_t[], size_t) override;
 
-      size_t m_block;
       std::unique_ptr<BlockCipher> m_cipher1, m_cipher2;
+      size_t m_block_size;
    };
 
 
diff --git a/src/lib/block/cast128/cast128.h b/src/lib/block/cast128/cast128.h
index 301b1dc5e..c0b139e02 100644
--- a/src/lib/block/cast128/cast128.h
+++ b/src/lib/block/cast128/cast128.h
@@ -23,7 +23,7 @@ class CAST_128 final : public Block_Cipher_Fixed_Params<8, 11, 16>
 
       void clear() override;
       std::string name() const override { return "CAST-128"; }
-      BlockCipher* clone() const override { return new CAST_128; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<CAST_128>(); }
 
    private:
       void key_schedule(const uint8_t[], size_t) override;
diff --git a/src/lib/block/des/des.h b/src/lib/block/des/des.h
index 4c834c6f6..1fd65cff5 100644
--- a/src/lib/block/des/des.h
+++ b/src/lib/block/des/des.h
@@ -23,7 +23,7 @@ class DES final : public Block_Cipher_Fixed_Params<8, 8>
 
       void clear() override;
       std::string name() const override { return "DES"; }
-      BlockCipher* clone() const override { return new DES; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<DES>(); }
    private:
       void key_schedule(const uint8_t[], size_t) override;
 
@@ -41,7 +41,7 @@ class TripleDES final : public Block_Cipher_Fixed_Params<8, 16, 24, 8>
 
       void clear() override;
       std::string name() const override { return "TripleDES"; }
-      BlockCipher* clone() const override { return new TripleDES; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<TripleDES>(); }
    private:
 
       void key_schedule(const uint8_t[], size_t) override;
diff --git a/src/lib/block/gost_28147/gost_28147.h b/src/lib/block/gost_28147/gost_28147.h
index e9d11e091..12f1ab8a6 100644
--- a/src/lib/block/gost_28147/gost_28147.h
+++ b/src/lib/block/gost_28147/gost_28147.h
@@ -64,7 +64,7 @@ class GOST_28147_89 final : public Block_Cipher_Fixed_Params<8, 32>
       void clear() override;
 
       std::string name() const override;
-      BlockCipher* clone() const override { return new GOST_28147_89(m_SBOX); }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<GOST_28147_89>(m_SBOX); }
 
       /**
       * @param params the sbox parameters to use
@@ -73,10 +73,11 @@ class GOST_28147_89 final : public Block_Cipher_Fixed_Params<8, 32>
 
       explicit GOST_28147_89(const std::string& param_name) :
          GOST_28147_89(GOST_28147_89_Params(param_name)) {}
-   private:
+
       explicit GOST_28147_89(const std::vector<uint32_t>& other_SBOX) :
          m_SBOX(other_SBOX), m_EK(8) {}
 
+   private:
       void key_schedule(const uint8_t[], size_t) override;
 
       /*
diff --git a/src/lib/block/idea/idea.h b/src/lib/block/idea/idea.h
index c15d34dd8..4628f55e2 100644
--- a/src/lib/block/idea/idea.h
+++ b/src/lib/block/idea/idea.h
@@ -25,7 +25,7 @@ class IDEA final : public Block_Cipher_Fixed_Params<8, 16>
 
       std::string provider() const override;
       std::string name() const override { return "IDEA"; }
-      BlockCipher* clone() const override { return new IDEA; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<IDEA>(); }
       size_t parallelism() const override;
 
    private:
diff --git a/src/lib/block/lion/lion.cpp b/src/lib/block/lion/lion.cpp
index 43270f3a7..ff5918391 100644
--- a/src/lib/block/lion/lion.cpp
+++ b/src/lib/block/lion/lion.cpp
@@ -101,12 +101,9 @@ std::string Lion::name() const
                     std::to_string(block_size()) + ")";
    }
 
-/*
-* Return a clone of this object
-*/
-BlockCipher* Lion::clone() const
+std::unique_ptr<BlockCipher> Lion::new_object() const
    {
-   return new Lion(m_hash->clone(), m_cipher->clone(), block_size());
+   return std::make_unique<Lion>(m_hash->new_object(), m_cipher->new_object(), block_size());
    }
 
 /*
@@ -123,10 +120,12 @@ void Lion::clear()
 /*
 * Lion Constructor
 */
-Lion::Lion(HashFunction* hash, StreamCipher* cipher, size_t bs) :
+Lion::Lion(std::unique_ptr<HashFunction> hash,
+           std::unique_ptr<StreamCipher> cipher,
+           size_t bs) :
    m_block_size(std::max<size_t>(2*hash->output_length() + 1, bs)),
-   m_hash(hash),
-   m_cipher(cipher)
+   m_hash(std::move(hash)),
+   m_cipher(std::move(cipher))
    {
    if(2*left_size() + 1 > m_block_size)
       throw Invalid_Argument(name() + ": Chosen block size is too small");
diff --git a/src/lib/block/lion/lion.h b/src/lib/block/lion/lion.h
index 6ffaa9260..375d40232 100644
--- a/src/lib/block/lion/lion.h
+++ b/src/lib/block/lion/lion.h
@@ -37,15 +37,15 @@ class Lion final : public BlockCipher
 
       void clear() override;
       std::string name() const override;
-      BlockCipher* clone() const override;
+      std::unique_ptr<BlockCipher> new_object() const override;
 
       /**
       * @param hash the hash to use internally
       * @param cipher the stream cipher to use internally
       * @param block_size the size of the block to use
       */
-      Lion(HashFunction* hash,
-           StreamCipher* cipher,
+      Lion(std::unique_ptr<HashFunction> hash,
+           std::unique_ptr<StreamCipher> cipher,
            size_t block_size);
    private:
       void key_schedule(const uint8_t[], size_t) override;
diff --git a/src/lib/block/noekeon/noekeon.h b/src/lib/block/noekeon/noekeon.h
index b2a39638b..05244b523 100644
--- a/src/lib/block/noekeon/noekeon.h
+++ b/src/lib/block/noekeon/noekeon.h
@@ -24,7 +24,7 @@ class Noekeon final : public Block_Cipher_Fixed_Params<16, 16>
       std::string provider() const override;
       void clear() override;
       std::string name() const override { return "Noekeon"; }
-      BlockCipher* clone() const override { return new Noekeon; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Noekeon>(); }
       size_t parallelism() const override;
 
    private:
diff --git a/src/lib/block/seed/seed.h b/src/lib/block/seed/seed.h
index 1105d5075..b054202bb 100644
--- a/src/lib/block/seed/seed.h
+++ b/src/lib/block/seed/seed.h
@@ -23,7 +23,7 @@ class SEED final : public Block_Cipher_Fixed_Params<16, 16>
 
       void clear() override;
       std::string name() const override { return "SEED"; }
-      BlockCipher* clone() const override { return new SEED; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<SEED>(); }
    private:
       void key_schedule(const uint8_t[], size_t) override;
 
diff --git a/src/lib/block/serpent/serpent.h b/src/lib/block/serpent/serpent.h
index 81c841190..fc895fbce 100644
--- a/src/lib/block/serpent/serpent.h
+++ b/src/lib/block/serpent/serpent.h
@@ -25,7 +25,7 @@ class Serpent final : public Block_Cipher_Fixed_Params<16, 16, 32, 8>
       void clear() override;
       std::string provider() const override;
       std::string name() const override { return "Serpent"; }
-      BlockCipher* clone() const override { return new Serpent; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Serpent>(); }
 
       size_t parallelism() const override { return 4; }
 
diff --git a/src/lib/block/shacal2/shacal2.h b/src/lib/block/shacal2/shacal2.h
index c27689655..3e8b6a056 100644
--- a/src/lib/block/shacal2/shacal2.h
+++ b/src/lib/block/shacal2/shacal2.h
@@ -24,7 +24,7 @@ class SHACAL2 final : public Block_Cipher_Fixed_Params<32, 16, 64, 4>
       std::string provider() const override;
       void clear() override;
       std::string name() const override { return "SHACAL2"; }
-      BlockCipher* clone() const override { return new SHACAL2; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<SHACAL2>(); }
       size_t parallelism() const override;
 
    private:
diff --git a/src/lib/block/sm4/sm4.h b/src/lib/block/sm4/sm4.h
index ed6c6742f..4948b09b7 100644
--- a/src/lib/block/sm4/sm4.h
+++ b/src/lib/block/sm4/sm4.h
@@ -23,7 +23,7 @@ class SM4 final : public Block_Cipher_Fixed_Params<16, 16>
 
       void clear() override;
       std::string name() const override { return "SM4"; }
-      BlockCipher* clone() const override { return new SM4; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<SM4>(); }
 
       std::string provider() const override;
       size_t parallelism() const override;
diff --git a/src/lib/block/threefish_512/threefish_512.h b/src/lib/block/threefish_512/threefish_512.h
index 10876fd84..76c7837a8 100644
--- a/src/lib/block/threefish_512/threefish_512.h
+++ b/src/lib/block/threefish_512/threefish_512.h
@@ -27,7 +27,7 @@ class Threefish_512 final :
       void clear() override;
       std::string provider() const override;
       std::string name() const override { return "Threefish-512"; }
-      BlockCipher* clone() const override { return new Threefish_512; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Threefish_512>(); }
       size_t parallelism() const override;
 
    private:
diff --git a/src/lib/block/twofish/twofish.h b/src/lib/block/twofish/twofish.h
index 5d95c198c..5e5b86ab4 100644
--- a/src/lib/block/twofish/twofish.h
+++ b/src/lib/block/twofish/twofish.h
@@ -23,7 +23,7 @@ class Twofish final : public Block_Cipher_Fixed_Params<16, 16, 32, 8>
 
       void clear() override;
       std::string name() const override { return "Twofish"; }
-      BlockCipher* clone() const override { return new Twofish; }
+      std::unique_ptr<BlockCipher> new_object() const override { return std::make_unique<Twofish>(); }
    private:
       void key_schedule(const uint8_t[], size_t) override;
 
diff --git a/src/lib/hash/blake2/blake2b.cpp b/src/lib/hash/blake2/blake2b.cpp
index 9f825acf5..6a68936f1 100644
--- a/src/lib/hash/blake2/blake2b.cpp
+++ b/src/lib/hash/blake2/blake2b.cpp
@@ -202,9 +202,9 @@ std::string BLAKE2b::name() const
    return "BLAKE2b(" + std::to_string(m_output_bits) + ")";
    }
 
-HashFunction* BLAKE2b::clone() const
+std::unique_ptr<HashFunction> BLAKE2b::new_object() const
    {
-   return new BLAKE2b(m_output_bits);
+   return std::make_unique<BLAKE2b>(m_output_bits);
    }
 
 std::unique_ptr<HashFunction> BLAKE2b::copy_state() const
diff --git a/src/lib/hash/blake2/blake2b.h b/src/lib/hash/blake2/blake2b.h
index e93a364e5..49e19ca4f 100644
--- a/src/lib/hash/blake2/blake2b.h
+++ b/src/lib/hash/blake2/blake2b.h
@@ -34,7 +34,7 @@ class BLAKE2b final : public HashFunction, public SymmetricAlgorithm
 
       Key_Length_Specification key_spec() const override;
 
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::string name() const override;
       void clear() override;
 
diff --git a/src/lib/hash/checksum/adler32/adler32.h b/src/lib/hash/checksum/adler32/adler32.h
index 84b8c0f8e..4abe1ef86 100644
--- a/src/lib/hash/checksum/adler32/adler32.h
+++ b/src/lib/hash/checksum/adler32/adler32.h
@@ -20,7 +20,7 @@ class Adler32 final : public HashFunction
    public:
       std::string name() const override { return "Adler32"; }
       size_t output_length() const override { return 4; }
-      HashFunction* clone() const override { return new Adler32; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<Adler32>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override { m_S1 = 1; m_S2 = 0; }
diff --git a/src/lib/hash/checksum/crc24/crc24.h b/src/lib/hash/checksum/crc24/crc24.h
index 49bc43d69..b65a99630 100644
--- a/src/lib/hash/checksum/crc24/crc24.h
+++ b/src/lib/hash/checksum/crc24/crc24.h
@@ -21,7 +21,7 @@ class CRC24 final : public HashFunction
    public:
       std::string name() const override { return "CRC24"; }
       size_t output_length() const override { return 3; }
-      HashFunction* clone() const override { return new CRC24; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<CRC24>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override { m_crc = 0XCE04B7L; }
diff --git a/src/lib/hash/checksum/crc32/crc32.h b/src/lib/hash/checksum/crc32/crc32.h
index 689fd7375..58dc28703 100644
--- a/src/lib/hash/checksum/crc32/crc32.h
+++ b/src/lib/hash/checksum/crc32/crc32.h
@@ -20,7 +20,7 @@ class CRC32 final : public HashFunction
    public:
       std::string name() const override { return "CRC32"; }
       size_t output_length() const override { return 4; }
-      HashFunction* clone() const override { return new CRC32; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<CRC32>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override { m_crc = 0xFFFFFFFF; }
diff --git a/src/lib/hash/comb4p/comb4p.cpp b/src/lib/hash/comb4p/comb4p.cpp
index bf8f412c7..476355d4b 100644
--- a/src/lib/hash/comb4p/comb4p.cpp
+++ b/src/lib/hash/comb4p/comb4p.cpp
@@ -33,8 +33,9 @@ void comb4p_round(secure_vector<uint8_t>& out,
 
 }
 
-Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) :
-   m_hash1(h1), m_hash2(h2)
+Comb4P::Comb4P(std::unique_ptr<HashFunction> h1, std::unique_ptr<HashFunction> h2) :
+   m_hash1(std::move(h1)),
+   m_hash2(std::move(h2))
    {
    if(m_hash1->name() == m_hash2->name())
       throw Invalid_Argument("Comb4P: Must use two distinct hashes");
diff --git a/src/lib/hash/comb4p/comb4p.h b/src/lib/hash/comb4p/comb4p.h
index f4cf73ba5..b449daa87 100644
--- a/src/lib/hash/comb4p/comb4p.h
+++ b/src/lib/hash/comb4p/comb4p.h
@@ -23,7 +23,7 @@ class Comb4P final : public HashFunction
       * @param h1 the first hash
       * @param h2 the second hash
       */
-      Comb4P(HashFunction* h1, HashFunction* h2);
+      Comb4P(std::unique_ptr<HashFunction> h1, std::unique_ptr<HashFunction> h2);
 
       size_t hash_block_size() const override;
 
@@ -32,9 +32,9 @@ class Comb4P final : public HashFunction
          return m_hash1->output_length() + m_hash2->output_length();
          }
 
-      HashFunction* clone() const override
+      std::unique_ptr<HashFunction> new_object() const override
          {
-         return new Comb4P(m_hash1->clone(), m_hash2->clone());
+         return std::make_unique<Comb4P>(m_hash1->new_object(), m_hash2->new_object());
          }
 
       std::unique_ptr<HashFunction> copy_state() const override;
diff --git a/src/lib/hash/gost_3411/gost_3411.h b/src/lib/hash/gost_3411/gost_3411.h
index 9628bad0e..f9da5e190 100644
--- a/src/lib/hash/gost_3411/gost_3411.h
+++ b/src/lib/hash/gost_3411/gost_3411.h
@@ -22,7 +22,7 @@ class GOST_34_11 final : public HashFunction
       std::string name() const override { return "GOST-R-34.11-94" ; }
       size_t output_length() const override { return 32; }
       size_t hash_block_size() const override { return 32; }
-      HashFunction* clone() const override { return new GOST_34_11; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<GOST_34_11>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/hash.cpp b/src/lib/hash/hash.cpp
index 9cfb382eb..4b681bcc8 100644
--- a/src/lib/hash/hash.cpp
+++ b/src/lib/hash/hash.cpp
@@ -314,7 +314,7 @@ std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec,
       std::unique_ptr<HashFunction> h2 = HashFunction::create(req.arg(1));
 
       if(h1 && h2)
-         return std::make_unique<Comb4P>(h1.release(), h2.release());
+         return std::make_unique<Comb4P>(std::move(h1), std::move(h2));
       }
 #endif
 
diff --git a/src/lib/hash/hash.h b/src/lib/hash/hash.h
index 8c6440e65..99401031e 100644
--- a/src/lib/hash/hash.h
+++ b/src/lib/hash/hash.h
@@ -46,11 +46,6 @@ class BOTAN_PUBLIC_API(2,0) HashFunction : public Buffered_Computation
       */
       static std::vector<std::string> providers(const std::string& algo_spec);
 
-      /**
-      * @return new object representing the same algorithm as *this
-      */
-      virtual HashFunction* clone() const = 0;
-
       /**
       * @return provider information about this implementation. Default is "base",
       * might also return "sse2", "avx2", "openssl", or some other arbitrary string.
@@ -84,6 +79,19 @@ class BOTAN_PUBLIC_API(2,0) HashFunction : public Buffered_Computation
       * @return new hash object
       */
       virtual std::unique_ptr<HashFunction> copy_state() const = 0;
+
+      /**
+      * @return new object representing the same algorithm as *this
+      */
+      virtual std::unique_ptr<HashFunction> new_object() const = 0;
+
+      /**
+      * @return new object representing the same algorithm as *this
+      */
+      HashFunction* clone() const
+         {
+         return this->new_object().release();
+         }
    };
 
 }
diff --git a/src/lib/hash/keccak/keccak.cpp b/src/lib/hash/keccak/keccak.cpp
index 7a1612205..1c27146a4 100644
--- a/src/lib/hash/keccak/keccak.cpp
+++ b/src/lib/hash/keccak/keccak.cpp
@@ -36,9 +36,9 @@ std::string Keccak_1600::name() const
    return "Keccak-1600(" + std::to_string(m_output_bits) + ")";
    }
 
-HashFunction* Keccak_1600::clone() const
+std::unique_ptr<HashFunction> Keccak_1600::new_object() const
    {
-   return new Keccak_1600(m_output_bits);
+   return std::make_unique<Keccak_1600>(m_output_bits);
    }
 
 void Keccak_1600::clear()
diff --git a/src/lib/hash/keccak/keccak.h b/src/lib/hash/keccak/keccak.h
index 235c88a91..e571c2362 100644
--- a/src/lib/hash/keccak/keccak.h
+++ b/src/lib/hash/keccak/keccak.h
@@ -30,7 +30,7 @@ class Keccak_1600 final : public HashFunction
       size_t hash_block_size() const override { return m_bitrate / 8; }
       size_t output_length() const override { return m_output_bits / 8; }
 
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string name() const override;
       void clear() override;
diff --git a/src/lib/hash/md4/md4.h b/src/lib/hash/md4/md4.h
index 5bd3c88a9..1bc9998fa 100644
--- a/src/lib/hash/md4/md4.h
+++ b/src/lib/hash/md4/md4.h
@@ -20,7 +20,7 @@ class MD4 final : public MDx_HashFunction
    public:
       std::string name() const override { return "MD4"; }
       size_t output_length() const override { return 16; }
-      HashFunction* clone() const override { return new MD4; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<MD4>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/md5/md5.h b/src/lib/hash/md5/md5.h
index 26706121e..01ecf621a 100644
--- a/src/lib/hash/md5/md5.h
+++ b/src/lib/hash/md5/md5.h
@@ -20,7 +20,7 @@ class MD5 final : public MDx_HashFunction
    public:
       std::string name() const override { return "MD5"; }
       size_t output_length() const override { return 16; }
-      HashFunction* clone() const override { return new MD5; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<MD5>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/par_hash/par_hash.cpp b/src/lib/hash/par_hash/par_hash.cpp
index 8f375537c..d2596eab1 100644
--- a/src/lib/hash/par_hash/par_hash.cpp
+++ b/src/lib/hash/par_hash/par_hash.cpp
@@ -46,26 +46,26 @@ std::string Parallel::name() const
    return "Parallel(" + string_join(names, ',') + ")";
    }
 
-HashFunction* Parallel::clone() const
+std::unique_ptr<HashFunction> Parallel::new_object() const
    {
    std::vector<std::unique_ptr<HashFunction>> hash_copies;
 
    for(auto&& hash : m_hashes)
-      hash_copies.push_back(std::unique_ptr<HashFunction>(hash->clone()));
+      hash_copies.push_back(std::unique_ptr<HashFunction>(hash->new_object()));
 
-   return new Parallel(hash_copies);
+   return std::make_unique<Parallel>(hash_copies);
    }
 
 std::unique_ptr<HashFunction> Parallel::copy_state() const
    {
-   std::vector<std::unique_ptr<HashFunction>> hash_clones;
+   std::vector<std::unique_ptr<HashFunction>> hash_new_objects;
 
    for(const auto& hash : m_hashes)
       {
-      hash_clones.push_back(hash->copy_state());
+      hash_new_objects.push_back(hash->copy_state());
       }
 
-   return std::make_unique<Parallel>(hash_clones);
+   return std::make_unique<Parallel>(hash_new_objects);
    }
 
 void Parallel::clear()
diff --git a/src/lib/hash/par_hash/par_hash.h b/src/lib/hash/par_hash/par_hash.h
index 3c77a7fbd..00bee9605 100644
--- a/src/lib/hash/par_hash/par_hash.h
+++ b/src/lib/hash/par_hash/par_hash.h
@@ -21,7 +21,7 @@ class Parallel final : public HashFunction
    public:
       void clear() override;
       std::string name() const override;
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::unique_ptr<HashFunction> copy_state() const override;
 
       size_t output_length() const override;
diff --git a/src/lib/hash/rmd160/rmd160.h b/src/lib/hash/rmd160/rmd160.h
index 2e635a0d2..db6d8fbf1 100644
--- a/src/lib/hash/rmd160/rmd160.h
+++ b/src/lib/hash/rmd160/rmd160.h
@@ -20,7 +20,7 @@ class RIPEMD_160 final : public MDx_HashFunction
    public:
       std::string name() const override { return "RIPEMD-160"; }
       size_t output_length() const override { return 20; }
-      HashFunction* clone() const override { return new RIPEMD_160; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<RIPEMD_160>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/sha1/sha160.h b/src/lib/hash/sha1/sha160.h
index dd834d4ba..8e3b046b4 100644
--- a/src/lib/hash/sha1/sha160.h
+++ b/src/lib/hash/sha1/sha160.h
@@ -20,7 +20,7 @@ class SHA_160 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SHA-160"; }
       size_t output_length() const override { return 20; }
-      HashFunction* clone() const override { return new SHA_160; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_160>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/sha2_32/sha2_32.h b/src/lib/hash/sha2_32/sha2_32.h
index 396b1d557..f2e4edf52 100644
--- a/src/lib/hash/sha2_32/sha2_32.h
+++ b/src/lib/hash/sha2_32/sha2_32.h
@@ -21,7 +21,7 @@ class SHA_224 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SHA-224"; }
       size_t output_length() const override { return 28; }
-      HashFunction* clone() const override { return new SHA_224; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_224>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
@@ -45,7 +45,7 @@ class SHA_256 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SHA-256"; }
       size_t output_length() const override { return 32; }
-      HashFunction* clone() const override { return new SHA_256; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_256>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/sha2_64/sha2_64.h b/src/lib/hash/sha2_64/sha2_64.h
index a3253e0e8..6036eb15c 100644
--- a/src/lib/hash/sha2_64/sha2_64.h
+++ b/src/lib/hash/sha2_64/sha2_64.h
@@ -20,7 +20,7 @@ class SHA_384 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SHA-384"; }
       size_t output_length() const override { return 48; }
-      HashFunction* clone() const override { return new SHA_384; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_384>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string provider() const override;
 
@@ -43,7 +43,7 @@ class SHA_512 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SHA-512"; }
       size_t output_length() const override { return 64; }
-      HashFunction* clone() const override { return new SHA_512; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_512>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string provider() const override;
 
@@ -81,7 +81,7 @@ class SHA_512_256 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SHA-512-256"; }
       size_t output_length() const override { return 32; }
-      HashFunction* clone() const override { return new SHA_512_256; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_512_256>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string provider() const override;
 
diff --git a/src/lib/hash/sha3/sha3.cpp b/src/lib/hash/sha3/sha3.cpp
index 83393acdd..5504a683d 100644
--- a/src/lib/hash/sha3/sha3.cpp
+++ b/src/lib/hash/sha3/sha3.cpp
@@ -237,9 +237,9 @@ std::unique_ptr<HashFunction> SHA_3::copy_state() const
    return std::make_unique<SHA_3>(*this);
    }
 
-HashFunction* SHA_3::clone() const
+std::unique_ptr<HashFunction> SHA_3::new_object() const
    {
-   return new SHA_3(m_output_bits);
+   return std::make_unique<SHA_3>(m_output_bits);
    }
 
 void SHA_3::clear()
diff --git a/src/lib/hash/sha3/sha3.h b/src/lib/hash/sha3/sha3.h
index 402dd5e23..3fdd72e04 100644
--- a/src/lib/hash/sha3/sha3.h
+++ b/src/lib/hash/sha3/sha3.h
@@ -30,7 +30,7 @@ class SHA_3 : public HashFunction
       size_t hash_block_size() const override { return m_bitrate / 8; }
       size_t output_length() const override { return m_output_bits / 8; }
 
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string name() const override;
       void clear() override;
diff --git a/src/lib/hash/shake/shake.cpp b/src/lib/hash/shake/shake.cpp
index 01f1d9dfa..16957719e 100644
--- a/src/lib/hash/shake/shake.cpp
+++ b/src/lib/hash/shake/shake.cpp
@@ -24,9 +24,9 @@ std::string SHAKE_128::name() const
    return "SHAKE-128(" + std::to_string(m_output_bits) + ")";
    }
 
-HashFunction* SHAKE_128::clone() const
+std::unique_ptr<HashFunction> SHAKE_128::new_object() const
    {
-   return new SHAKE_128(m_output_bits);
+   return std::make_unique<SHAKE_128>(m_output_bits);
    }
 
 std::unique_ptr<HashFunction> SHAKE_128::copy_state() const
@@ -65,9 +65,9 @@ std::string SHAKE_256::name() const
    return "SHAKE-256(" + std::to_string(m_output_bits) + ")";
    }
 
-HashFunction* SHAKE_256::clone() const
+std::unique_ptr<HashFunction> SHAKE_256::new_object() const
    {
-   return new SHAKE_256(m_output_bits);
+   return std::make_unique<SHAKE_256>(m_output_bits);
    }
 
 std::unique_ptr<HashFunction> SHAKE_256::copy_state() const
diff --git a/src/lib/hash/shake/shake.h b/src/lib/hash/shake/shake.h
index f58ca3273..47d8f7ce8 100644
--- a/src/lib/hash/shake/shake.h
+++ b/src/lib/hash/shake/shake.h
@@ -30,7 +30,7 @@ class SHAKE_128 final : public HashFunction
       size_t hash_block_size() const override { return SHAKE_128_BITRATE / 8; }
       size_t output_length() const override { return m_output_bits / 8; }
 
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string name() const override;
       void clear() override;
@@ -62,7 +62,7 @@ class SHAKE_256 final : public HashFunction
       size_t hash_block_size() const override { return SHAKE_256_BITRATE / 8; }
       size_t output_length() const override { return m_output_bits / 8; }
 
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string name() const override;
       void clear() override;
diff --git a/src/lib/hash/skein/skein_512.cpp b/src/lib/hash/skein/skein_512.cpp
index 78cd3e794..7689b5004 100644
--- a/src/lib/hash/skein/skein_512.cpp
+++ b/src/lib/hash/skein/skein_512.cpp
@@ -33,9 +33,9 @@ std::string Skein_512::name() const
    return "Skein-512(" + std::to_string(m_output_bits) + ")";
    }
 
-HashFunction* Skein_512::clone() const
+std::unique_ptr<HashFunction> Skein_512::new_object() const
    {
-   return new Skein_512(m_output_bits, m_personalization);
+   return std::make_unique<Skein_512>(m_output_bits, m_personalization);
    }
 
 std::unique_ptr<HashFunction> Skein_512::copy_state() const
diff --git a/src/lib/hash/skein/skein_512.h b/src/lib/hash/skein/skein_512.h
index d6d5ca44f..4bda04c30 100644
--- a/src/lib/hash/skein/skein_512.h
+++ b/src/lib/hash/skein/skein_512.h
@@ -32,7 +32,7 @@ class Skein_512 final : public HashFunction
       size_t hash_block_size() const override { return 64; }
       size_t output_length() const override { return m_output_bits / 8; }
 
-      HashFunction* clone() const override;
+      std::unique_ptr<HashFunction> new_object() const override;
       std::unique_ptr<HashFunction> copy_state() const override;
       std::string name() const override;
       void clear() override;
diff --git a/src/lib/hash/sm3/sm3.h b/src/lib/hash/sm3/sm3.h
index e156d2b22..387b1278d 100644
--- a/src/lib/hash/sm3/sm3.h
+++ b/src/lib/hash/sm3/sm3.h
@@ -25,7 +25,7 @@ class SM3 final : public MDx_HashFunction
    public:
       std::string name() const override { return "SM3"; }
       size_t output_length() const override { return SM3_DIGEST_BYTES; }
-      HashFunction* clone() const override { return new SM3; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SM3>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/hash/streebog/streebog.h b/src/lib/hash/streebog/streebog.h
index 87b9608ac..523a20221 100644
--- a/src/lib/hash/streebog/streebog.h
+++ b/src/lib/hash/streebog/streebog.h
@@ -21,7 +21,7 @@ class Streebog : public HashFunction
    public:
       size_t output_length() const override { return m_output_bits / 8; }
 
-      HashFunction* clone() const override { return new Streebog(m_output_bits); }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<Streebog>(m_output_bits); }
       void clear() override;
       std::string name() const override;
       size_t hash_block_size() const override { return 64; }
diff --git a/src/lib/hash/whirlpool/whrlpool.h b/src/lib/hash/whirlpool/whrlpool.h
index 7bc311252..2cb6cfc63 100644
--- a/src/lib/hash/whirlpool/whrlpool.h
+++ b/src/lib/hash/whirlpool/whrlpool.h
@@ -20,7 +20,7 @@ class Whirlpool final : public MDx_HashFunction
    public:
       std::string name() const override { return "Whirlpool"; }
       size_t output_length() const override { return 64; }
-      HashFunction* clone() const override { return new Whirlpool; }
+      std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<Whirlpool>(); }
       std::unique_ptr<HashFunction> copy_state() const override;
 
       void clear() override;
diff --git a/src/lib/kdf/hkdf/hkdf.cpp b/src/lib/kdf/hkdf/hkdf.cpp
index 618226a17..fe39423b2 100644
--- a/src/lib/kdf/hkdf/hkdf.cpp
+++ b/src/lib/kdf/hkdf/hkdf.cpp
@@ -17,8 +17,8 @@ void HKDF::kdf(uint8_t key[], size_t key_len,
                const uint8_t salt[], size_t salt_len,
                const uint8_t label[], size_t label_len) const
    {
-   HKDF_Extract extract(m_prf->clone());
-   HKDF_Expand expand(m_prf->clone());
+   HKDF_Extract extract(m_prf->new_object());
+   HKDF_Expand expand(m_prf->new_object());
    secure_vector<uint8_t> prk(m_prf->output_length());
 
    extract.kdf(prk.data(), prk.size(), secret, secret_len, salt, salt_len, nullptr, 0);
@@ -107,9 +107,7 @@ hkdf_expand_label(const std::string& hash_fn,
 
    const uint16_t length16 = static_cast<uint16_t>(length);
 
-   auto mac = MessageAuthenticationCode::create_or_throw("HMAC(" + hash_fn + ")");
-
-   HKDF_Expand hkdf(mac.release());
+   HKDF_Expand hkdf(MessageAuthenticationCode::create_or_throw("HMAC(" + hash_fn + ")"));
 
    secure_vector<uint8_t> output(length16);
    std::vector<uint8_t> prefix(3 + label.size() + 1);
diff --git a/src/lib/kdf/hkdf/hkdf.h b/src/lib/kdf/hkdf/hkdf.h
index 632c3178c..860cfe548 100644
--- a/src/lib/kdf/hkdf/hkdf.h
+++ b/src/lib/kdf/hkdf/hkdf.h
@@ -23,9 +23,13 @@ class HKDF final : public KDF
       /**
       * @param prf MAC algorithm to use
       */
-      explicit HKDF(MessageAuthenticationCode* prf) : m_prf(prf) {}
+      explicit HKDF(std::unique_ptr<MessageAuthenticationCode> prf) :
+         m_prf(std::move(prf)) {}
 
-      KDF* clone() const override { return new HKDF(m_prf->clone()); }
+      std::unique_ptr<KDF> new_object() const override
+         {
+         return std::make_unique<HKDF>(m_prf->new_object());
+         }
 
       std::string name() const override { return "HKDF(" + m_prf->name() + ")"; }
 
@@ -47,9 +51,13 @@ class HKDF_Extract final : public KDF
       /**
       * @param prf MAC algorithm to use
       */
-      explicit HKDF_Extract(MessageAuthenticationCode* prf) : m_prf(prf) {}
+      explicit HKDF_Extract(std::unique_ptr<MessageAuthenticationCode> prf) :
+         m_prf(std::move(prf)) {}
 
-      KDF* clone() const override { return new HKDF_Extract(m_prf->clone()); }
+      std::unique_ptr<KDF> new_object() const override
+         {
+         return std::make_unique<HKDF_Extract>(m_prf->new_object());
+         }
 
       std::string name() const override { return "HKDF-Extract(" + m_prf->name() + ")"; }
 
@@ -71,9 +79,13 @@ class HKDF_Expand final : public KDF
       /**
       * @param prf MAC algorithm to use
       */
-      explicit HKDF_Expand(MessageAuthenticationCode* prf) : m_prf(prf) {}
+      explicit HKDF_Expand(std::unique_ptr<MessageAuthenticationCode> prf) :
+         m_prf(std::move(prf)) {}
 
-      KDF* clone() const override { return new HKDF_Expand(m_prf->clone()); }
+      std::unique_ptr<KDF> new_object() const override
+         {
+         return std::make_unique<HKDF_Expand>(m_prf->new_object());
+         }
 
       std::string name() const override { return "HKDF-Expand(" + m_prf->name() + ")"; }
 
diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp
index 79a794c7d..891b161bc 100644
--- a/src/lib/kdf/kdf.cpp
+++ b/src/lib/kdf/kdf.cpp
@@ -56,10 +56,10 @@ std::unique_ptr<KDF>
 kdf_create_mac_or_hash(const std::string& nm)
    {
    if(auto mac = MessageAuthenticationCode::create("HMAC(" + nm + ")"))
-      return std::make_unique<KDF_Type>(mac.release());
+      return std::make_unique<KDF_Type>(std::move(mac));
 
    if(auto mac = MessageAuthenticationCode::create(nm))
-      return std::make_unique<KDF_Type>(mac.release());
+      return std::make_unique<KDF_Type>(std::move(mac));
 
    return nullptr;
    }
@@ -103,7 +103,7 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec,
       if(provider.empty() || provider == "base")
          {
          if(auto hash = HashFunction::create(req.arg(0)))
-            return std::make_unique<KDF2>(hash.release());
+            return std::make_unique<KDF2>(std::move(hash));
          }
       }
 #endif
@@ -114,7 +114,7 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec,
       if(provider.empty() || provider == "base")
          {
          if(auto hash = HashFunction::create(req.arg(0)))
-            return std::make_unique<KDF1_18033>(hash.release());
+            return std::make_unique<KDF1_18033>(std::move(hash));
          }
       }
 #endif
@@ -125,7 +125,7 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec,
       if(provider.empty() || provider == "base")
          {
          if(auto hash = HashFunction::create(req.arg(0)))
-            return std::make_unique<KDF1>(hash.release());
+            return std::make_unique<KDF1>(std::move(hash));
          }
       }
 #endif
@@ -180,9 +180,9 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec,
    if(req.algo_name() == "SP800-56A" && req.arg_count() == 1)
       {
       if(auto hash = HashFunction::create(req.arg(0)))
-         return std::make_unique<SP800_56A_Hash>(hash.release());
+         return std::make_unique<SP800_56A_Hash>(std::move(hash));
       if(auto mac = MessageAuthenticationCode::create(req.arg(0)))
-         return std::make_unique<SP800_56A_HMAC>(mac.release());
+         return std::make_unique<SP800_56A_HMAC>(std::move(mac));
       }
 #endif
 
@@ -193,10 +193,10 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec,
       if(exp)
          {
          if(auto mac = MessageAuthenticationCode::create(req.arg(0)))
-            return std::make_unique<SP800_56C>(mac.release(), exp.release());
+            return std::make_unique<SP800_56C>(std::move(mac), std::move(exp));
 
          if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")"))
-            return std::make_unique<SP800_56C>(mac.release(), exp.release());
+            return std::make_unique<SP800_56C>(std::move(mac), std::move(exp));
          }
       }
 #endif
diff --git a/src/lib/kdf/kdf.h b/src/lib/kdf/kdf.h
index ecfebf64e..ece4b138a 100644
--- a/src/lib/kdf/kdf.h
+++ b/src/lib/kdf/kdf.h
@@ -180,7 +180,15 @@ class BOTAN_PUBLIC_API(2,0) KDF
       /**
       * @return new object representing the same algorithm as *this
       */
-      virtual KDF* clone() const = 0;
+      virtual std::unique_ptr<KDF> new_object() const = 0;
+
+      /**
+      * @return new object representing the same algorithm as *this
+      */
+      KDF* clone() const
+         {
+         return this->new_object().release();
+         }
    };
 
 /**
diff --git a/src/lib/kdf/kdf1/kdf1.cpp b/src/lib/kdf/kdf1/kdf1.cpp
index a3232be74..0207ac0f0 100644
--- a/src/lib/kdf/kdf1/kdf1.cpp
+++ b/src/lib/kdf/kdf1/kdf1.cpp
@@ -15,9 +15,9 @@ std::string KDF1::name() const
    return "KDF1(" + m_hash->name() + ")";
    }
 
-KDF* KDF1::clone() const
+std::unique_ptr<KDF> KDF1::new_object() const
    {
-   return new KDF1(m_hash->clone());
+   return std::make_unique<KDF1>(m_hash->new_object());
    }
 
 void KDF1::kdf(uint8_t key[], size_t key_len,
diff --git a/src/lib/kdf/kdf1/kdf1.h b/src/lib/kdf/kdf1/kdf1.h
index e6e955cca..f7de1def5 100644
--- a/src/lib/kdf/kdf1/kdf1.h
+++ b/src/lib/kdf/kdf1/kdf1.h
@@ -21,7 +21,7 @@ class KDF1 final : public KDF
    public:
       std::string name() const override;
 
-      KDF* clone() const override;
+      std::unique_ptr<KDF> new_object() const override;
 
       void kdf(uint8_t key[], size_t key_len,
                const uint8_t secret[], size_t secret_len,
@@ -29,9 +29,11 @@ class KDF1 final : public KDF
                const uint8_t label[], size_t label_len) const override;
 
       /**
-      * @param h hash function to use
+      * @param hash function to use
       */
-      explicit KDF1(HashFunction* h) : m_hash(h) {}
+      explicit KDF1(std::unique_ptr<HashFunction> hash) :
+         m_hash(std::move(hash))
+         {}
    private:
       std::unique_ptr<HashFunction> m_hash;
    };
diff --git a/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h b/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h
index 73f843c7d..faec1cc4a 100644
--- a/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h
+++ b/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h
@@ -21,7 +21,7 @@ class KDF1_18033 final : public KDF
    public:
       std::string name() const override { return "KDF1-18033(" + m_hash->name() + ")"; }
 
-      KDF* clone() const override { return new KDF1_18033(m_hash->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<KDF1_18033>(m_hash->new_object()); }
 
       void kdf(uint8_t key[], size_t key_len,
                const uint8_t secret[], size_t secret_len,
@@ -29,9 +29,11 @@ class KDF1_18033 final : public KDF
                const uint8_t label[], size_t label_len) const override;
 
       /**
-      * @param h hash function to use
+      * @param hash function to use
       */
-      explicit KDF1_18033(HashFunction* h) : m_hash(h) {}
+      explicit KDF1_18033(std::unique_ptr<HashFunction> hash) :
+         m_hash(std::move(hash))
+         {}
    private:
       std::unique_ptr<HashFunction> m_hash;
    };
diff --git a/src/lib/kdf/kdf2/kdf2.cpp b/src/lib/kdf/kdf2/kdf2.cpp
index bc829784c..0bc37b1e4 100644
--- a/src/lib/kdf/kdf2/kdf2.cpp
+++ b/src/lib/kdf/kdf2/kdf2.cpp
@@ -15,9 +15,9 @@ std::string KDF2::name() const
    return "KDF2(" + m_hash->name() + ")";
    }
 
-KDF* KDF2::clone() const
+std::unique_ptr<KDF> KDF2::new_object() const
    {
-   return new KDF2(m_hash->clone());
+   return std::make_unique<KDF2>(m_hash->new_object());
    }
 
 void KDF2::kdf(uint8_t key[], size_t key_len,
diff --git a/src/lib/kdf/kdf2/kdf2.h b/src/lib/kdf/kdf2/kdf2.h
index 93a0293a7..3d9925cbf 100644
--- a/src/lib/kdf/kdf2/kdf2.h
+++ b/src/lib/kdf/kdf2/kdf2.h
@@ -21,7 +21,7 @@ class KDF2 final : public KDF
    public:
       std::string name() const override;
 
-      KDF* clone() const override;
+      std::unique_ptr<KDF> new_object() const override;
 
       void kdf(uint8_t key[], size_t key_len,
                const uint8_t secret[], size_t secret_len,
@@ -31,7 +31,9 @@ class KDF2 final : public KDF
       /**
       * @param h hash function to use
       */
-      explicit KDF2(HashFunction* h) : m_hash(h) {}
+      explicit KDF2(std::unique_ptr<HashFunction> hash) :
+         m_hash(std::move(hash))
+         {}
    private:
       std::unique_ptr<HashFunction> m_hash;
    };
diff --git a/src/lib/kdf/prf_tls/prf_tls.h b/src/lib/kdf/prf_tls/prf_tls.h
index 19cfc7797..7b9d3c7f6 100644
--- a/src/lib/kdf/prf_tls/prf_tls.h
+++ b/src/lib/kdf/prf_tls/prf_tls.h
@@ -21,7 +21,7 @@ class TLS_12_PRF final : public KDF
    public:
       std::string name() const override { return "TLS-12-PRF(" + m_mac->name() + ")"; }
 
-      KDF* clone() const override { return new TLS_12_PRF(m_mac->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<TLS_12_PRF>(m_mac->new_object()); }
 
       void kdf(uint8_t key[], size_t key_len,
                const uint8_t secret[], size_t secret_len,
@@ -31,7 +31,7 @@ class TLS_12_PRF final : public KDF
       /**
       * @param mac MAC algorithm to use
       */
-      explicit TLS_12_PRF(MessageAuthenticationCode* mac) : m_mac(mac) {}
+      explicit TLS_12_PRF(std::unique_ptr<MessageAuthenticationCode> mac) : m_mac(std::move(mac)) {}
    private:
       std::unique_ptr<MessageAuthenticationCode> m_mac;
    };
diff --git a/src/lib/kdf/prf_x942/prf_x942.h b/src/lib/kdf/prf_x942/prf_x942.h
index 4dac61c45..6ef449744 100644
--- a/src/lib/kdf/prf_x942/prf_x942.h
+++ b/src/lib/kdf/prf_x942/prf_x942.h
@@ -21,7 +21,7 @@ class X942_PRF final : public KDF
    public:
       std::string name() const override;
 
-      KDF* clone() const override { return new X942_PRF(m_key_wrap_oid); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<X942_PRF>(m_key_wrap_oid); }
 
       void kdf(uint8_t key[], size_t key_len,
                const uint8_t secret[], size_t secret_len,
diff --git a/src/lib/kdf/sp800_108/sp800_108.h b/src/lib/kdf/sp800_108/sp800_108.h
index 94f8ec506..806282017 100644
--- a/src/lib/kdf/sp800_108/sp800_108.h
+++ b/src/lib/kdf/sp800_108/sp800_108.h
@@ -21,7 +21,7 @@ class SP800_108_Counter final : public KDF
    public:
       std::string name() const override { return "SP800-108-Counter(" + m_prf->name() + ")"; }
 
-      KDF* clone() const override { return new SP800_108_Counter(m_prf->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<SP800_108_Counter>(m_prf->new_object()); }
 
       /**
       * Derive a key using the SP800-108 KDF in Counter mode.
@@ -48,7 +48,7 @@ class SP800_108_Counter final : public KDF
       /**
       * @param mac MAC algorithm to use
       */
-      explicit SP800_108_Counter(MessageAuthenticationCode* mac) : m_prf(mac) {}
+      explicit SP800_108_Counter(std::unique_ptr<MessageAuthenticationCode> mac) : m_prf(std::move(mac)) {}
    private:
       std::unique_ptr<MessageAuthenticationCode> m_prf;
    };
@@ -61,7 +61,7 @@ class SP800_108_Feedback final : public KDF
    public:
       std::string name() const override { return "SP800-108-Feedback(" + m_prf->name() + ")"; }
 
-      KDF* clone() const override { return new SP800_108_Feedback(m_prf->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<SP800_108_Feedback>(m_prf->new_object()); }
 
       /**
       * Derive a key using the SP800-108 KDF in Feedback mode.
@@ -85,7 +85,7 @@ class SP800_108_Feedback final : public KDF
                  const uint8_t salt[], size_t salt_len,
                  const uint8_t label[], size_t label_len) const override;
 
-      explicit SP800_108_Feedback(MessageAuthenticationCode* mac) : m_prf(mac) {}
+      explicit SP800_108_Feedback(std::unique_ptr<MessageAuthenticationCode> mac) : m_prf(std::move(mac)) {}
    private:
       std::unique_ptr<MessageAuthenticationCode> m_prf;
    };
@@ -98,7 +98,7 @@ class SP800_108_Pipeline final : public KDF
    public:
       std::string name() const override { return "SP800-108-Pipeline(" + m_prf->name() + ")"; }
 
-      KDF* clone() const override { return new SP800_108_Pipeline(m_prf->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<SP800_108_Pipeline>(m_prf->new_object()); }
 
       /**
       * Derive a key using the SP800-108 KDF in Double Pipeline mode.
@@ -122,7 +122,7 @@ class SP800_108_Pipeline final : public KDF
                  const uint8_t salt[], size_t salt_len,
                  const uint8_t label[], size_t label_len) const override;
 
-      explicit SP800_108_Pipeline(MessageAuthenticationCode* mac) : m_prf(mac) {}
+      explicit SP800_108_Pipeline(std::unique_ptr<MessageAuthenticationCode> mac) : m_prf(std::move(mac)) {}
 
    private:
       std::unique_ptr<MessageAuthenticationCode> m_prf;
diff --git a/src/lib/kdf/sp800_56a/sp800_56a.cpp b/src/lib/kdf/sp800_56a/sp800_56a.cpp
index 9cf298ead..73474f85c 100644
--- a/src/lib/kdf/sp800_56a/sp800_56a.cpp
+++ b/src/lib/kdf/sp800_56a/sp800_56a.cpp
@@ -65,7 +65,7 @@ void SP800_56A_Hash::kdf(uint8_t key[], size_t key_len,
    SP800_56A_kdf(*m_hash, key, key_len, secret, secret_len, label, label_len);
    }
 
-SP800_56A_HMAC::SP800_56A_HMAC(MessageAuthenticationCode* mac) : m_mac(mac)
+SP800_56A_HMAC::SP800_56A_HMAC(std::unique_ptr<MessageAuthenticationCode> mac) : m_mac(std::move(mac))
    {
    // TODO: we need a MessageAuthenticationCode::is_hmac
    const SCAN_Name req(m_mac->name());
diff --git a/src/lib/kdf/sp800_56a/sp800_56a.h b/src/lib/kdf/sp800_56a/sp800_56a.h
index 5d976fefd..2c4c1e878 100644
--- a/src/lib/kdf/sp800_56a/sp800_56a.h
+++ b/src/lib/kdf/sp800_56a/sp800_56a.h
@@ -24,7 +24,7 @@ class SP800_56A_Hash final : public KDF
    public:
       std::string name() const override { return "SP800-56A(" + m_hash->name() + ")"; }
 
-      KDF* clone() const override { return new SP800_56A_Hash(m_hash->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<SP800_56A_Hash>(m_hash->new_object()); }
 
       /**
       * Derive a key using the SP800-56A KDF.
@@ -51,7 +51,7 @@ class SP800_56A_Hash final : public KDF
       /**
       * @param hash the hash function to use as the auxiliary function
       */
-      explicit SP800_56A_Hash(HashFunction* hash) : m_hash(hash) {}
+      explicit SP800_56A_Hash(std::unique_ptr<HashFunction> hash) : m_hash(std::move(hash)) {}
    private:
       std::unique_ptr<HashFunction> m_hash;
    };
@@ -64,7 +64,7 @@ class SP800_56A_HMAC final : public KDF
    public:
       std::string name() const override { return "SP800-56A(" + m_mac->name() + ")"; }
 
-      KDF* clone() const override { return new SP800_56A_HMAC(m_mac->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<SP800_56A_HMAC>(m_mac->new_object()); }
 
       /**
       * Derive a key using the SP800-56A KDF.
@@ -91,7 +91,7 @@ class SP800_56A_HMAC final : public KDF
       /**
       * @param mac the HMAC to use as the auxiliary function
       */
-      explicit SP800_56A_HMAC(MessageAuthenticationCode* mac);
+      explicit SP800_56A_HMAC(std::unique_ptr<MessageAuthenticationCode> mac);
    private:
       std::unique_ptr<MessageAuthenticationCode> m_mac;
    };
diff --git a/src/lib/kdf/sp800_56c/sp800_56c.h b/src/lib/kdf/sp800_56c/sp800_56c.h
index fa5750563..075fe03a1 100644
--- a/src/lib/kdf/sp800_56c/sp800_56c.h
+++ b/src/lib/kdf/sp800_56c/sp800_56c.h
@@ -21,7 +21,7 @@ class SP800_56C final : public KDF
    public:
       std::string name() const override { return "SP800-56C(" + m_prf->name() + ")"; }
 
-      KDF* clone() const override { return new SP800_56C(m_prf->clone(), m_exp->clone()); }
+      std::unique_ptr<KDF> new_object() const override { return std::make_unique<SP800_56C>(m_prf->new_object(), m_exp->new_object()); }
 
       /**
       * Derive a key using the SP800-56C KDF.
@@ -47,7 +47,11 @@ class SP800_56C final : public KDF
       * @param mac MAC algorithm used for randomness extraction
       * @param exp KDF used for key expansion
       */
-      SP800_56C(MessageAuthenticationCode* mac, KDF* exp) : m_prf(mac), m_exp(exp) {}
+      SP800_56C(std::unique_ptr<MessageAuthenticationCode> mac,
+                std::unique_ptr<KDF> exp) :
+         m_prf(std::move(mac)),
+         m_exp(std::move(exp))
+         {}
    private:
       std::unique_ptr<MessageAuthenticationCode> m_prf;
       std::unique_ptr<KDF> m_exp;
diff --git a/src/lib/mac/blake2mac/blake2bmac.cpp b/src/lib/mac/blake2mac/blake2bmac.cpp
index f9a4cbbd5..e9a138f8e 100644
--- a/src/lib/mac/blake2mac/blake2bmac.cpp
+++ b/src/lib/mac/blake2mac/blake2bmac.cpp
@@ -19,11 +19,11 @@ void BLAKE2bMAC::clear()
    }
 
 /*
-* Return a clone of this object
+* Return a new_object of this object
 */
-MessageAuthenticationCode* BLAKE2bMAC::clone() const
+std::unique_ptr<MessageAuthenticationCode> BLAKE2bMAC::new_object() const
    {
-   return new BLAKE2bMAC(m_blake.output_length() * 8);
+   return std::make_unique<BLAKE2bMAC>(m_blake.output_length() * 8);
    }
 
 /*
diff --git a/src/lib/mac/blake2mac/blake2bmac.h b/src/lib/mac/blake2mac/blake2bmac.h
index 66a504020..1fb403899 100644
--- a/src/lib/mac/blake2mac/blake2bmac.h
+++ b/src/lib/mac/blake2mac/blake2bmac.h
@@ -27,7 +27,7 @@ class BLAKE2bMAC final : public MessageAuthenticationCode
 
       std::string name() const override { return m_blake.name(); }
       size_t output_length() const override { return m_blake.output_length(); }
-      MessageAuthenticationCode* clone() const override;
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override;
 
       void clear() override;
 
diff --git a/src/lib/mac/cmac/cmac.cpp b/src/lib/mac/cmac/cmac.cpp
index 1ab462056..204c5a3ac 100644
--- a/src/lib/mac/cmac/cmac.cpp
+++ b/src/lib/mac/cmac/cmac.cpp
@@ -98,18 +98,18 @@ std::string CMAC::name() const
    }
 
 /*
-* Return a clone of this object
+* Return a new_object of this object
 */
-MessageAuthenticationCode* CMAC::clone() const
+std::unique_ptr<MessageAuthenticationCode> CMAC::new_object() const
    {
-   return new CMAC(m_cipher->clone());
+   return std::make_unique<CMAC>(m_cipher->new_object());
    }
 
 /*
 * CMAC Constructor
 */
-CMAC::CMAC(BlockCipher* cipher) :
-   m_cipher(cipher),
+CMAC::CMAC(std::unique_ptr<BlockCipher> cipher) :
+   m_cipher(std::move(cipher)),
    m_block_size(m_cipher->block_size())
    {
    if(poly_double_supported_size(m_block_size) == false)
diff --git a/src/lib/mac/cmac/cmac.h b/src/lib/mac/cmac/cmac.h
index 861db8929..629bf0955 100644
--- a/src/lib/mac/cmac/cmac.h
+++ b/src/lib/mac/cmac/cmac.h
@@ -21,7 +21,7 @@ class CMAC final : public MessageAuthenticationCode
    public:
       std::string name() const override;
       size_t output_length() const override { return m_block_size; }
-      MessageAuthenticationCode* clone() const override;
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override;
 
       void clear() override;
 
@@ -33,7 +33,7 @@ class CMAC final : public MessageAuthenticationCode
       /**
       * @param cipher the block cipher to use
       */
-      explicit CMAC(BlockCipher* cipher);
+      explicit CMAC(std::unique_ptr<BlockCipher> cipher);
 
       CMAC(const CMAC&) = delete;
       CMAC& operator=(const CMAC&) = delete;
diff --git a/src/lib/mac/gmac/gmac.cpp b/src/lib/mac/gmac/gmac.cpp
index 2e594378d..4c6aae291 100644
--- a/src/lib/mac/gmac/gmac.cpp
+++ b/src/lib/mac/gmac/gmac.cpp
@@ -13,8 +13,8 @@
 
 namespace Botan {
 
-GMAC::GMAC(BlockCipher* cipher) :
-   m_cipher(cipher),
+GMAC::GMAC(std::unique_ptr<BlockCipher> cipher) :
+   m_cipher(std::move(cipher)),
    m_ghash(new GHASH),
    m_aad_buf(GCM_BS),
    m_aad_buf_pos(0),
@@ -127,8 +127,8 @@ void GMAC::final_result(uint8_t mac[])
    clear();
    }
 
-MessageAuthenticationCode* GMAC::clone() const
+std::unique_ptr<MessageAuthenticationCode> GMAC::new_object() const
    {
-   return new GMAC(m_cipher->clone());
+   return std::make_unique<GMAC>(m_cipher->new_object());
    }
 }
diff --git a/src/lib/mac/gmac/gmac.h b/src/lib/mac/gmac/gmac.h
index 5b7052251..b8ce3f5ea 100644
--- a/src/lib/mac/gmac/gmac.h
+++ b/src/lib/mac/gmac/gmac.h
@@ -28,7 +28,7 @@ class GMAC final : public MessageAuthenticationCode
       void clear() override;
       std::string name() const override;
       size_t output_length() const override;
-      MessageAuthenticationCode* clone() const override;
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override;
 
       Key_Length_Specification key_spec() const override;
 
@@ -37,7 +37,7 @@ class GMAC final : public MessageAuthenticationCode
       *
       * @param cipher the underlying block cipher to use
       */
-      explicit GMAC(BlockCipher* cipher);
+      explicit GMAC(std::unique_ptr<BlockCipher> cipher);
 
       GMAC(const GMAC&) = delete;
       GMAC& operator=(const GMAC&) = delete;
diff --git a/src/lib/mac/hmac/hmac.cpp b/src/lib/mac/hmac/hmac.cpp
index 7a7c38aab..d37dfab0f 100644
--- a/src/lib/mac/hmac/hmac.cpp
+++ b/src/lib/mac/hmac/hmac.cpp
@@ -128,18 +128,18 @@ std::string HMAC::name() const
    }
 
 /*
-* Return a clone of this object
+* Return a new_object of this object
 */
-MessageAuthenticationCode* HMAC::clone() const
+std::unique_ptr<MessageAuthenticationCode> HMAC::new_object() const
    {
-   return new HMAC(m_hash->clone());
+   return std::make_unique<HMAC>(m_hash->new_object());
    }
 
 /*
 * HMAC Constructor
 */
-HMAC::HMAC(HashFunction* hash) :
-   m_hash(hash),
+HMAC::HMAC(std::unique_ptr<HashFunction> hash) :
+   m_hash(std::move(hash)),
    m_hash_output_length(m_hash->output_length()),
    m_hash_block_size(m_hash->hash_block_size())
    {
diff --git a/src/lib/mac/hmac/hmac.h b/src/lib/mac/hmac/hmac.h
index 9258a2f4e..aa709b6db 100644
--- a/src/lib/mac/hmac/hmac.h
+++ b/src/lib/mac/hmac/hmac.h
@@ -21,7 +21,7 @@ class HMAC final : public MessageAuthenticationCode
    public:
       void clear() override;
       std::string name() const override;
-      MessageAuthenticationCode* clone() const override;
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override;
 
       size_t output_length() const override;
 
@@ -30,7 +30,7 @@ class HMAC final : public MessageAuthenticationCode
       /**
       * @param hash the hash to use for HMACing
       */
-      explicit HMAC(HashFunction* hash);
+      explicit HMAC(std::unique_ptr<HashFunction> hash);
 
       HMAC(const HMAC&) = delete;
       HMAC& operator=(const HMAC&) = delete;
diff --git a/src/lib/mac/mac.cpp b/src/lib/mac/mac.cpp
index 90cfff796..e87380a67 100644
--- a/src/lib/mac/mac.cpp
+++ b/src/lib/mac/mac.cpp
@@ -61,7 +61,7 @@ MessageAuthenticationCode::create(const std::string& algo_spec,
       if(provider.empty() || provider == "base")
          {
          if(auto bc = BlockCipher::create(req.arg(0)))
-            return std::make_unique<GMAC>(bc.release());
+            return std::make_unique<GMAC>(std::move(bc));
          }
       }
 #endif
@@ -72,8 +72,8 @@ MessageAuthenticationCode::create(const std::string& algo_spec,
       // TODO OpenSSL
       if(provider.empty() || provider == "base")
          {
-         if(auto h = HashFunction::create(req.arg(0)))
-            return std::make_unique<HMAC>(h.release());
+         if(auto hash = HashFunction::create(req.arg(0)))
+            return std::make_unique<HMAC>(std::move(hash));
          }
       }
 #endif
@@ -103,7 +103,7 @@ MessageAuthenticationCode::create(const std::string& algo_spec,
       if(provider.empty() || provider == "base")
          {
          if(auto bc = BlockCipher::create(req.arg(0)))
-            return std::make_unique<CMAC>(bc.release());
+            return std::make_unique<CMAC>(std::move(bc));
          }
       }
 #endif
diff --git a/src/lib/mac/mac.h b/src/lib/mac/mac.h
index de30b7dbb..8d06be47f 100644
--- a/src/lib/mac/mac.h
+++ b/src/lib/mac/mac.h
@@ -123,10 +123,18 @@ class BOTAN_PUBLIC_API(2,0) MessageAuthenticationCode : public Buffered_Computat
          return verify_mac(in.data(), in.size());
          }
 
+      /**
+      * @return new object representing the same algorithm as *this
+      */
+      virtual std::unique_ptr<MessageAuthenticationCode> new_object() const = 0;
+
       /**
       * Get a new object representing the same algorithm as *this
       */
-      virtual MessageAuthenticationCode* clone() const = 0;
+      MessageAuthenticationCode* clone() const
+         {
+         return this->new_object().release();
+         }
 
       /**
       * @return provider information about this implementation. Default is "base",
diff --git a/src/lib/mac/poly1305/poly1305.h b/src/lib/mac/poly1305/poly1305.h
index 7c1c68c5e..cc5c8eef7 100644
--- a/src/lib/mac/poly1305/poly1305.h
+++ b/src/lib/mac/poly1305/poly1305.h
@@ -22,7 +22,7 @@ class Poly1305 final : public MessageAuthenticationCode
    public:
       std::string name() const override { return "Poly1305"; }
 
-      MessageAuthenticationCode* clone() const override { return new Poly1305; }
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override { return std::make_unique<Poly1305>(); }
 
       void clear() override;
 
diff --git a/src/lib/mac/siphash/siphash.cpp b/src/lib/mac/siphash/siphash.cpp
index bb95de75e..1e0e65299 100644
--- a/src/lib/mac/siphash/siphash.cpp
+++ b/src/lib/mac/siphash/siphash.cpp
@@ -128,9 +128,9 @@ std::string SipHash::name() const
    return "SipHash(" + std::to_string(m_C) + "," + std::to_string(m_D) + ")";
    }
 
-MessageAuthenticationCode* SipHash::clone() const
+std::unique_ptr<MessageAuthenticationCode> SipHash::new_object() const
    {
-   return new SipHash(m_C, m_D);
+   return std::make_unique<SipHash>(m_C, m_D);
    }
 
 }
diff --git a/src/lib/mac/siphash/siphash.h b/src/lib/mac/siphash/siphash.h
index 1412bbb92..398d43ba0 100644
--- a/src/lib/mac/siphash/siphash.h
+++ b/src/lib/mac/siphash/siphash.h
@@ -20,7 +20,7 @@ class SipHash final : public MessageAuthenticationCode
       void clear() override;
       std::string name() const override;
 
-      MessageAuthenticationCode* clone() const override;
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override;
 
       size_t output_length() const override { return 8; }
 
diff --git a/src/lib/mac/x919_mac/x919_mac.cpp b/src/lib/mac/x919_mac/x919_mac.cpp
index 41dca8e13..794d521e4 100644
--- a/src/lib/mac/x919_mac/x919_mac.cpp
+++ b/src/lib/mac/x919_mac/x919_mac.cpp
@@ -81,9 +81,9 @@ std::string ANSI_X919_MAC::name() const
    return "X9.19-MAC";
    }
 
-MessageAuthenticationCode* ANSI_X919_MAC::clone() const
+std::unique_ptr<MessageAuthenticationCode> ANSI_X919_MAC::new_object() const
    {
-   return new ANSI_X919_MAC;
+   return std::make_unique<ANSI_X919_MAC>();
    }
 
 /*
@@ -91,7 +91,7 @@ MessageAuthenticationCode* ANSI_X919_MAC::clone() const
 */
 ANSI_X919_MAC::ANSI_X919_MAC() :
    m_des1(BlockCipher::create("DES")),
-   m_des2(m_des1->clone()),
+   m_des2(m_des1->new_object()),
    m_position(0)
    {
    }
diff --git a/src/lib/mac/x919_mac/x919_mac.h b/src/lib/mac/x919_mac/x919_mac.h
index 4cd8652fc..b7a758f54 100644
--- a/src/lib/mac/x919_mac/x919_mac.h
+++ b/src/lib/mac/x919_mac/x919_mac.h
@@ -23,7 +23,7 @@ class ANSI_X919_MAC final : public MessageAuthenticationCode
       std::string name() const override;
       size_t output_length() const override { return 8; }
 
-      MessageAuthenticationCode* clone() const override;
+      std::unique_ptr<MessageAuthenticationCode> new_object() const override;
 
       Key_Length_Specification key_spec() const override
          {
diff --git a/src/lib/modes/aead/eax/eax.cpp b/src/lib/modes/aead/eax/eax.cpp
index 92d1f358f..94b938a18 100644
--- a/src/lib/modes/aead/eax/eax.cpp
+++ b/src/lib/modes/aead/eax/eax.cpp
@@ -38,8 +38,8 @@ secure_vector<uint8_t> eax_prf(uint8_t tag, size_t block_size,
 EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) :
    m_tag_size(tag_size),
    m_cipher(cipher),
-   m_ctr(new CTR_BE(m_cipher->clone())),
-   m_cmac(new CMAC(m_cipher->clone()))
+   m_ctr(new CTR_BE(m_cipher->new_object())),
+   m_cmac(new CMAC(m_cipher->new_object()))
    {
    if(m_tag_size < 8 || m_tag_size > m_cmac->output_length())
       throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size));
diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp
index bfb11fe4d..aa736f776 100644
--- a/src/lib/modes/aead/gcm/gcm.cpp
+++ b/src/lib/modes/aead/gcm/gcm.cpp
@@ -19,7 +19,7 @@ namespace Botan {
 GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) :
    m_tag_size(tag_size),
    m_cipher_name(cipher->name()),
-   m_ctr(new CTR_BE(cipher, 4)),
+   m_ctr(new CTR_BE(std::unique_ptr<BlockCipher>(cipher), 4)),
    m_ghash(new GHASH)
    {
    if(cipher->block_size() != GCM_BS)
diff --git a/src/lib/modes/aead/siv/siv.cpp b/src/lib/modes/aead/siv/siv.cpp
index 96569ee85..59ae3e991 100644
--- a/src/lib/modes/aead/siv/siv.cpp
+++ b/src/lib/modes/aead/siv/siv.cpp
@@ -16,10 +16,11 @@ namespace Botan {
 
 SIV_Mode::SIV_Mode(BlockCipher* cipher) :
    m_name(cipher->name() + "/SIV"),
-   m_ctr(new CTR_BE(cipher->clone(), 8)),
-   m_mac(new CMAC(cipher)),
+   m_ctr(new CTR_BE(cipher->new_object(), 8)),
+   m_mac(new CMAC(cipher->new_object())),
    m_bs(cipher->block_size())
    {
+   delete cipher; // fixme
    // Not really true but only 128 bit allowed at the moment
    if(m_bs != 16)
       throw Invalid_Argument("SIV requires a 128 bit block cipher");
diff --git a/src/lib/prov/commoncrypto/commoncrypto_block.cpp b/src/lib/prov/commoncrypto/commoncrypto_block.cpp
index 417e765bd..053b195f7 100644
--- a/src/lib/prov/commoncrypto/commoncrypto_block.cpp
+++ b/src/lib/prov/commoncrypto/commoncrypto_block.cpp
@@ -26,7 +26,7 @@ class CommonCrypto_BlockCipher final : public BlockCipher
       void clear() override;
       std::string provider() const override { return "commoncrypto"; }
       std::string name() const override { return m_cipher_name; }
-      BlockCipher* clone() const override;
+      std::unique_ptr<BlockCipher> new_object() const override;
 
       size_t block_size() const override { return m_opts.block_size; }
 
@@ -120,9 +120,9 @@ void CommonCrypto_BlockCipher::key_schedule(const uint8_t key[], size_t length)
 /*
 * Return a clone of this object
 */
-BlockCipher* CommonCrypto_BlockCipher::clone() const
+std::unique_ptr<BlockCipher> CommonCrypto_BlockCipher::new_object() const
    {
-   return new CommonCrypto_BlockCipher(m_cipher_name, m_opts);
+   return std::make_unique<CommonCrypto_BlockCipher>(m_cipher_name, m_opts);
    }
 
 /*
diff --git a/src/lib/prov/commoncrypto/commoncrypto_hash.cpp b/src/lib/prov/commoncrypto/commoncrypto_hash.cpp
index 40bab29dd..b00ef702d 100644
--- a/src/lib/prov/commoncrypto/commoncrypto_hash.cpp
+++ b/src/lib/prov/commoncrypto/commoncrypto_hash.cpp
@@ -38,9 +38,9 @@ class CommonCrypto_HashFunction final : public HashFunction
       std::string provider() const override { return "commoncrypto"; }
       std::string name() const override { return m_info.name; }
 
-      HashFunction* clone() const override
+      std::unique_ptr<HashFunction> new_object() const override
          {
-         return new CommonCrypto_HashFunction(m_info);
+         return std::make_unique<CommonCrypto_HashFunction>(m_info);
          }
 
       std::unique_ptr<HashFunction> copy_state() const override
diff --git a/src/lib/prov/openssl/openssl_block.cpp b/src/lib/prov/openssl/openssl_block.cpp
index 138f9f9e1..3a893cad3 100644
--- a/src/lib/prov/openssl/openssl_block.cpp
+++ b/src/lib/prov/openssl/openssl_block.cpp
@@ -29,7 +29,7 @@ class OpenSSL_BlockCipher final : public BlockCipher
       void clear() override;
       std::string provider() const override { return "openssl"; }
       std::string name() const override { return m_cipher_name; }
-      BlockCipher* clone() const override;
+      std::unique_ptr<BlockCipher> new_object() const override;
 
       size_t block_size() const override { return m_block_sz; }
 
@@ -166,13 +166,14 @@ void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length)
 /*
 * Return a clone of this object
 */
-BlockCipher* OpenSSL_BlockCipher::clone() const
+std::unique_ptr<BlockCipher> OpenSSL_BlockCipher::new_object() const
    {
-   return new OpenSSL_BlockCipher(m_cipher_name,
-                                  EVP_CIPHER_CTX_cipher(m_encrypt),
-                                  m_cipher_key_spec.minimum_keylength(),
-                                  m_cipher_key_spec.maximum_keylength(),
-                                  m_cipher_key_spec.keylength_multiple());
+   return std::make_unique<OpenSSL_BlockCipher>(
+      m_cipher_name,
+      EVP_CIPHER_CTX_cipher(m_encrypt),
+      m_cipher_key_spec.minimum_keylength(),
+      m_cipher_key_spec.maximum_keylength(),
+      m_cipher_key_spec.keylength_multiple());
    }
 
 /*
diff --git a/src/lib/prov/openssl/openssl_hash.cpp b/src/lib/prov/openssl/openssl_hash.cpp
index a4c04cb9f..fa061f071 100644
--- a/src/lib/prov/openssl/openssl_hash.cpp
+++ b/src/lib/prov/openssl/openssl_hash.cpp
@@ -27,10 +27,10 @@ class OpenSSL_HashFunction final : public HashFunction
       std::string provider() const override { return "openssl"; }
       std::string name() const override { return m_name; }
 
-      HashFunction* clone() const override
+      std::unique_ptr<HashFunction> new_object() const override
          {
          const EVP_MD* algo = EVP_MD_CTX_md(m_md);
-         return new OpenSSL_HashFunction(name(), algo);
+         return std::make_unique<OpenSSL_HashFunction>(name(), algo);
          }
 
       std::unique_ptr<HashFunction> copy_state() const override
diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp
index 748e31cbb..bae4c3776 100644
--- a/src/lib/prov/openssl/openssl_rc4.cpp
+++ b/src/lib/prov/openssl/openssl_rc4.cpp
@@ -38,7 +38,10 @@ class OpenSSL_RC4 final : public StreamCipher
             }
          }
 
-      StreamCipher* clone() const override { return new OpenSSL_RC4(m_skip); }
+      std::unique_ptr<StreamCipher> new_object() const override
+         {
+         return std::make_unique<OpenSSL_RC4>(m_skip);
+         }
 
       Key_Length_Specification key_spec() const override
          {
diff --git a/src/lib/psk_db/psk_db.cpp b/src/lib/psk_db/psk_db.cpp
index 59fa76893..21f3a099e 100644
--- a/src/lib/psk_db/psk_db.cpp
+++ b/src/lib/psk_db/psk_db.cpp
@@ -77,7 +77,7 @@ secure_vector<uint8_t> Encrypted_PSK_Database::get(const std::string& name) cons
 
    const secure_vector<uint8_t> val = base64_decode(val_base64);
 
-   std::unique_ptr<BlockCipher> wrap_cipher(m_cipher->clone());
+   auto wrap_cipher = m_cipher->new_object();
    wrap_cipher->set_key(m_hmac->process(wrapped_name));
 
    return nist_key_unwrap_padded(val.data(), val.size(), *wrap_cipher);
@@ -95,7 +95,7 @@ void Encrypted_PSK_Database::set(const std::string& name, const uint8_t val[], s
                            name.size(),
                            *m_cipher);
 
-   std::unique_ptr<BlockCipher> wrap_cipher(m_cipher->clone());
+   auto wrap_cipher = m_cipher->new_object();
    wrap_cipher->set_key(m_hmac->process(wrapped_name));
    const std::vector<uint8_t> wrapped_key = nist_key_wrap_padded(val, len, *wrap_cipher);
 
diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp
index aa9f8c11c..7825cedc2 100644
--- a/src/lib/stream/chacha/chacha.cpp
+++ b/src/lib/stream/chacha/chacha.cpp
@@ -287,9 +287,9 @@ Key_Length_Specification ChaCha::key_spec() const
    return Key_Length_Specification(16, 32, 16);
    }
 
-StreamCipher* ChaCha::clone() const
+std::unique_ptr<StreamCipher> ChaCha::new_object() const
    {
-   return new ChaCha(m_rounds);
+   return std::make_unique<ChaCha>(m_rounds);
    }
 
 bool ChaCha::valid_iv_length(size_t iv_len) const
diff --git a/src/lib/stream/chacha/chacha.h b/src/lib/stream/chacha/chacha.h
index f6a99531b..e721e8aa3 100644
--- a/src/lib/stream/chacha/chacha.h
+++ b/src/lib/stream/chacha/chacha.h
@@ -47,7 +47,7 @@ class ChaCha final : public StreamCipher
 
       void clear() override;
 
-      StreamCipher* clone() const override;
+      std::unique_ptr<StreamCipher> new_object() const override;
 
       std::string name() const override;
 
diff --git a/src/lib/stream/ctr/ctr.cpp b/src/lib/stream/ctr/ctr.cpp
index af879b26a..7ebc1ec2c 100644
--- a/src/lib/stream/ctr/ctr.cpp
+++ b/src/lib/stream/ctr/ctr.cpp
@@ -12,8 +12,8 @@
 
 namespace Botan {
 
-CTR_BE::CTR_BE(BlockCipher* ciph) :
-   m_cipher(ciph),
+CTR_BE::CTR_BE(std::unique_ptr<BlockCipher> cipher) :
+   m_cipher(std::move(cipher)),
    m_block_size(m_cipher->block_size()),
    m_ctr_size(m_block_size),
    m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
@@ -23,8 +23,8 @@ CTR_BE::CTR_BE(BlockCipher* ciph) :
    {
    }
 
-CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) :
-   m_cipher(cipher),
+CTR_BE::CTR_BE(std::unique_ptr<BlockCipher> cipher, size_t ctr_size) :
+   m_cipher(std::move(cipher)),
    m_block_size(m_cipher->block_size()),
    m_ctr_size(ctr_size),
    m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
@@ -60,9 +60,9 @@ Key_Length_Specification CTR_BE::key_spec() const
    return m_cipher->key_spec();
    }
 
-CTR_BE* CTR_BE::clone() const
+std::unique_ptr<StreamCipher> CTR_BE::new_object() const
    {
-   return new CTR_BE(m_cipher->clone(), m_ctr_size);
+   return std::make_unique<CTR_BE>(m_cipher->new_object(), m_ctr_size);
    }
 
 void CTR_BE::key_schedule(const uint8_t key[], size_t key_len)
diff --git a/src/lib/stream/ctr/ctr.h b/src/lib/stream/ctr/ctr.h
index 09fdcca19..f27fce2d4 100644
--- a/src/lib/stream/ctr/ctr.h
+++ b/src/lib/stream/ctr/ctr.h
@@ -31,16 +31,16 @@ class CTR_BE final : public StreamCipher
 
       std::string name() const override;
 
-      CTR_BE* clone() const override;
+      std::unique_ptr<StreamCipher> new_object() const override;
 
       void clear() override;
 
       /**
       * @param cipher the block cipher to use
       */
-      explicit CTR_BE(BlockCipher* cipher);
+      explicit CTR_BE(std::unique_ptr<BlockCipher>);
 
-      CTR_BE(BlockCipher* cipher, size_t ctr_size);
+      CTR_BE(std::unique_ptr<BlockCipher> cipher, size_t ctr_size);
 
       void seek(uint64_t offset) override;
    private:
diff --git a/src/lib/stream/ofb/ofb.cpp b/src/lib/stream/ofb/ofb.cpp
index 113e253ad..772a77aa7 100644
--- a/src/lib/stream/ofb/ofb.cpp
+++ b/src/lib/stream/ofb/ofb.cpp
@@ -10,8 +10,8 @@
 
 namespace Botan {
 
-OFB::OFB(BlockCipher* cipher) :
-   m_cipher(cipher),
+OFB::OFB(std::unique_ptr<BlockCipher> cipher) :
+   m_cipher(std::move(cipher)),
    m_buffer(m_cipher->block_size()),
    m_buf_pos(0)
    {
@@ -52,9 +52,9 @@ Key_Length_Specification OFB::key_spec() const
    return m_cipher->key_spec();
    }
 
-OFB* OFB::clone() const
+std::unique_ptr<StreamCipher> OFB::new_object() const
    {
-   return new OFB(m_cipher->clone());
+   return std::make_unique<OFB>(m_cipher->new_object());
    }
 
 void OFB::cipher(const uint8_t in[], uint8_t out[], size_t length)
diff --git a/src/lib/stream/ofb/ofb.h b/src/lib/stream/ofb/ofb.h
index 9dd2c204d..dcf42a06a 100644
--- a/src/lib/stream/ofb/ofb.h
+++ b/src/lib/stream/ofb/ofb.h
@@ -31,14 +31,14 @@ class OFB final : public StreamCipher
 
       std::string name() const override;
 
-      OFB* clone() const override;
+      std::unique_ptr<StreamCipher> new_object() const override;
 
       void clear() override;
 
       /**
       * @param cipher the block cipher to use
       */
-      explicit OFB(BlockCipher* cipher);
+      explicit OFB(std::unique_ptr<BlockCipher> cipher);
 
       void seek(uint64_t offset) override;
    private:
diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp
index 4cf82b695..1fbd4e87c 100644
--- a/src/lib/stream/rc4/rc4.cpp
+++ b/src/lib/stream/rc4/rc4.cpp
@@ -29,9 +29,9 @@ void RC4::cipher(const uint8_t in[], uint8_t out[], size_t length)
    m_position += length;
    }
 
-StreamCipher* RC4::clone() const
+std::unique_ptr<StreamCipher> RC4::new_object() const
    {
-   return new RC4(m_SKIP);
+   return std::make_unique<RC4>(m_SKIP);
    }
 
 Key_Length_Specification RC4::key_spec() const
diff --git a/src/lib/stream/rc4/rc4.h b/src/lib/stream/rc4/rc4.h
index 2c130e4d6..49d78c710 100644
--- a/src/lib/stream/rc4/rc4.h
+++ b/src/lib/stream/rc4/rc4.h
@@ -26,7 +26,7 @@ class RC4 final : public StreamCipher
       void clear() override;
       std::string name() const override;
 
-      StreamCipher* clone() const override;
+      std::unique_ptr<StreamCipher> new_object() const override;
 
       Key_Length_Specification key_spec() const override;
 
diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp
index 3582524c8..67c0d654a 100644
--- a/src/lib/stream/salsa20/salsa20.cpp
+++ b/src/lib/stream/salsa20/salsa20.cpp
@@ -259,9 +259,9 @@ Key_Length_Specification Salsa20::key_spec() const
    return Key_Length_Specification(16, 32, 16);
    }
 
-StreamCipher* Salsa20::clone() const
+std::unique_ptr<StreamCipher> Salsa20::new_object() const
    {
-   return new Salsa20;
+   return std::make_unique<Salsa20>();
    }
 
 std::string Salsa20::name() const
diff --git a/src/lib/stream/salsa20/salsa20.h b/src/lib/stream/salsa20/salsa20.h
index 839da2ad0..f9f30837a 100644
--- a/src/lib/stream/salsa20/salsa20.h
+++ b/src/lib/stream/salsa20/salsa20.h
@@ -30,7 +30,7 @@ class Salsa20 final : public StreamCipher
 
       void clear() override;
       std::string name() const override;
-      StreamCipher* clone() const override;
+      std::unique_ptr<StreamCipher> new_object() const override;
 
       static void salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds);
       static void hsalsa20(uint32_t output[8], const uint32_t input[16]);
diff --git a/src/lib/stream/shake_cipher/shake_cipher.cpp b/src/lib/stream/shake_cipher/shake_cipher.cpp
index 96cc7951d..954fc57ae 100644
--- a/src/lib/stream/shake_cipher/shake_cipher.cpp
+++ b/src/lib/stream/shake_cipher/shake_cipher.cpp
@@ -82,9 +82,9 @@ std::string SHAKE_128_Cipher::name() const
    return "SHAKE-128";
    }
 
-StreamCipher* SHAKE_128_Cipher::clone() const
+std::unique_ptr<StreamCipher> SHAKE_128_Cipher::new_object() const
    {
-   return new SHAKE_128_Cipher;
+   return std::make_unique<SHAKE_128_Cipher>();
    }
 
 }
diff --git a/src/lib/stream/shake_cipher/shake_cipher.h b/src/lib/stream/shake_cipher/shake_cipher.h
index a66639919..948513042 100644
--- a/src/lib/stream/shake_cipher/shake_cipher.h
+++ b/src/lib/stream/shake_cipher/shake_cipher.h
@@ -40,7 +40,7 @@ class SHAKE_128_Cipher final : public StreamCipher
 
       void clear() override;
       std::string name() const override;
-      StreamCipher* clone() const override;
+      std::unique_ptr<StreamCipher> new_object() const override;
 
    private:
       void key_schedule(const uint8_t key[], size_t key_len) override;
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
index 7877310f5..ce463181e 100644
--- a/src/lib/stream/stream_cipher.cpp
+++ b/src/lib/stream/stream_cipher.cpp
@@ -53,7 +53,7 @@ std::unique_ptr<StreamCipher> StreamCipher::create(const std::string& algo_spec,
          if(cipher)
             {
             size_t ctr_size = req.arg_as_integer(1, cipher->block_size());
-            return std::make_unique<CTR_BE>(cipher.release(), ctr_size);
+            return std::make_unique<CTR_BE>(std::move(cipher), ctr_size);
             }
          }
       }
@@ -94,8 +94,8 @@ std::unique_ptr<StreamCipher> StreamCipher::create(const std::string& algo_spec,
       {
       if(provider.empty() || provider == "base")
          {
-         if(auto c = BlockCipher::create(req.arg(0)))
-            return std::make_unique<OFB>(c.release());
+         if(auto cipher = BlockCipher::create(req.arg(0)))
+            return std::make_unique<OFB>(std::move(cipher));
          }
       }
 #endif
diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h
index a07f21041..497d89943 100644
--- a/src/lib/stream/stream_cipher.h
+++ b/src/lib/stream/stream_cipher.h
@@ -127,7 +127,15 @@ class BOTAN_PUBLIC_API(2,0) StreamCipher : public SymmetricAlgorithm
       /**
       * @return a new object representing the same algorithm as *this
       */
-      virtual StreamCipher* clone() const = 0;
+      StreamCipher* clone() const
+         {
+         return this->new_object().release();
+         }
+
+      /**
+      * @return new object representing the same algorithm as *this
+      */
+      virtual std::unique_ptr<StreamCipher> new_object() const = 0;
 
       /**
       * Set the offset and the state used later to generate the keystream


Test patch:
diff --git a/src/tests/test_ocb.cpp b/src/tests/test_ocb.cpp
index 5c41d7001..dbb9cbadc 100644
--- a/src/tests/test_ocb.cpp
+++ b/src/tests/test_ocb.cpp
@@ -30,9 +30,9 @@ class OCB_Wide_Test_Block_Cipher final : public Botan::BlockCipher
       size_t block_size() const override { return m_bs; }
       void clear() override { m_key.clear(); }
 
-      Botan::BlockCipher* clone() const override
+      std::unique_ptr<Botan::BlockCipher> new_object() const override
          {
-         return new OCB_Wide_Test_Block_Cipher(m_bs);
+         return std::make_unique<OCB_Wide_Test_Block_Cipher>(m_bs);
          }
 
       void key_schedule(const uint8_t key[], size_t length) override
diff --git a/src/tests/test_tls.cpp b/src/tests/test_tls.cpp
index 40dac7cf6..b2a07b658 100644
--- a/src/tests/test_tls.cpp
+++ b/src/tests/test_tls.cpp
@@ -135,7 +135,10 @@ class TLS_CBC_Tests final : public Text_Based_Test
                return Botan::Key_Length_Specification(0, 0, 1);
                }
 
-            virtual MessageAuthenticationCode* clone() const override { return new ZeroMac(m_mac_len); }
+            virtual std::unique_ptr<MessageAuthenticationCode> new_object() const override
+               {
+               return std::make_unique<ZeroMac>(m_mac_len);
+               }
 
          private:
             void key_schedule(const uint8_t[], size_t) override {}
@@ -167,7 +170,10 @@ class TLS_CBC_Tests final : public Text_Based_Test
                return Botan::Key_Length_Specification(0, 0, 1);
                }
 
-            virtual BlockCipher* clone() const override { return new Noop_Block_Cipher(m_bs); }
+            std::unique_ptr<BlockCipher> new_object() const override
+               {
+               return std::make_unique<Noop_Block_Cipher>(m_bs);
+               }
          private:
             void key_schedule(const uint8_t[], size_t) override {}