Created
September 3, 2012 17:22
-
-
Save cky/3611062 to your computer and use it in GitHub Desktop.
Simple program for testing out MACs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 | |
#include <functional> | |
#include <iostream> | |
#include <map> | |
#include <memory> | |
#include <boost/format.hpp> | |
#include <boost/iostreams/categories.hpp> | |
#include <boost/iostreams/copy.hpp> | |
#include <boost/iostreams/device/back_inserter.hpp> | |
#include <boost/iostreams/device/file.hpp> | |
#include <boost/optional.hpp> | |
#include <boost/program_options.hpp> | |
#include <crypto++/cryptlib.h> | |
#include <crypto++/aes.h> | |
#include <crypto++/cmac.h> | |
#include <crypto++/dmac.h> | |
#include <crypto++/gcm.h> | |
#include <crypto++/hmac.h> | |
#include <crypto++/md2.h> | |
#include <crypto++/md4.h> | |
#include <crypto++/md5.h> | |
#include <crypto++/ripemd.h> | |
#include <crypto++/sha.h> | |
#include <crypto++/tiger.h> | |
#include <crypto++/ttmac.h> | |
#include <crypto++/vmac.h> | |
#include <crypto++/whrlpool.h> | |
namespace { | |
namespace ios = boost::iostreams; | |
namespace po = boost::program_options; | |
namespace cpp = CryptoPP; | |
typedef cpp::MessageAuthenticationCode Mac; | |
typedef std::function<std::unique_ptr<Mac> ()> MacFactoryFunc; | |
typedef std::map<std::string, MacFactoryFunc> MacFactoryMap; | |
template <class T> | |
MacFactoryMap::value_type create_map_value() { | |
return {T::StaticAlgorithmName(), []{return std::unique_ptr<Mac>(new T);}}; | |
} | |
MacFactoryMap const factory_map = { | |
create_map_value<cpp::HMAC<cpp::Weak::MD2>>(), | |
create_map_value<cpp::HMAC<cpp::Weak::MD4>>(), | |
create_map_value<cpp::HMAC<cpp::Weak::MD5>>(), | |
create_map_value<cpp::HMAC<cpp::SHA1>>(), | |
create_map_value<cpp::HMAC<cpp::SHA224>>(), | |
create_map_value<cpp::HMAC<cpp::SHA256>>(), | |
create_map_value<cpp::HMAC<cpp::SHA384>>(), | |
create_map_value<cpp::HMAC<cpp::SHA512>>(), | |
create_map_value<cpp::HMAC<cpp::RIPEMD128>>(), | |
create_map_value<cpp::HMAC<cpp::RIPEMD160>>(), | |
create_map_value<cpp::HMAC<cpp::RIPEMD256>>(), | |
create_map_value<cpp::HMAC<cpp::RIPEMD320>>(), | |
create_map_value<cpp::HMAC<cpp::Tiger>>(), | |
create_map_value<cpp::HMAC<cpp::Whirlpool>>(), | |
create_map_value<cpp::CMAC<cpp::AES>>(), | |
create_map_value<cpp::DMAC<cpp::AES>>(), | |
create_map_value<cpp::GCM<cpp::AES>::Encryption>(), | |
create_map_value<cpp::VMAC<cpp::AES>>(), | |
create_map_value<cpp::TTMAC>(), | |
}; | |
/* | |
* Simple wrapper around the lambdas above just to enable Koenig | |
* lookup! (As used by program_options::value_semantic to call | |
* validate.) | |
*/ | |
class MacFactory { | |
MacFactoryFunc func_; | |
public: | |
MacFactory() = default; | |
MacFactory(MacFactoryFunc func) : func_(func) {} | |
std::unique_ptr<Mac> operator()() {return func_();} | |
explicit operator bool() {return static_cast<bool>(func_);} | |
}; | |
class MacSink { | |
Mac& mac_; | |
public: | |
typedef char char_type; | |
typedef ios::sink_tag category; | |
MacSink(Mac& mac) : mac_(mac) {} | |
std::streamsize write(char_type const* s, std::streamsize n) { | |
mac_.Update(reinterpret_cast<byte const*>(s), n); | |
return n; | |
} | |
}; | |
void validate(boost::any& v, std::vector<std::string> const& xs, | |
MacFactory*, int) { | |
auto name(po::validators::get_single_string(xs)); | |
auto iter(factory_map.find(name)); | |
if (iter == factory_map.end()) | |
throw po::invalid_option_value(name); | |
v = boost::any(MacFactory(iter->second)); | |
} | |
void set_key(Mac& mac, char* key, size_t keylen, | |
boost::optional<std::vector<char>> const& iv) { | |
auto keybytes(reinterpret_cast<byte const*>(key)); | |
if (iv) { | |
auto ivbytes(reinterpret_cast<byte const*>(&(*iv)[0])); | |
mac.SetKeyWithIV(keybytes, keylen, ivbytes, iv->size()); | |
} else { | |
mac.SetKey(keybytes, keylen); | |
} | |
std::fill(key, key + keylen, 0); | |
} | |
void set_iv(Mac& mac, boost::optional<std::vector<char>> const& iv) { | |
if (iv) { | |
auto ivbytes(reinterpret_cast<byte const*>(&(*iv)[0])); | |
mac.Resynchronize(ivbytes, iv->size()); | |
} | |
} | |
void print_hash(Mac& mac, boost::optional<std::string> const& name) { | |
std::vector<byte> hash(mac.DigestSize()); | |
mac.Final(&hash[0]); | |
if (name) { | |
std::cout << boost::format("%s(%s) = ") | |
% mac.AlgorithmName() % *name; | |
} | |
for (auto b : hash) | |
std::cout << boost::format("%02x") % (b & 0xff); | |
std::cout << '\n'; | |
} | |
} | |
int main(int argc, char** argv) { | |
MacFactory factory; | |
std::string ivfile; | |
std::string keyfile; | |
std::vector<std::string> files; | |
po::options_description options; | |
options.add_options() | |
("algorithm,a", po::value(&factory)) | |
("ivfile,iv", po::value(&ivfile)) | |
("keyfile,k", po::value(&keyfile)) | |
("files", po::value(&files)); | |
po::positional_options_description pos; | |
pos.add("files", -1); | |
po::variables_map vm; | |
po::store(po::command_line_parser(argc, argv).options(options) | |
.positional(pos).run(), vm); | |
po::notify(vm); | |
if (!factory) { | |
std::cerr << "An --algorithm must be specified. Valid algorithms are:\n"; | |
for (auto entry : factory_map) | |
std::cerr << '\t' << entry.first << '\n'; | |
return 1; | |
} | |
std::unique_ptr<Mac> mac(factory()); | |
boost::optional<std::vector<char>> iv; | |
if (!ivfile.empty()) { | |
iv = std::vector<char>(); | |
ios::copy(ios::file_source(ivfile), ios::back_inserter(*iv)); | |
} | |
if (keyfile.empty()) { | |
auto pass(getpass("Key: ")); | |
set_key(*mac, pass, strlen(pass), iv); | |
} else { | |
std::vector<char> key; | |
ios::copy(ios::file_source(keyfile), ios::back_inserter(key)); | |
set_key(*mac, &key[0], key.size(), iv); | |
} | |
if (files.empty()) { | |
ios::copy(std::cin, MacSink(*mac)); | |
print_hash(*mac, boost::none); | |
} else { | |
for (auto file : files) { | |
set_iv(*mac, iv); | |
ios::copy(ios::file_source(file), MacSink(*mac)); | |
print_hash(*mac, file); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment