Skip to content

Instantly share code, notes, and snippets.

@cky
Created September 3, 2012 17:22
Show Gist options
  • Save cky/3611062 to your computer and use it in GitHub Desktop.
Save cky/3611062 to your computer and use it in GitHub Desktop.
Simple program for testing out MACs
#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