diff options
author | lloyd <[email protected]> | 2015-02-04 04:03:38 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2015-02-04 04:03:38 +0000 |
commit | 0dd060fed07b0060f94e3bae62e125a85c1bb877 (patch) | |
tree | ed4bc7a961e2b30f17ed5e80769c84b0c313c8b7 /src/lib/base | |
parent | f9a7c85b74be0f4a7273e8e0591703af83036e81 (diff) |
Remove algo factory, engines, global RNG, global state, etc.
Convert all uses of Algorithm_Factory and the engines to using Algo_Registry
The shared pool of entropy sources remains but is moved to EntropySource.
With that and few remaining initializations (default OIDs and aliases)
moved elsewhere, the global state is empty and init and shutdown are no-ops.
Remove almost all of the headers and code for handling the global
state, except LibraryInitializer which remains as a compatability stub.
Update seeding for blinding so only one hacky almost-global RNG
instance needs to be setup instead of across all pubkey uses (it uses
either the system RNG or an AutoSeeded_RNG if the system RNG is not
available).
Diffstat (limited to 'src/lib/base')
-rw-r--r-- | src/lib/base/algo_registry.h | 215 | ||||
-rw-r--r-- | src/lib/base/botan.h | 21 | ||||
-rw-r--r-- | src/lib/base/buf_comp.h | 171 | ||||
-rw-r--r-- | src/lib/base/info.txt | 29 | ||||
-rw-r--r-- | src/lib/base/init.h | 33 | ||||
-rw-r--r-- | src/lib/base/key_spec.h | 95 | ||||
-rw-r--r-- | src/lib/base/lookup.cpp | 78 | ||||
-rw-r--r-- | src/lib/base/lookup.h | 82 | ||||
-rw-r--r-- | src/lib/base/scan_name.cpp | 221 | ||||
-rw-r--r-- | src/lib/base/scan_name.h | 121 | ||||
-rw-r--r-- | src/lib/base/sym_algo.h | 99 | ||||
-rw-r--r-- | src/lib/base/symkey.cpp | 132 | ||||
-rw-r--r-- | src/lib/base/symkey.h | 143 | ||||
-rw-r--r-- | src/lib/base/transform.h | 182 |
14 files changed, 1622 insertions, 0 deletions
diff --git a/src/lib/base/algo_registry.h b/src/lib/base/algo_registry.h new file mode 100644 index 000000000..9582180bd --- /dev/null +++ b/src/lib/base/algo_registry.h @@ -0,0 +1,215 @@ +/* +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ALGO_REGISTRY_H__ +#define BOTAN_ALGO_REGISTRY_H__ + +#include <botan/types.h> +#include <functional> +#include <stdexcept> +#include <mutex> +#include <vector> +#include <map> +#include <unordered_map> + +namespace Botan { + +template<typename T> +class Algo_Registry + { + public: + typedef typename T::Spec Spec; + + typedef std::function<T* (const Spec&)> maker_fn; + + static Algo_Registry<T>& global_registry() + { + static Algo_Registry<T> g_registry; + return g_registry; + } + + void add(const std::string& name, const std::string& provider, maker_fn fn, byte pref) + { + std::unique_lock<std::mutex> lock(m_mutex); + m_algo_info[name].add_provider(provider, fn, pref); + } + + std::vector<std::string> providers_of(const Spec& spec) + { + std::unique_lock<std::mutex> lock(m_mutex); + auto i = m_algo_info.find(spec.algo_name()); + if(i != m_algo_info.end()) + return i->second.providers(); + return std::vector<std::string>(); + } + + T* make(const Spec& spec, const std::string& provider = "") + { + maker_fn maker = find_maker(spec, provider); + + try + { + return maker(spec); + } + catch(std::exception& e) + { + throw std::runtime_error("Creating '" + spec.as_string() + "' failed: " + e.what()); + } + } + + class Add + { + public: + Add(const std::string& basename, maker_fn fn, const std::string& provider = "builtin", byte pref = 128) + { + Algo_Registry<T>::global_registry().add(basename, provider, fn, pref); + } + + Add(bool cond, const std::string& basename, maker_fn fn, const std::string& provider, byte pref) + { + if(cond) + Algo_Registry<T>::global_registry().add(basename, provider, fn, pref); + } + }; + + private: + Algo_Registry() {} + + maker_fn find_maker(const Spec& spec, const std::string& provider) + { + std::unique_lock<std::mutex> lock(m_mutex); + return m_algo_info[spec.algo_name()].get_maker(provider); + } + + struct Algo_Info + { + public: + void add_provider(const std::string& provider, maker_fn fn, byte pref = 128) + { + if(m_maker_fns.count(provider) > 0) + throw std::runtime_error("Duplicated registration of '" + provider + "'"); + + m_maker_fns[provider] = std::make_pair(pref, fn); + } + + std::vector<std::string> providers() const + { + std::vector<std::string> v; + for(auto&& k : m_maker_fns) + v.push_back(k.first); + return v; + } + + void set_pref(const std::string& provider, byte val) + { + m_maker_fns[provider].first = val; + } + + maker_fn get_maker(const std::string& req_provider) + { + maker_fn null_result = [](const Spec&) { return nullptr; }; + + if(req_provider != "") + { + // find one explicit provider requested by user or fail + auto i = m_maker_fns.find(req_provider); + if(i != m_maker_fns.end()) + return i->second.second; + return null_result; + } + + size_t pref = 255; + maker_fn result = null_result; + + for(auto&& i : m_maker_fns) + { + if(i.second.first < pref) + { + pref = i.second.first; + result = i.second.second; + } + } + + return result; + } + private: + std::unordered_map<std::string, std::pair<byte, maker_fn>> m_maker_fns; // provider -> (pref, creator fn) + }; + + std::mutex m_mutex; + std::unordered_map<std::string, Algo_Info> m_algo_info; + }; + +template<typename T> T* +make_a(const typename T::Spec& spec, const std::string provider = "") + { + return Algo_Registry<T>::global_registry().make(spec, provider); + } + +template<typename T> std::vector<std::string> providers_of(const typename T::Spec& spec) + { + return Algo_Registry<T>::global_registry().providers_of(spec); + } + +template<typename T> T* +make_new_T(const typename Algo_Registry<T>::Spec&) { return new T; } + +template<typename T, size_t DEF_VAL> T* +make_new_T_1len(const typename Algo_Registry<T>::Spec& spec) + { + return new T(spec.arg_as_integer(0, DEF_VAL)); + } + +template<typename T, size_t DEF1, size_t DEF2> T* +make_new_T_2len(const typename Algo_Registry<T>::Spec& spec) + { + return new T(spec.arg_as_integer(0, DEF1), spec.arg_as_integer(1, DEF2)); + } + +template<typename T> T* +make_new_T_1str(const typename Algo_Registry<T>::Spec& spec, const std::string& def) + { + return new T(spec.arg(0, def)); + } + +template<typename T> T* +make_new_T_1str_req(const typename Algo_Registry<T>::Spec& spec) + { + return new T(spec.arg(0)); + } + +template<typename T, typename X> T* +make_new_T_1X(const typename Algo_Registry<T>::Spec& spec) + { + std::unique_ptr<X> x(Algo_Registry<X>::global_registry().make(spec.arg(0))); + if(!x) + throw std::runtime_error(spec.arg(0)); + return new T(x.release()); + } + +#define BOTAN_REGISTER_NAMED_T(T, namestr, type, maker) \ + namespace { Algo_Registry<T>::Add g_ ## type ## _reg(namestr, maker); } +#define BOTAN_REGISTER_T(T, name, maker) \ + namespace { Algo_Registry<T>::Add g_ ## name ## _reg(#name, maker); } +#define BOTAN_REGISTER_T_NOARGS(T, name) \ + namespace { Algo_Registry<T>::Add g_ ## name ## _reg(#name, make_new_T<name>); } +#define BOTAN_REGISTER_T_1LEN(T, name, def) \ + namespace { Algo_Registry<T>::Add g_ ## name ## _reg(#name, make_new_T_1len<name, def>); } + +#define BOTAN_REGISTER_NAMED_T_NOARGS(T, type, name, provider) \ + namespace { Algo_Registry<T>::Add g_ ## type ## _reg(name, make_new_T<type>, provider); } +#define BOTAN_COND_REGISTER_NAMED_T_NOARGS(cond, T, type, name, provider, pref) \ + namespace { Algo_Registry<T>::Add g_ ## type ## _reg(cond, name, make_new_T<type>, provider, pref); } +#define BOTAN_REGISTER_NAMED_T_2LEN(T, type, name, provider, len1, len2) \ + namespace { Algo_Registry<T>::Add g_ ## type ## _reg(name, make_new_T_2len<type, len1, len2>, provider); } + +// TODO move elsewhere: +#define BOTAN_REGISTER_TRANSFORM(name, maker) BOTAN_REGISTER_T(Transform, name, maker) +#define BOTAN_REGISTER_TRANSFORM_NOARGS(name) BOTAN_REGISTER_T_NOARGS(Transform, name) + +} + +#endif diff --git a/src/lib/base/botan.h b/src/lib/base/botan.h new file mode 100644 index 000000000..0d8749155 --- /dev/null +++ b/src/lib/base/botan.h @@ -0,0 +1,21 @@ +/* +* A vague catch all include file for Botan +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BOTAN_H__ +#define BOTAN_BOTAN_H__ + +#include <botan/lookup.h> +#include <botan/version.h> +#include <botan/parsing.h> + +#include <botan/rng.h> + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include <botan/auto_rng.h> +#endif + +#endif diff --git a/src/lib/base/buf_comp.h b/src/lib/base/buf_comp.h new file mode 100644 index 000000000..5d11fdb73 --- /dev/null +++ b/src/lib/base/buf_comp.h @@ -0,0 +1,171 @@ +/* +* Buffered Computation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BUFFERED_COMPUTATION_H__ +#define BOTAN_BUFFERED_COMPUTATION_H__ + +#include <botan/secmem.h> +#include <botan/get_byte.h> +#include <string> + +namespace Botan { + +/** +* This class represents any kind of computation which uses an internal +* state, such as hash functions or MACs +*/ +class BOTAN_DLL Buffered_Computation + { + public: + /** + * @return length of the output of this function in bytes + */ + virtual size_t output_length() const = 0; + + /** + * Add new input to process. + * @param in the input to process as a byte array + * @param length of param in in bytes + */ + void update(const byte in[], size_t length) { add_data(in, length); } + + /** + * Add new input to process. + * @param in the input to process as a secure_vector + */ + void update(const secure_vector<byte>& in) + { + add_data(&in[0], in.size()); + } + + /** + * Add new input to process. + * @param in the input to process as a std::vector + */ + void update(const std::vector<byte>& in) + { + add_data(&in[0], in.size()); + } + + /** + * Add an integer in big-endian order + * @param in the value + */ + template<typename T> void update_be(const T in) + { + for(size_t i = 0; i != sizeof(T); ++i) + { + byte b = get_byte(i, in); + add_data(&b, 1); + } + } + + /** + * Add new input to process. + * @param str the input to process as a std::string. Will be interpreted + * as a byte array based on + * the strings encoding. + */ + void update(const std::string& str) + { + add_data(reinterpret_cast<const byte*>(str.data()), str.size()); + } + + /** + * Process a single byte. + * @param in the byte to process + */ + void update(byte in) { add_data(&in, 1); } + + /** + * Complete the computation and retrieve the + * final result. + * @param out The byte array to be filled with the result. + * Must be of length output_length() + */ + void final(byte out[]) { final_result(out); } + + /** + * Complete the computation and retrieve the + * final result. + * @return secure_vector holding the result + */ + secure_vector<byte> final() + { + secure_vector<byte> output(output_length()); + final_result(&output[0]); + return output; + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a byte array + * @param length the length of the byte array + * @result the result of the call to final() + */ + secure_vector<byte> process(const byte in[], size_t length) + { + add_data(in, length); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector<byte> process(const secure_vector<byte>& in) + { + add_data(&in[0], in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector<byte> process(const std::vector<byte>& in) + { + add_data(&in[0], in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a string + * @result the result of the call to final() + */ + secure_vector<byte> process(const std::string& in) + { + update(in); + return final(); + } + + virtual ~Buffered_Computation() {} + private: + /** + * Add more data to the computation + * @param input is an input buffer + * @param length is the length of input in bytes + */ + virtual void add_data(const byte input[], size_t length) = 0; + + /** + * Write the final output to out + * @param out is an output buffer of output_length() + */ + virtual void final_result(byte out[]) = 0; + }; + +} + +#endif diff --git a/src/lib/base/info.txt b/src/lib/base/info.txt new file mode 100644 index 000000000..581c40fe0 --- /dev/null +++ b/src/lib/base/info.txt @@ -0,0 +1,29 @@ +<header:public> +botan.h +buf_comp.h +init.h +key_spec.h +lookup.h +scan_name.h +sym_algo.h +symkey.h +transform.h +</header:public> + +<header:internal> +algo_registry.h +</header:internal> + +define TRANSFORM 20131209 + +<requires> +alloc +block +hash +hex +mac +modes +rng +stream +utils +</requires> diff --git a/src/lib/base/init.h b/src/lib/base/init.h new file mode 100644 index 000000000..96e676d63 --- /dev/null +++ b/src/lib/base/init.h @@ -0,0 +1,33 @@ +/* +* Library Initialization +* (C) 1999-2008,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LIBRARY_INITIALIZER_H__ +#define BOTAN_LIBRARY_INITIALIZER_H__ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/* +* Previously botan had state whose lifetime had to be explicitly +* managed by the application. As of 1.11.14 this is no longer the +* case, and this class is no longer needed and kept only for backwards +* compatability. +*/ +class BOTAN_DLL LibraryInitializer + { + public: + LibraryInitializer(const std::string& = "") {} + ~LibraryInitializer() {} + static void initialize(const std::string& = "") {} + static void deinitialize() {} + }; + +} + +#endif diff --git a/src/lib/base/key_spec.h b/src/lib/base/key_spec.h new file mode 100644 index 000000000..78b6b8a23 --- /dev/null +++ b/src/lib/base/key_spec.h @@ -0,0 +1,95 @@ +/* +* Symmetric Key Length Specification +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEY_LEN_SPECIFICATION_H__ +#define BOTAN_KEY_LEN_SPECIFICATION_H__ + +#include <botan/types.h> + +namespace Botan { + +/** +* Represents the length requirements on an algorithm key +*/ +class BOTAN_DLL Key_Length_Specification + { + public: + /** + * Constructor for fixed length keys + * @param keylen the supported key length + */ + Key_Length_Specification(size_t keylen) : + min_keylen(keylen), + max_keylen(keylen), + keylen_mod(1) + { + } + + /** + * Constructor for variable length keys + * @param min_k the smallest supported key length + * @param max_k the largest supported key length + * @param k_mod the number of bytes the key must be a multiple of + */ + Key_Length_Specification(size_t min_k, + size_t max_k, + size_t k_mod = 1) : + min_keylen(min_k), + max_keylen(max_k ? max_k : min_k), + keylen_mod(k_mod) + { + } + + /** + * @param length is a key length in bytes + * @return true iff this length is a valid length for this algo + */ + bool valid_keylength(size_t length) const + { + return ((length >= min_keylen) && + (length <= max_keylen) && + (length % keylen_mod == 0)); + } + + /** + * @return minimum key length in bytes + */ + size_t minimum_keylength() const + { + return min_keylen; + } + + /** + * @return maximum key length in bytes + */ + size_t maximum_keylength() const + { + return max_keylen; + } + + /** + * @return key length multiple in bytes + */ + size_t keylength_multiple() const + { + return keylen_mod; + } + + Key_Length_Specification multiple(size_t n) const + { + return Key_Length_Specification(n * min_keylen, + n * max_keylen, + n * keylen_mod); + } + + private: + size_t min_keylen, max_keylen, keylen_mod; + }; + +} + +#endif diff --git a/src/lib/base/lookup.cpp b/src/lib/base/lookup.cpp new file mode 100644 index 000000000..e82866e37 --- /dev/null +++ b/src/lib/base/lookup.cpp @@ -0,0 +1,78 @@ +/* +* Algorithm Retrieval +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/lookup.h> +#include <botan/internal/algo_registry.h> +#include <botan/cipher_mode.h> +#include <botan/transform_filter.h> +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> +#include <botan/hash.h> +#include <botan/mac.h> +#include <botan/pbkdf.h> + +namespace Botan { + +Transform* get_transform(const std::string& specstr, + const std::string& provider, + const std::string& dirstr) + { + Algo_Registry<Transform>::Spec spec(specstr, dirstr); + return Algo_Registry<Transform>::global_registry().make(spec, provider); + } + +BlockCipher* get_block_cipher(const std::string& algo_spec, const std::string& provider) + { + return make_a<BlockCipher>(algo_spec, provider); + } + +StreamCipher* get_stream_cipher(const std::string& algo_spec, const std::string& provider) + { + return make_a<StreamCipher>(algo_spec, provider); + } + +HashFunction* get_hash_function(const std::string& algo_spec, const std::string& provider) + { + return make_a<HashFunction>(algo_spec, provider); + } + +MessageAuthenticationCode* get_mac(const std::string& algo_spec, const std::string& provider) + { + return make_a<MessageAuthenticationCode>(algo_spec, provider); + } + +std::vector<std::string> get_block_cipher_providers(const std::string& algo_spec) + { + return providers_of<BlockCipher>(BlockCipher::Spec(algo_spec)); + } + +std::vector<std::string> get_stream_cipher_providers(const std::string& algo_spec) + { + return providers_of<StreamCipher>(StreamCipher::Spec(algo_spec)); + } + +std::vector<std::string> get_hash_function_providers(const std::string& algo_spec) + { + return providers_of<HashFunction>(HashFunction::Spec(algo_spec)); + } + +std::vector<std::string> get_mac_providers(const std::string& algo_spec) + { + return providers_of<MessageAuthenticationCode>(MessageAuthenticationCode::Spec(algo_spec)); + } + +/* +* Get a PBKDF algorithm by name +*/ +PBKDF* get_pbkdf(const std::string& algo_spec, const std::string& provider) + { + if(PBKDF* pbkdf = make_a<PBKDF>(algo_spec, provider)) + return pbkdf; + throw Algorithm_Not_Found(algo_spec); + } + +} diff --git a/src/lib/base/lookup.h b/src/lib/base/lookup.h new file mode 100644 index 000000000..c50186e35 --- /dev/null +++ b/src/lib/base/lookup.h @@ -0,0 +1,82 @@ +/* +* Algorithm Lookup +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LOOKUP_H__ +#define BOTAN_LOOKUP_H__ + +#include <botan/symkey.h> +#include <string> + +namespace Botan { + +class BlockCipher; +class StreamCipher; +class HashFunction; +class MessageAuthenticationCode; +class PBKDF; + +/* +* Get an algorithm object +* NOTE: these functions create and return new objects, letting the +* caller assume ownership of them +*/ + +/** +* Block cipher factory method. +* +* @param algo_spec the name of the desired block cipher +* @return pointer to the block cipher object +*/ +BOTAN_DLL BlockCipher* get_block_cipher(const std::string& algo_spec, const std::string& provider = ""); + +BOTAN_DLL std::vector<std::string> get_block_cipher_providers(const std::string& algo_spec); + +/** +* Stream cipher factory method. +* +* @param algo_spec the name of the desired stream cipher +* @return pointer to the stream cipher object +*/ +BOTAN_DLL StreamCipher* get_stream_cipher(const std::string& algo_spec, const std::string& provider = ""); + +BOTAN_DLL std::vector<std::string> get_stream_cipher_providers(const std::string& algo_spec); + +/** +* Hash function factory method. +* +* @param algo_spec the name of the desired hash function +* @return pointer to the hash function object +*/ +BOTAN_DLL HashFunction* get_hash_function(const std::string& algo_spec, const std::string& provider = ""); + +inline HashFunction* get_hash(const std::string& algo_spec, const std::string& provider = "") + { + return get_hash_function(algo_spec, provider); + } + +BOTAN_DLL std::vector<std::string> get_hash_function_providers(const std::string& algo_spec); + +/** +* MAC factory method. +* +* @param algo_spec the name of the desired MAC +* @return pointer to the MAC object +*/ +BOTAN_DLL MessageAuthenticationCode* get_mac(const std::string& algo_spec, const std::string& provider = ""); + +BOTAN_DLL std::vector<std::string> get_mac_providers(const std::string& algo_spec); + +/** +* Password based key derivation function factory method +* @param algo_spec the name of the desired PBKDF algorithm +* @return pointer to newly allocated object of that type +*/ +BOTAN_DLL PBKDF* get_pbkdf(const std::string& algo_spec, const std::string& provider = ""); + +} + +#endif diff --git a/src/lib/base/scan_name.cpp b/src/lib/base/scan_name.cpp new file mode 100644 index 000000000..4b0c95004 --- /dev/null +++ b/src/lib/base/scan_name.cpp @@ -0,0 +1,221 @@ +/* +* SCAN Name Abstraction +* (C) 2008-2009,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/scan_name.h> +#include <botan/parsing.h> +#include <botan/exceptn.h> +#include <stdexcept> + +namespace Botan { + +namespace { + +std::string make_arg( + const std::vector<std::pair<size_t, std::string> >& name, size_t start) + { + std::string output = name[start].second; + size_t level = name[start].first; + + size_t paren_depth = 0; + + for(size_t i = start + 1; i != name.size(); ++i) + { + if(name[i].first <= name[start].first) + break; + + if(name[i].first > level) + { + output += '(' + name[i].second; + ++paren_depth; + } + else if(name[i].first < level) + { + output += ")," + name[i].second; + --paren_depth; + } + else + { + if(output[output.size() - 1] != '(') + output += ","; + output += name[i].second; + } + + level = name[i].first; + } + + for(size_t i = 0; i != paren_depth; ++i) + output += ')'; + + return output; + } + +std::pair<size_t, std::string> +deref_aliases(const std::pair<size_t, std::string>& in) + { + return std::make_pair(in.first, + SCAN_Name::deref_alias(in.second)); + } + +} + +SCAN_Name::SCAN_Name(std::string algo_spec, const std::string& extra) : SCAN_Name(algo_spec) + { + alg_name += extra; + } + +SCAN_Name::SCAN_Name(const char* algo_spec) : SCAN_Name(std::string(algo_spec)) + { + } + +SCAN_Name::SCAN_Name(std::string algo_spec) + { + orig_algo_spec = algo_spec; + + std::vector<std::pair<size_t, std::string> > name; + size_t level = 0; + std::pair<size_t, std::string> accum = std::make_pair(level, ""); + + const std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; + + algo_spec = SCAN_Name::deref_alias(algo_spec); + + for(size_t i = 0; i != algo_spec.size(); ++i) + { + char c = algo_spec[i]; + + if(c == '/' || c == ',' || c == '(' || c == ')') + { + if(c == '(') + ++level; + else if(c == ')') + { + if(level == 0) + throw Decoding_Error(decoding_error + "Mismatched parens"); + --level; + } + + if(c == '/' && level > 0) + accum.second.push_back(c); + else + { + if(accum.second != "") + name.push_back(deref_aliases(accum)); + accum = std::make_pair(level, ""); + } + } + else + accum.second.push_back(c); + } + + if(accum.second != "") + name.push_back(deref_aliases(accum)); + + if(level != 0) + throw Decoding_Error(decoding_error + "Missing close paren"); + + if(name.size() == 0) + throw Decoding_Error(decoding_error + "Empty name"); + + alg_name = name[0].second; + + bool in_modes = false; + + for(size_t i = 1; i != name.size(); ++i) + { + if(name[i].first == 0) + { + mode_info.push_back(make_arg(name, i)); + in_modes = true; + } + else if(name[i].first == 1 && !in_modes) + args.push_back(make_arg(name, i)); + } + } + +std::string SCAN_Name::all_arguments() const + { + std::string out; + if(arg_count()) + { + out += '('; + for(size_t i = 0; i != arg_count(); ++i) + { + out += arg(i); + if(i != arg_count() - 1) + out += ','; + } + out += ')'; + } + return out; + } + +std::string SCAN_Name::arg(size_t i) const + { + if(i >= arg_count()) + throw std::range_error("SCAN_Name::arg " + std::to_string(i) + + " out of range for '" + as_string() + "'"); + return args[i]; + } + +std::string SCAN_Name::arg(size_t i, const std::string& def_value) const + { + if(i >= arg_count()) + return def_value; + return args[i]; + } + +size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const + { + if(i >= arg_count()) + return def_value; + return to_u32bit(args[i]); + } + +std::mutex SCAN_Name::g_alias_map_mutex; +std::map<std::string, std::string> SCAN_Name::g_alias_map = { + { "3DES", "TripleDES" }, + { "ARC4", "RC4" }, + { "CAST5", "CAST-128" }, + { "DES-EDE", "TripleDES" }, + { "EME-OAEP", "OAEP" }, + { "EME-PKCS1-v1_5", "PKCS1v15" }, + { "EME1", "OAEP" }, + { "EMSA-PKCS1-v1_5", "EMSA_PKCS1" }, + { "EMSA-PSS", "PSSR" }, + { "EMSA2", "EMSA_X931" }, + { "EMSA3", "EMSA_PKCS1" }, + { "EMSA4", "PSSR" }, + { "GOST-34.11", "GOST-R-34.11-94" }, + { "MARK-4", "RC4(256)" }, + { "OMAC", "CMAC" }, + { "PSS-MGF1", "PSSR" }, + { "SHA-1", "SHA-160" }, + { "SHA1", "SHA-160" }, + { "X9.31", "EMSA2" } +}; + +void SCAN_Name::add_alias(const std::string& alias, const std::string& basename) + { + std::lock_guard<std::mutex> lock(g_alias_map_mutex); + + if(g_alias_map.find(alias) == g_alias_map.end()) + g_alias_map[alias] = basename; + } + +std::string SCAN_Name::deref_alias(const std::string& alias) + { + std::lock_guard<std::mutex> lock(g_alias_map_mutex); + + std::string name = alias; + + for(auto i = g_alias_map.find(name); i != g_alias_map.end(); i = g_alias_map.find(name)) + name = i->second; + + return name; + } + +} diff --git a/src/lib/base/scan_name.h b/src/lib/base/scan_name.h new file mode 100644 index 000000000..cc89bf998 --- /dev/null +++ b/src/lib/base/scan_name.h @@ -0,0 +1,121 @@ +/* +* SCAN Name Abstraction +* (C) 2008,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SCAN_NAME_H__ +#define BOTAN_SCAN_NAME_H__ + +#include <botan/types.h> +#include <string> +#include <vector> +#include <mutex> +#include <map> + +namespace Botan { + +/** +A class encapsulating a SCAN name (similar to JCE conventions) +http://www.users.zetnet.co.uk/hopwood/crypto/scan/ +*/ +class BOTAN_DLL SCAN_Name + { + public: + /** + * @param algo_spec A SCAN-format name + */ + SCAN_Name(const char* algo_spec); + + /** + * @param algo_spec A SCAN-format name + */ + SCAN_Name(std::string algo_spec); + + /** + * @param algo_spec A SCAN-format name + */ + SCAN_Name(std::string algo_spec, const std::string& extra); + + /** + * @return original input string + */ + const std::string& as_string() const { return orig_algo_spec; } + + /** + * @return algorithm name + */ + const std::string& algo_name() const { return alg_name; } + + /** + * @return algorithm name plus any arguments + */ + std::string algo_name_and_args() const { return algo_name() + all_arguments(); } + + /** + * @return all arguments + */ + std::string all_arguments() const; + + /** + * @return number of arguments + */ + size_t arg_count() const { return args.size(); } + + /** + * @param lower is the lower bound + * @param upper is the upper bound + * @return if the number of arguments is between lower and upper + */ + bool arg_count_between(size_t lower, size_t upper) const + { return ((arg_count() >= lower) && (arg_count() <= upper)); } + + /** + * @param i which argument + * @return ith argument + */ + std::string arg(size_t i) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument or the default value + */ + std::string arg(size_t i, const std::string& def_value) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument as an integer, or the default value + */ + size_t arg_as_integer(size_t i, size_t def_value) const; + + /** + * @return cipher mode (if any) + */ + std::string cipher_mode() const + { return (mode_info.size() >= 1) ? mode_info[0] : ""; } + + /** + * @return cipher mode padding (if any) + */ + std::string cipher_mode_pad() const + { return (mode_info.size() >= 2) ? mode_info[1] : ""; } + + static void add_alias(const std::string& alias, const std::string& basename); + + static std::string deref_alias(const std::string& alias); + private: + static std::mutex g_alias_map_mutex; + static std::map<std::string, std::string> g_alias_map; + + std::string orig_algo_spec; + std::string alg_name; + std::vector<std::string> args; + std::vector<std::string> mode_info; + }; + +} + +#endif diff --git a/src/lib/base/sym_algo.h b/src/lib/base/sym_algo.h new file mode 100644 index 000000000..7c37b2a47 --- /dev/null +++ b/src/lib/base/sym_algo.h @@ -0,0 +1,99 @@ +/* +* Symmetric Algorithm Base Class +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYMMETRIC_ALGORITHM_H__ +#define BOTAN_SYMMETRIC_ALGORITHM_H__ + +#include <botan/key_spec.h> +#include <botan/exceptn.h> +#include <botan/symkey.h> +#include <botan/types.h> + +namespace Botan { + +/** +* This class represents a symmetric algorithm object. +*/ +class BOTAN_DLL SymmetricAlgorithm + { + public: + virtual ~SymmetricAlgorithm() {} + + virtual void clear() = 0; + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * @return minimum allowed key length + */ + size_t maximum_keylength() const + { + return key_spec().maximum_keylength(); + } + + /** + * @return maxmium allowed key length + */ + size_t minimum_keylength() const + { + return key_spec().minimum_keylength(); + } + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this object. + * @param key the SymmetricKey to be set. + */ + void set_key(const SymmetricKey& key) + { + set_key(key.begin(), key.length()); + } + + template<typename Alloc> + void set_key(const std::vector<byte, Alloc>& key) + { + set_key(&key[0], key.size()); + } + + /** + * Set the symmetric key of this object. + * @param key the to be set as a byte array. + * @param length in bytes of key param + */ + void set_key(const byte key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + + virtual std::string name() const = 0; + + private: + /** + * Run the key schedule + * @param key the key + * @param length of key + */ + virtual void key_schedule(const byte key[], size_t length) = 0; + }; + +} + +#endif diff --git a/src/lib/base/symkey.cpp b/src/lib/base/symkey.cpp new file mode 100644 index 000000000..0cb0d9e35 --- /dev/null +++ b/src/lib/base/symkey.cpp @@ -0,0 +1,132 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/symkey.h> +#include <botan/internal/xor_buf.h> +#include <botan/rng.h> +#include <botan/hex.h> +#include <algorithm> + +namespace Botan { + +/* +* Create an OctetString from RNG output +*/ +OctetString::OctetString(RandomNumberGenerator& rng, + size_t length) + { + bits = rng.random_vec(length); + } + +/* +* Create an OctetString from a hex string +*/ +OctetString::OctetString(const std::string& hex_string) + { + bits.resize(1 + hex_string.length() / 2); + bits.resize(hex_decode(&bits[0], hex_string)); + } + +/* +* Create an OctetString from a byte string +*/ +OctetString::OctetString(const byte in[], size_t n) + { + bits.assign(in, in + n); + } + +/* +* Set the parity of each key byte to odd +*/ +void OctetString::set_odd_parity() + { + const byte ODD_PARITY[256] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, + 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, + 0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52, + 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, + 0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83, + 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, + 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, + 0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, + 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3, + 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, + 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, + 0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, + 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3, + 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, + 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, + 0xFD, 0xFD, 0xFE, 0xFE }; + + for(size_t j = 0; j != bits.size(); ++j) + bits[j] = ODD_PARITY[bits[j]]; + } + +/* +* Hex encode an OctetString +*/ +std::string OctetString::as_string() const + { + return hex_encode(&bits[0], bits.size()); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString& OctetString::operator^=(const OctetString& k) + { + if(&k == this) { zeroise(bits); return (*this); } + xor_buf(&bits[0], k.begin(), std::min(length(), k.length())); + return (*this); + } + +/* +* Equality Operation for OctetStrings +*/ +bool operator==(const OctetString& s1, const OctetString& s2) + { + return (s1.bits_of() == s2.bits_of()); + } + +/* +* Unequality Operation for OctetStrings +*/ +bool operator!=(const OctetString& s1, const OctetString& s2) + { + return !(s1 == s2); + } + +/* +* Append Operation for OctetStrings +*/ +OctetString operator+(const OctetString& k1, const OctetString& k2) + { + secure_vector<byte> out; + out += k1.bits_of(); + out += k2.bits_of(); + return OctetString(out); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString operator^(const OctetString& k1, const OctetString& k2) + { + secure_vector<byte> ret(std::max(k1.length(), k2.length())); + + copy_mem(&ret[0], k1.begin(), k1.length()); + xor_buf(&ret[0], k2.begin(), k2.length()); + return OctetString(ret); + } + +} diff --git a/src/lib/base/symkey.h b/src/lib/base/symkey.h new file mode 100644 index 000000000..f49bf226f --- /dev/null +++ b/src/lib/base/symkey.h @@ -0,0 +1,143 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYMKEY_H__ +#define BOTAN_SYMKEY_H__ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Octet String +*/ +class BOTAN_DLL OctetString + { + public: + /** + * @return size of this octet string in bytes + */ + size_t length() const { return bits.size(); } + + /** + * @return this object as a secure_vector<byte> + */ + secure_vector<byte> bits_of() const { return bits; } + + /** + * @return start of this string + */ + const byte* begin() const { return &bits[0]; } + + /** + * @return end of this string + */ + const byte* end() const { return begin() + bits.size(); } + + /** + * @return this encoded as hex + */ + std::string as_string() const; + + /** + * XOR the contents of another octet string into this one + * @param other octet string + * @return reference to this + */ + OctetString& operator^=(const OctetString& other); + + /** + * Force to have odd parity + */ + void set_odd_parity(); + + /** + * Create a new OctetString + * @param str is a hex encoded string + */ + OctetString(const std::string& str = ""); + + /** + * Create a new random OctetString + * @param rng is a random number generator + * @param len is the desired length in bytes + */ + OctetString(class RandomNumberGenerator& rng, size_t len); + + /** + * Create a new OctetString + * @param in is an array + * @param len is the length of in in bytes + */ + OctetString(const byte in[], size_t len); + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const secure_vector<byte>& in) : bits(in) {} + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const std::vector<byte>& in) : bits(in.begin(), in.end()) {} + private: + secure_vector<byte> bits; + }; + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is equal to y +*/ +BOTAN_DLL bool operator==(const OctetString& x, + const OctetString& y); + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is not equal to y +*/ +BOTAN_DLL bool operator!=(const OctetString& x, + const OctetString& y); + +/** +* Concatenate two strings +* @param x an octet string +* @param y an octet string +* @return x concatenated with y +*/ +BOTAN_DLL OctetString operator+(const OctetString& x, + const OctetString& y); + +/** +* XOR two strings +* @param x an octet string +* @param y an octet string +* @return x XORed with y +*/ +BOTAN_DLL OctetString operator^(const OctetString& x, + const OctetString& y); + + +/** +* Alternate name for octet string showing intent to use as a key +*/ +typedef OctetString SymmetricKey; + +/** +* Alternate name for octet string showing intent to use as an IV +*/ +typedef OctetString InitializationVector; + +} + +#endif diff --git a/src/lib/base/transform.h b/src/lib/base/transform.h new file mode 100644 index 000000000..75bd5004a --- /dev/null +++ b/src/lib/base/transform.h @@ -0,0 +1,182 @@ +/* +* Transforms of data +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TRANSFORM_H__ +#define BOTAN_TRANSFORM_H__ + +#include <botan/secmem.h> +#include <botan/key_spec.h> +#include <botan/exceptn.h> +#include <botan/symkey.h> +#include <botan/scan_name.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +* Interface for general transformations on data +*/ +class BOTAN_DLL Transform + { + public: + typedef SCAN_Name Spec; + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + secure_vector<byte> start(const std::vector<byte, Alloc>& nonce) + { + return start(&nonce[0], nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + BOTAN_DEPRECATED("Use Transform::start") + secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce) + { + return start(&nonce[0], nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + secure_vector<byte> start(const byte nonce[], size_t nonce_len) + { + return start_raw(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + secure_vector<byte> start() + { + return start_raw(nullptr, 0); + } + + virtual secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) = 0; + + /** + * Process some data. Input must be in size update_granularity() byte blocks. + * @param blocks in/out paramter which will possibly be resized + * @param offset an offset into blocks to begin processing + */ + virtual void update(secure_vector<byte>& blocks, size_t offset = 0) = 0; + + /** + * Complete processing of a message. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector<byte>& final_block, size_t offset = 0) = 0; + + /** + * Returns the size of the output if this transform is used to process a + * message with input_length bytes. Will throw if unable to give a precise + * answer. + */ + virtual size_t output_length(size_t input_length) const = 0; + + /** + * @return size of required blocks to update + */ + virtual size_t update_granularity() const = 0; + + /** + * @return required minimium size to finalize() - may be any + * length larger than this. + */ + virtual size_t minimum_final_size() const = 0; + + /** + * Return the default size for a nonce + */ + virtual size_t default_nonce_length() const = 0; + + /** + * Return true iff nonce_len is a valid length for the nonce + */ + virtual bool valid_nonce_length(size_t nonce_len) const = 0; + + /** + * Return some short name describing the provider of this tranformation. + * Useful in cases where multiple implementations are available (eg, + * different implementations of AES). Default "core" is used for the + * 'standard' implementation included in the library. + */ + virtual std::string provider() const { return "core"; } + + virtual std::string name() const = 0; + + virtual void clear() = 0; + + virtual ~Transform() {} + }; + +class BOTAN_DLL Keyed_Transform : public Transform + { + public: + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + template<typename Alloc> + void set_key(const std::vector<byte, Alloc>& key) + { + set_key(&key[0], key.size()); + } + + void set_key(const SymmetricKey& key) + { + set_key(key.begin(), key.length()); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + * @param length in bytes of key param + */ + void set_key(const byte key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + + private: + virtual void key_schedule(const byte key[], size_t length) = 0; + }; + +typedef Transform Transformation; + +BOTAN_DLL Transform* get_transform(const std::string& specstr, + const std::string& provider = "", + const std::string& dirstr = ""); + +} + +#endif |