aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/algo_factory
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/algo_factory')
-rw-r--r--src/lib/algo_factory/algo_cache.h239
-rw-r--r--src/lib/algo_factory/algo_factory.cpp352
-rw-r--r--src/lib/algo_factory/algo_factory.h225
-rw-r--r--src/lib/algo_factory/info.txt24
-rw-r--r--src/lib/algo_factory/prov_weight.cpp34
5 files changed, 874 insertions, 0 deletions
diff --git a/src/lib/algo_factory/algo_cache.h b/src/lib/algo_factory/algo_cache.h
new file mode 100644
index 000000000..3bd9f0031
--- /dev/null
+++ b/src/lib/algo_factory/algo_cache.h
@@ -0,0 +1,239 @@
+/*
+* An algorithm cache (used by Algorithm_Factory)
+* (C) 2008-2009,2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
+#define BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
+
+#include <botan/types.h>
+#include <botan/internal/stl_util.h>
+#include <mutex>
+#include <string>
+#include <vector>
+#include <map>
+
+namespace Botan {
+
+/**
+* @param prov_name a provider name
+* @return weight for this provider
+*/
+size_t static_provider_weight(const std::string& prov_name);
+
+/**
+* Algorithm_Cache (used by Algorithm_Factory)
+*/
+template<typename T>
+class Algorithm_Cache
+ {
+ public:
+ /**
+ * @param algo_spec names the requested algorithm
+ * @param pref_provider suggests a preferred provider
+ * @return prototype object, or NULL
+ */
+ const T* get(const std::string& algo_spec,
+ const std::string& pref_provider);
+
+ /**
+ * Add a new algorithm implementation to the cache
+ * @param algo the algorithm prototype object
+ * @param requested_name how this name will be requested
+ * @param provider_name is the name of the provider of this prototype
+ */
+ void add(T* algo,
+ const std::string& requested_name,
+ const std::string& provider_name);
+
+ /**
+ * Set the preferred provider
+ * @param algo_spec names the algorithm
+ * @param provider names the preferred provider
+ */
+ void set_preferred_provider(const std::string& algo_spec,
+ const std::string& provider);
+
+ /**
+ * Return the list of providers of this algorithm
+ * @param algo_name names the algorithm
+ * @return list of providers of this algorithm
+ */
+ std::vector<std::string> providers_of(const std::string& algo_name);
+
+ /**
+ * Clear the cache
+ */
+ void clear_cache();
+
+ ~Algorithm_Cache() { clear_cache(); }
+ private:
+ typename std::map<std::string, std::map<std::string, T*> >::const_iterator
+ find_algorithm(const std::string& algo_spec);
+
+ std::mutex mutex;
+ std::map<std::string, std::string> aliases;
+ std::map<std::string, std::string> pref_providers;
+ std::map<std::string, std::map<std::string, T*> > algorithms;
+ };
+
+/*
+* Look for an algorithm implementation in the cache, also checking aliases
+* Assumes object lock is held
+*/
+template<typename T>
+typename std::map<std::string, std::map<std::string, T*> >::const_iterator
+Algorithm_Cache<T>::find_algorithm(const std::string& algo_spec)
+ {
+ auto algo = algorithms.find(algo_spec);
+
+ // Not found? Check if a known alias
+ if(algo == algorithms.end())
+ {
+ auto alias = aliases.find(algo_spec);
+
+ if(alias != aliases.end())
+ algo = algorithms.find(alias->second);
+ }
+
+ return algo;
+ }
+
+/*
+* Look for an algorithm implementation by a particular provider
+*/
+template<typename T>
+const T* Algorithm_Cache<T>::get(const std::string& algo_spec,
+ const std::string& requested_provider)
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+
+ auto algo = find_algorithm(algo_spec);
+ if(algo == algorithms.end()) // algo not found at all (no providers)
+ return nullptr;
+
+ // If a provider is requested specifically, return it or fail entirely
+ if(requested_provider != "")
+ {
+ auto prov = algo->second.find(requested_provider);
+ if(prov != algo->second.end())
+ return prov->second;
+ return nullptr;
+ }
+
+ const T* prototype = nullptr;
+ std::string prototype_provider;
+ size_t prototype_prov_weight = 0;
+
+ const std::string pref_provider = search_map(pref_providers, algo_spec);
+
+ for(auto i = algo->second.begin(); i != algo->second.end(); ++i)
+ {
+ // preferred prov exists, return immediately
+ if(i->first == pref_provider)
+ return i->second;
+
+ const size_t prov_weight = static_provider_weight(i->first);
+
+ if(prototype == nullptr || prov_weight > prototype_prov_weight)
+ {
+ prototype = i->second;
+ prototype_provider = i->first;
+ prototype_prov_weight = prov_weight;
+ }
+ }
+
+ return prototype;
+ }
+
+/*
+* Add an implementation to the cache
+*/
+template<typename T>
+void Algorithm_Cache<T>::add(T* algo,
+ const std::string& requested_name,
+ const std::string& provider)
+ {
+ if(!algo)
+ return;
+
+ std::lock_guard<std::mutex> lock(mutex);
+
+ if(algo->name() != requested_name &&
+ aliases.find(requested_name) == aliases.end())
+ {
+ aliases[requested_name] = algo->name();
+ }
+
+ if(!algorithms[algo->name()][provider])
+ algorithms[algo->name()][provider] = algo;
+ else
+ delete algo;
+ }
+
+/*
+* Find the providers of this algo (if any)
+*/
+template<typename T> std::vector<std::string>
+Algorithm_Cache<T>::providers_of(const std::string& algo_name)
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+
+ std::vector<std::string> providers;
+
+ auto algo = find_algorithm(algo_name);
+ if(algo != algorithms.end())
+ {
+ auto provider = algo->second.begin();
+
+ while(provider != algo->second.end())
+ {
+ providers.push_back(provider->first);
+ ++provider;
+ }
+ }
+
+ return providers;
+ }
+
+/*
+* Set the preferred provider for an algorithm
+*/
+template<typename T>
+void Algorithm_Cache<T>::set_preferred_provider(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+
+ pref_providers[algo_spec] = provider;
+ }
+
+/*
+* Clear out the cache
+*/
+template<typename T>
+void Algorithm_Cache<T>::clear_cache()
+ {
+ auto algo = algorithms.begin();
+
+ while(algo != algorithms.end())
+ {
+ auto provider = algo->second.begin();
+
+ while(provider != algo->second.end())
+ {
+ delete provider->second;
+ ++provider;
+ }
+
+ ++algo;
+ }
+
+ algorithms.clear();
+ }
+
+}
+
+#endif
diff --git a/src/lib/algo_factory/algo_factory.cpp b/src/lib/algo_factory/algo_factory.cpp
new file mode 100644
index 000000000..1683648bd
--- /dev/null
+++ b/src/lib/algo_factory/algo_factory.cpp
@@ -0,0 +1,352 @@
+/*
+* Algorithm Factory
+* (C) 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/algo_factory.h>
+#include <botan/internal/algo_cache.h>
+#include <botan/internal/stl_util.h>
+#include <botan/engine.h>
+#include <botan/exceptn.h>
+
+#include <botan/block_cipher.h>
+#include <botan/stream_cipher.h>
+#include <botan/hash.h>
+#include <botan/mac.h>
+#include <botan/pbkdf.h>
+
+#include <algorithm>
+
+namespace Botan {
+
+namespace {
+
+/*
+* Template functions for the factory prototype/search algorithm
+*/
+template<typename T>
+T* engine_get_algo(Engine*,
+ const SCAN_Name&,
+ Algorithm_Factory&)
+ { return nullptr; }
+
+template<>
+BlockCipher* engine_get_algo(Engine* engine,
+ const SCAN_Name& request,
+ Algorithm_Factory& af)
+ { return engine->find_block_cipher(request, af); }
+
+template<>
+StreamCipher* engine_get_algo(Engine* engine,
+ const SCAN_Name& request,
+ Algorithm_Factory& af)
+ { return engine->find_stream_cipher(request, af); }
+
+template<>
+HashFunction* engine_get_algo(Engine* engine,
+ const SCAN_Name& request,
+ Algorithm_Factory& af)
+ { return engine->find_hash(request, af); }
+
+template<>
+MessageAuthenticationCode* engine_get_algo(Engine* engine,
+ const SCAN_Name& request,
+ Algorithm_Factory& af)
+ { return engine->find_mac(request, af); }
+
+template<>
+PBKDF* engine_get_algo(Engine* engine,
+ const SCAN_Name& request,
+ Algorithm_Factory& af)
+ { return engine->find_pbkdf(request, af); }
+
+template<typename T>
+const T* factory_prototype(const std::string& algo_spec,
+ const std::string& provider,
+ const std::vector<Engine*>& engines,
+ Algorithm_Factory& af,
+ Algorithm_Cache<T>* cache)
+ {
+ if(const T* cache_hit = cache->get(algo_spec, provider))
+ return cache_hit;
+
+ SCAN_Name scan_name(algo_spec);
+
+ if(scan_name.cipher_mode() != "")
+ return nullptr;
+
+ for(size_t i = 0; i != engines.size(); ++i)
+ {
+ if(provider == "" || engines[i]->provider_name() == provider)
+ {
+ if(T* impl = engine_get_algo<T>(engines[i], scan_name, af))
+ cache->add(impl, algo_spec, engines[i]->provider_name());
+ }
+ }
+
+ return cache->get(algo_spec, provider);
+ }
+
+}
+
+/*
+* Setup caches
+*/
+Algorithm_Factory::Algorithm_Factory()
+ {
+ block_cipher_cache = new Algorithm_Cache<BlockCipher>();
+ stream_cipher_cache = new Algorithm_Cache<StreamCipher>();
+ hash_cache = new Algorithm_Cache<HashFunction>();
+ mac_cache = new Algorithm_Cache<MessageAuthenticationCode>();
+ pbkdf_cache = new Algorithm_Cache<PBKDF>();
+ }
+
+/*
+* Delete all engines
+*/
+Algorithm_Factory::~Algorithm_Factory()
+ {
+ delete block_cipher_cache;
+ delete stream_cipher_cache;
+ delete hash_cache;
+ delete mac_cache;
+ delete pbkdf_cache;
+
+ for(auto i = engines.begin(); i != engines.end(); ++i)
+ delete *i;
+ }
+
+void Algorithm_Factory::clear_caches()
+ {
+ block_cipher_cache->clear_cache();
+ stream_cipher_cache->clear_cache();
+ hash_cache->clear_cache();
+ mac_cache->clear_cache();
+ pbkdf_cache->clear_cache();
+ }
+
+void Algorithm_Factory::add_engine(Engine* engine)
+ {
+ clear_caches();
+ engines.push_back(engine);
+ }
+
+/*
+* Set the preferred provider for an algorithm
+*/
+void Algorithm_Factory::set_preferred_provider(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ if(prototype_block_cipher(algo_spec))
+ block_cipher_cache->set_preferred_provider(algo_spec, provider);
+ else if(prototype_stream_cipher(algo_spec))
+ stream_cipher_cache->set_preferred_provider(algo_spec, provider);
+ else if(prototype_hash_function(algo_spec))
+ hash_cache->set_preferred_provider(algo_spec, provider);
+ else if(prototype_mac(algo_spec))
+ mac_cache->set_preferred_provider(algo_spec, provider);
+ else if(prototype_pbkdf(algo_spec))
+ pbkdf_cache->set_preferred_provider(algo_spec, provider);
+ }
+
+/*
+* Get an engine out of the list
+*/
+Engine* Algorithm_Factory::get_engine_n(size_t n) const
+ {
+ if(n >= engines.size())
+ return nullptr;
+ return engines[n];
+ }
+
+/*
+* Return the possible providers of a request
+* Note: assumes you don't have different types by the same name
+*/
+std::vector<std::string>
+Algorithm_Factory::providers_of(const std::string& algo_spec)
+ {
+ /* The checks with if(prototype_X(algo_spec)) have the effect of
+ forcing a full search, since otherwise there might not be any
+ providers at all in the cache.
+ */
+
+ if(prototype_block_cipher(algo_spec))
+ return block_cipher_cache->providers_of(algo_spec);
+ else if(prototype_stream_cipher(algo_spec))
+ return stream_cipher_cache->providers_of(algo_spec);
+ else if(prototype_hash_function(algo_spec))
+ return hash_cache->providers_of(algo_spec);
+ else if(prototype_mac(algo_spec))
+ return mac_cache->providers_of(algo_spec);
+ else if(prototype_pbkdf(algo_spec))
+ return pbkdf_cache->providers_of(algo_spec);
+ else
+ return std::vector<std::string>();
+ }
+
+/*
+* Return the prototypical block cipher corresponding to this request
+*/
+const BlockCipher*
+Algorithm_Factory::prototype_block_cipher(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ return factory_prototype<BlockCipher>(algo_spec, provider, engines,
+ *this, block_cipher_cache);
+ }
+
+/*
+* Return the prototypical stream cipher corresponding to this request
+*/
+const StreamCipher*
+Algorithm_Factory::prototype_stream_cipher(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ return factory_prototype<StreamCipher>(algo_spec, provider, engines,
+ *this, stream_cipher_cache);
+ }
+
+/*
+* Return the prototypical object corresponding to this request (if found)
+*/
+const HashFunction*
+Algorithm_Factory::prototype_hash_function(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ return factory_prototype<HashFunction>(algo_spec, provider, engines,
+ *this, hash_cache);
+ }
+
+/*
+* Return the prototypical object corresponding to this request
+*/
+const MessageAuthenticationCode*
+Algorithm_Factory::prototype_mac(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ return factory_prototype<MessageAuthenticationCode>(algo_spec, provider,
+ engines,
+ *this, mac_cache);
+ }
+
+/*
+* Return the prototypical object corresponding to this request
+*/
+const PBKDF*
+Algorithm_Factory::prototype_pbkdf(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ return factory_prototype<PBKDF>(algo_spec, provider,
+ engines,
+ *this, pbkdf_cache);
+ }
+
+/*
+* Return a new block cipher corresponding to this request
+*/
+BlockCipher*
+Algorithm_Factory::make_block_cipher(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ if(const BlockCipher* proto = prototype_block_cipher(algo_spec, provider))
+ return proto->clone();
+ throw Algorithm_Not_Found(algo_spec);
+ }
+
+/*
+* Return a new stream cipher corresponding to this request
+*/
+StreamCipher*
+Algorithm_Factory::make_stream_cipher(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ if(const StreamCipher* proto = prototype_stream_cipher(algo_spec, provider))
+ return proto->clone();
+ throw Algorithm_Not_Found(algo_spec);
+ }
+
+/*
+* Return a new object corresponding to this request
+*/
+HashFunction*
+Algorithm_Factory::make_hash_function(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ if(const HashFunction* proto = prototype_hash_function(algo_spec, provider))
+ return proto->clone();
+ throw Algorithm_Not_Found(algo_spec);
+ }
+
+/*
+* Return a new object corresponding to this request
+*/
+MessageAuthenticationCode*
+Algorithm_Factory::make_mac(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ if(const MessageAuthenticationCode* proto = prototype_mac(algo_spec, provider))
+ return proto->clone();
+ throw Algorithm_Not_Found(algo_spec);
+ }
+
+/*
+* Return a new object corresponding to this request
+*/
+PBKDF*
+Algorithm_Factory::make_pbkdf(const std::string& algo_spec,
+ const std::string& provider)
+ {
+ if(const PBKDF* proto = prototype_pbkdf(algo_spec, provider))
+ return proto->clone();
+ throw Algorithm_Not_Found(algo_spec);
+ }
+
+/*
+* Add a new block cipher
+*/
+void Algorithm_Factory::add_block_cipher(BlockCipher* block_cipher,
+ const std::string& provider)
+ {
+ block_cipher_cache->add(block_cipher, block_cipher->name(), provider);
+ }
+
+/*
+* Add a new stream cipher
+*/
+void Algorithm_Factory::add_stream_cipher(StreamCipher* stream_cipher,
+ const std::string& provider)
+ {
+ stream_cipher_cache->add(stream_cipher, stream_cipher->name(), provider);
+ }
+
+/*
+* Add a new hash
+*/
+void Algorithm_Factory::add_hash_function(HashFunction* hash,
+ const std::string& provider)
+ {
+ hash_cache->add(hash, hash->name(), provider);
+ }
+
+/*
+* Add a new mac
+*/
+void Algorithm_Factory::add_mac(MessageAuthenticationCode* mac,
+ const std::string& provider)
+ {
+ mac_cache->add(mac, mac->name(), provider);
+ }
+
+/*
+* Add a new PBKDF
+*/
+void Algorithm_Factory::add_pbkdf(PBKDF* pbkdf,
+ const std::string& provider)
+ {
+ pbkdf_cache->add(pbkdf, pbkdf->name(), provider);
+ }
+
+}
diff --git a/src/lib/algo_factory/algo_factory.h b/src/lib/algo_factory/algo_factory.h
new file mode 100644
index 000000000..201982766
--- /dev/null
+++ b/src/lib/algo_factory/algo_factory.h
@@ -0,0 +1,225 @@
+/*
+* Algorithm Factory
+* (C) 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ALGORITHM_FACTORY_H__
+#define BOTAN_ALGORITHM_FACTORY_H__
+
+#include <botan/types.h>
+#include <string>
+#include <vector>
+
+namespace Botan {
+
+/**
+* Forward declarations (don't need full definitions here)
+*/
+class BlockCipher;
+class StreamCipher;
+class HashFunction;
+class MessageAuthenticationCode;
+class PBKDF;
+
+template<typename T> class Algorithm_Cache;
+
+class Engine;
+
+/**
+* Algorithm Factory
+*/
+class BOTAN_DLL Algorithm_Factory
+ {
+ public:
+ /**
+ * Constructor
+ */
+ Algorithm_Factory();
+
+ /**
+ * Destructor
+ */
+ ~Algorithm_Factory();
+
+ /**
+ * @param engine to add (Algorithm_Factory takes ownership)
+ */
+ void add_engine(Engine* engine);
+
+ /**
+ * Clear out any cached objects
+ */
+ void clear_caches();
+
+ /**
+ * @param algo_spec the algorithm we are querying
+ * @returns list of providers of this algorithm
+ */
+ std::vector<std::string> providers_of(const std::string& algo_spec);
+
+ /**
+ * @param algo_spec the algorithm we are setting a provider for
+ * @param provider the provider we would like to use
+ */
+ void set_preferred_provider(const std::string& algo_spec,
+ const std::string& provider);
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to const prototype object, ready to clone(), or NULL
+ */
+ const BlockCipher*
+ prototype_block_cipher(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to freshly created instance of the request algorithm
+ */
+ BlockCipher* make_block_cipher(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo the algorithm to add
+ * @param provider the provider of this algorithm
+ */
+ void add_block_cipher(BlockCipher* algo, const std::string& provider);
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to const prototype object, ready to clone(), or NULL
+ */
+ const StreamCipher*
+ prototype_stream_cipher(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to freshly created instance of the request algorithm
+ */
+ StreamCipher* make_stream_cipher(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo the algorithm to add
+ * @param provider the provider of this algorithm
+ */
+ void add_stream_cipher(StreamCipher* algo, const std::string& provider);
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to const prototype object, ready to clone(), or NULL
+ */
+ const HashFunction*
+ prototype_hash_function(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to freshly created instance of the request algorithm
+ */
+ HashFunction* make_hash_function(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo the algorithm to add
+ * @param provider the provider of this algorithm
+ */
+ void add_hash_function(HashFunction* algo, const std::string& provider);
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to const prototype object, ready to clone(), or NULL
+ */
+ const MessageAuthenticationCode*
+ prototype_mac(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to freshly created instance of the request algorithm
+ */
+ MessageAuthenticationCode* make_mac(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo the algorithm to add
+ * @param provider the provider of this algorithm
+ */
+ void add_mac(MessageAuthenticationCode* algo,
+ const std::string& provider);
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to const prototype object, ready to clone(), or NULL
+ */
+ const PBKDF* prototype_pbkdf(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo_spec the algorithm we want
+ * @param provider the provider we would like to use
+ * @returns pointer to freshly created instance of the request algorithm
+ */
+ PBKDF* make_pbkdf(const std::string& algo_spec,
+ const std::string& provider = "");
+
+ /**
+ * @param algo the algorithm to add
+ * @param provider the provider of this algorithm
+ */
+ void add_pbkdf(PBKDF* algo, const std::string& provider);
+
+ /**
+ * An iterator for the engines in this factory
+ * @deprecated Avoid in new code
+ */
+ class BOTAN_DLL Engine_Iterator
+ {
+ public:
+ /**
+ * @return next engine in the sequence
+ */
+ Engine* next() { return af.get_engine_n(n++); }
+
+ /**
+ * @param a an algorithm factory
+ */
+ Engine_Iterator(const Algorithm_Factory& a) :
+ af(a) { n = 0; }
+ private:
+ const Algorithm_Factory& af;
+ size_t n;
+ };
+ friend class Engine_Iterator;
+
+ private:
+ Algorithm_Factory(const Algorithm_Factory&) {}
+ Algorithm_Factory& operator=(const Algorithm_Factory&)
+ { return (*this); }
+
+ Engine* get_engine_n(size_t n) const;
+
+ std::vector<Engine*> engines;
+
+ Algorithm_Cache<BlockCipher>* block_cipher_cache;
+ Algorithm_Cache<StreamCipher>* stream_cipher_cache;
+ Algorithm_Cache<HashFunction>* hash_cache;
+ Algorithm_Cache<MessageAuthenticationCode>* mac_cache;
+ Algorithm_Cache<PBKDF>* pbkdf_cache;
+ };
+
+}
+
+#endif
diff --git a/src/lib/algo_factory/info.txt b/src/lib/algo_factory/info.txt
new file mode 100644
index 000000000..837ced1d0
--- /dev/null
+++ b/src/lib/algo_factory/info.txt
@@ -0,0 +1,24 @@
+load_on auto
+
+define ALGORITHM_FACTORY 20131128
+
+<header:public>
+algo_factory.h
+</header:public>
+
+<header:internal>
+algo_cache.h
+</header:internal>
+
+<source>
+algo_factory.cpp
+prov_weight.cpp
+</source>
+
+<requires>
+block
+engine
+hash
+mac
+stream
+</requires>
diff --git a/src/lib/algo_factory/prov_weight.cpp b/src/lib/algo_factory/prov_weight.cpp
new file mode 100644
index 000000000..fca791333
--- /dev/null
+++ b/src/lib/algo_factory/prov_weight.cpp
@@ -0,0 +1,34 @@
+/*
+* Default provider weights for Algorithm_Cache
+* (C) 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/algo_cache.h>
+
+namespace Botan {
+
+/**
+* Return a static provider weighing
+*/
+size_t static_provider_weight(const std::string& prov_name)
+ {
+ /*
+ * Prefer asm over C++, but prefer anything over OpenSSL or GNU MP; to use
+ * them, set the provider explicitly for the algorithms you want
+ */
+
+ if(prov_name == "aes_isa") return 9;
+ if(prov_name == "simd") return 8;
+ if(prov_name == "asm") return 7;
+
+ if(prov_name == "core") return 5;
+
+ if(prov_name == "openssl") return 2;
+ if(prov_name == "gmp") return 1;
+
+ return 0; // other/unknown
+ }
+
+}