#ifndef _H_HASHING
#define _H_HASHING
#include <CommonCrypto/CommonDigest.h>
#include <cstring>
#include <memory>
#include <sys/types.h>
#include <CommonCrypto/CommonDigestSPI.h> // SPI slated to become API
namespace Security {
class Hashing {
public:
typedef unsigned char Byte;
};
template <uint32_t _size, class _HashType>
class Hash : public Hashing {
_HashType &_self() { return static_cast<_HashType &>(*this); } public:
static const size_t digestLength = _size; typedef Byte Digest[_size]; struct SDigest { Digest data;
SDigest() { }
SDigest(const Byte *source) { ::memcpy(data, source, digestLength); }
friend bool operator < (const SDigest &x, const SDigest &y) { return ::memcmp(x.data, y.data, digestLength) < 0; }
bool operator == (const SDigest &other) const
{ return ::memcmp(this->data, other.data, digestLength) == 0; }
bool operator != (const SDigest &other) const
{ return ::memcmp(this->data, other.data, digestLength) != 0; }
bool operator == (const Byte *other) const
{ return ::memcmp(this->data, other, digestLength) == 0; }
bool operator != (const Byte *other) const
{ return ::memcmp(this->data, other, digestLength) != 0; }
};
void operator () (const void *data, size_t length) { _self().update(data, length); }
void finish(SDigest &digest)
{ _self().finish(digest.data); }
bool verify(const Byte *digest)
{ Digest d; _self().finish(d); return memcmp(d, digest, digestLength) == 0; }
};
class DynamicHash : public Hashing {
public:
virtual ~DynamicHash();
virtual size_t digestLength() const = 0;
virtual void update(const void *data, size_t length) = 0;
virtual void finish(Byte *digest) = 0;
void operator () (const void *data, size_t length)
{ return this->update(data, length); }
bool verify(const Byte *digest)
{ Byte d[this->digestLength()]; this->finish(d); return memcmp(d, digest, this->digestLength()) == 0; }
};
template <class _HashType>
class DynamicHashInstance : public DynamicHash, public _HashType {
public:
DynamicHashInstance() { }
template <class Arg1>
DynamicHashInstance(const Arg1 &arg1) : _HashType(arg1) { }
template <class Arg1, class Arg2>
DynamicHashInstance(const Arg1 &arg1, const Arg2 &arg2) : _HashType(arg1, arg2) { }
template <class Arg1, class Arg2, class Arg3>
DynamicHashInstance(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : _HashType(arg1, arg2, arg3) { }
size_t digestLength() const
{ return _HashType::digestLength; }
void update(const void *data, size_t length)
{ return _HashType::update(data, length); }
void finish(unsigned char *digest)
{ return _HashType::finish(digest); }
};
class CCHashInstance : public DynamicHash {
public:
CCHashInstance(CCDigestAlg alg);
~CCHashInstance()
{ CCDigestDestroy(mDigest); }
size_t digestLength() const
{ return CCDigestOutputSize(mDigest); }
void update(const void *data, size_t length)
{ CCDigestUpdate(mDigest, data, length); }
void finish(unsigned char *digest)
{ CCDigestFinal(mDigest, digest); }
private:
CCDigestRef mDigest;
};
template <class _Giver, DynamicHash *(_Giver::*_fetcher)() const = &_Giver::getHash>
class MakeHash : public std::auto_ptr<DynamicHash> {
public:
MakeHash(const _Giver *giver) : std::auto_ptr<DynamicHash>((giver->*_fetcher)()) { }
operator DynamicHash *() const { return this->get(); }
};
class SHA1 : public CC_SHA1_CTX, public Hash<CC_SHA1_DIGEST_LENGTH, SHA1> {
public:
SHA1() { CC_SHA1_Init(this); }
void update(const void *data, size_t length)
{ CC_SHA1_Update(this, data, (CC_LONG)length); }
void finish(Byte *digest) { CC_SHA1_Final(digest, this); }
using Hash<CC_SHA1_DIGEST_LENGTH, SHA1>::finish;
};
}
#endif //_H_HASHING