mirror of
https://github.com/anope/anope.git
synced 2026-06-12 17:04:47 +02:00
Misc improvements to the encryption API.
This commit is contained in:
@@ -13,26 +13,89 @@
|
||||
|
||||
namespace Encryption
|
||||
{
|
||||
typedef std::pair<const unsigned char *, size_t> Hash;
|
||||
typedef std::pair<const uint32_t *, size_t> IV;
|
||||
|
||||
/** Base class for encryption contexts. */
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
virtual ~Context() = default;
|
||||
|
||||
/** Updates the encryption context with the specified data.
|
||||
* @param str The data to update the context with.
|
||||
*/
|
||||
inline void Update(const Anope::string &str)
|
||||
{
|
||||
Update(reinterpret_cast<const unsigned char *>(str.c_str()), str.length());
|
||||
}
|
||||
|
||||
/** Updates the encryption context with the specified data.
|
||||
* @param data The data to update the context with.
|
||||
* @param len The length of the data.
|
||||
*/
|
||||
virtual void Update(const unsigned char *data, size_t len) = 0;
|
||||
virtual void Finalize() = 0;
|
||||
virtual Hash GetFinalizedHash() = 0;
|
||||
|
||||
/** Finalises the encryption context and returns the digest. */
|
||||
virtual Anope::string Finalize() = 0;
|
||||
};
|
||||
|
||||
/** Provider of encryption contexts. */
|
||||
class Provider
|
||||
: public Service
|
||||
{
|
||||
public:
|
||||
Provider(Module *creator, const Anope::string &sname) : Service(creator, "Encryption::Provider", sname) { }
|
||||
/** The byte size of the block cipher. */
|
||||
const size_t block_size;
|
||||
|
||||
/** The byte size of the resulting digest. */
|
||||
const size_t digest_size;
|
||||
|
||||
/** Creates a provider of encryption contexts.
|
||||
* @param creator The module that created this provider.
|
||||
* @param algorithm The name of the encryption algorithm.
|
||||
* @param bs The byte size of the block cipher.
|
||||
* @param ds The byte size of the resulting digest.
|
||||
*/
|
||||
Provider(Module *creator, const Anope::string &algorithm, size_t bs, size_t ds)
|
||||
: Service(creator, "Encryption::Provider", algorithm)
|
||||
, block_size(bs)
|
||||
, digest_size(ds)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Provider() = default;
|
||||
|
||||
virtual Context *CreateContext(IV * = NULL) = 0;
|
||||
virtual IV GetDefaultIV() = 0;
|
||||
/** Creates a new encryption context. */
|
||||
virtual std::unique_ptr<Context> CreateContext() = 0;
|
||||
|
||||
template<typename... Args>
|
||||
Anope::string Encrypt(Args &&...args)
|
||||
{
|
||||
auto context = CreateContext();
|
||||
context->Update(std::forward<Args>(args)...);
|
||||
return context->Finalize();
|
||||
}
|
||||
};
|
||||
|
||||
/** Helper template for creating simple providers of encryption contexts. */
|
||||
template <typename T>
|
||||
class SimpleProvider final
|
||||
: public Provider
|
||||
{
|
||||
public:
|
||||
/** Creates a simple provider of encryption contexts.
|
||||
* @param creator The module that created this provider.
|
||||
* @param algorithm The name of the encryption algorithm.
|
||||
* @param bs The byte size of the block cipher.
|
||||
* @param ds The byte size of the resulting digest.
|
||||
*/
|
||||
SimpleProvider(Module *creator, const Anope::string &algorithm, size_t bs, size_t ds)
|
||||
: Provider(creator, algorithm, bs, ds)
|
||||
{
|
||||
}
|
||||
|
||||
/** @copydoc Encryption::Provider::CreateContext. */
|
||||
std::unique_ptr<Context> CreateContext() override
|
||||
{
|
||||
return std::make_unique<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ class MD5Context final
|
||||
unsigned state[4]; /* state (ABCD) */
|
||||
unsigned count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
unsigned char digest[16]; /* final digest */
|
||||
|
||||
/* Constants for MD5Transform routine.
|
||||
*/
|
||||
@@ -229,19 +228,10 @@ class MD5Context final
|
||||
}
|
||||
|
||||
public:
|
||||
MD5Context(Encryption::IV *iv = NULL)
|
||||
MD5Context()
|
||||
{
|
||||
if (iv != NULL)
|
||||
{
|
||||
if (iv->second != 4)
|
||||
throw CoreException("Invalid IV size");
|
||||
/* Load magic initialization constants. */
|
||||
for (int i = 0; i < 4; ++i)
|
||||
this->state[i] = iv->first[i];
|
||||
}
|
||||
else
|
||||
for (int i = 0; i < 4; ++i)
|
||||
this->state[i] = md5_iv[i];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
this->state[i] = md5_iv[i];
|
||||
|
||||
this->count[0] = this->count[1] = 0;
|
||||
memset(this->buffer, 0, sizeof(this->buffer));
|
||||
@@ -286,7 +276,7 @@ public:
|
||||
/* MD5 finalization. Ends an MD5 message-digest opera
|
||||
* the message digest and zeroizing the context.
|
||||
*/
|
||||
void Finalize() override
|
||||
Anope::string Finalize() override
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned index, padLen;
|
||||
@@ -301,6 +291,7 @@ public:
|
||||
|
||||
/* Append length (before padding) */
|
||||
this->Update(bits, 8);
|
||||
unsigned char digest[16]; /* final digest */
|
||||
/* Store state in digest */
|
||||
this->Encode(digest, this->state, 16);
|
||||
|
||||
@@ -308,45 +299,21 @@ public:
|
||||
memset(this->state, 0, sizeof(this->state));
|
||||
memset(this->count, 0, sizeof(this->count));
|
||||
memset(this->buffer, 0, sizeof(this->buffer));
|
||||
}
|
||||
|
||||
Encryption::Hash GetFinalizedHash() override
|
||||
{
|
||||
Encryption::Hash hash;
|
||||
hash.first = this->digest;
|
||||
hash.second = sizeof(this->digest);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class MD5Provider final
|
||||
: public Encryption::Provider
|
||||
{
|
||||
public:
|
||||
MD5Provider(Module *creator) : Encryption::Provider(creator, "md5") { }
|
||||
|
||||
Encryption::Context *CreateContext(Encryption::IV *iv) override
|
||||
{
|
||||
return new MD5Context(iv);
|
||||
}
|
||||
|
||||
Encryption::IV GetDefaultIV() override
|
||||
{
|
||||
Encryption::IV iv;
|
||||
iv.first = md5_iv;
|
||||
iv.second = sizeof(md5_iv) / sizeof(uint32_t);
|
||||
return iv;
|
||||
return Anope::string(reinterpret_cast<const char *>(&digest), sizeof(digest));
|
||||
}
|
||||
};
|
||||
|
||||
class EMD5 final
|
||||
: public Module
|
||||
{
|
||||
MD5Provider md5provider;
|
||||
private:
|
||||
Encryption::SimpleProvider<MD5Context> md5provider;
|
||||
|
||||
public:
|
||||
EMD5(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION | VENDOR),
|
||||
md5provider(this)
|
||||
EMD5(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
, md5provider(this, "md5", 16, 64)
|
||||
{
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
throw ModuleException("enc_md5 is deprecated and can not be used as a primary encryption method");
|
||||
@@ -354,14 +321,7 @@ public:
|
||||
|
||||
EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) override
|
||||
{
|
||||
MD5Context context;
|
||||
|
||||
context.Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
context.Finalize();
|
||||
|
||||
Encryption::Hash hash = context.GetFinalizedHash();
|
||||
|
||||
Anope::string buf = "md5:" + Anope::Hex(reinterpret_cast<const char *>(hash.first), hash.second);
|
||||
Anope::string buf = "md5:" + Anope::Hex(md5provider.Encrypt(src));
|
||||
|
||||
Log(LOG_DEBUG_2) << "(enc_md5) hashed password from [" << src << "] to [" << buf << "]";
|
||||
dest = buf;
|
||||
|
||||
@@ -18,20 +18,16 @@ class OldMD5Provider final
|
||||
: public Encryption::Provider
|
||||
{
|
||||
public:
|
||||
OldMD5Provider(Module *creator) : Encryption::Provider(creator, "oldmd5") { }
|
||||
|
||||
Encryption::Context *CreateContext(Encryption::IV *iv) override
|
||||
OldMD5Provider(Module *creator)
|
||||
: Encryption::Provider(creator, "oldmd5", 16, 64)
|
||||
{
|
||||
if (md5)
|
||||
return md5->CreateContext(iv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Encryption::IV GetDefaultIV() override
|
||||
std::unique_ptr<Encryption::Context> CreateContext() override
|
||||
{
|
||||
if (md5)
|
||||
return md5->GetDefaultIV();
|
||||
return Encryption::IV(static_cast<const uint32_t *>(NULL), 0);
|
||||
return md5->CreateContext();
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,17 +56,12 @@ public:
|
||||
if (!md5)
|
||||
return EVENT_CONTINUE;
|
||||
|
||||
Encryption::Context *context = md5->CreateContext();
|
||||
context->Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
context->Finalize();
|
||||
|
||||
Encryption::Hash hash = context->GetFinalizedHash();
|
||||
|
||||
char digest[32], digest2[16];
|
||||
memset(digest, 0, sizeof(digest));
|
||||
if (hash.second > sizeof(digest))
|
||||
auto hash = md5->Encrypt(src);
|
||||
if (hash.length() > sizeof(digest))
|
||||
throw CoreException("Hash too large");
|
||||
memcpy(digest, hash.first, hash.second);
|
||||
memcpy(digest, hash.data(), hash.length());
|
||||
|
||||
for (int i = 0; i < 32; i += 2)
|
||||
digest2[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]);
|
||||
@@ -79,7 +70,6 @@ public:
|
||||
|
||||
Log(LOG_DEBUG_2) << "(enc_old) hashed password from [" << src << "] to [" << buf << "]";
|
||||
dest = buf;
|
||||
delete context;
|
||||
return EVENT_ALLOW;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ class SHA1Context final
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
unsigned char buffer[64];
|
||||
unsigned char digest[20];
|
||||
|
||||
void Transform(const unsigned char buf[64])
|
||||
{
|
||||
@@ -108,22 +107,13 @@ class SHA1Context final
|
||||
}
|
||||
|
||||
public:
|
||||
SHA1Context(Encryption::IV *iv = NULL)
|
||||
SHA1Context()
|
||||
{
|
||||
if (iv != NULL)
|
||||
{
|
||||
if (iv->second != 5)
|
||||
throw CoreException("Invalid IV size");
|
||||
for (int i = 0; i < 5; ++i)
|
||||
this->state[i] = iv->first[i];
|
||||
}
|
||||
else
|
||||
for (int i = 0; i < 5; ++i)
|
||||
this->state[i] = sha1_iv[i];
|
||||
for (int i = 0; i < 5; ++i)
|
||||
this->state[i] = sha1_iv[i];
|
||||
|
||||
this->count[0] = this->count[1] = 0;
|
||||
memset(this->buffer, 0, sizeof(this->buffer));
|
||||
memset(this->digest, 0, sizeof(this->digest));
|
||||
}
|
||||
|
||||
void Update(const unsigned char *data, size_t len) override
|
||||
@@ -147,7 +137,7 @@ public:
|
||||
memcpy(&this->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
void Finalize() override
|
||||
Anope::string Finalize() override
|
||||
{
|
||||
uint32_t i;
|
||||
unsigned char finalcount[8];
|
||||
@@ -158,8 +148,10 @@ public:
|
||||
while ((this->count[0] & 504) != 448)
|
||||
this->Update(reinterpret_cast<const unsigned char *>("\0"), 1);
|
||||
this->Update(finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
unsigned char digest[20];
|
||||
memset(digest, 0, sizeof(digest));
|
||||
for (i = 0; i < 20; ++i)
|
||||
this->digest[i] = static_cast<unsigned char>((this->state[i>>2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
digest[i] = static_cast<unsigned char>((this->state[i>>2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
|
||||
/* Wipe variables */
|
||||
memset(this->buffer, 0, sizeof(this->buffer));
|
||||
@@ -168,45 +160,21 @@ public:
|
||||
memset(&finalcount, 0, sizeof(finalcount));
|
||||
|
||||
this->Transform(this->buffer);
|
||||
}
|
||||
|
||||
Encryption::Hash GetFinalizedHash() override
|
||||
{
|
||||
Encryption::Hash hash;
|
||||
hash.first = this->digest;
|
||||
hash.second = sizeof(this->digest);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class SHA1Provider final
|
||||
: public Encryption::Provider
|
||||
{
|
||||
public:
|
||||
SHA1Provider(Module *creator) : Encryption::Provider(creator, "sha1") { }
|
||||
|
||||
Encryption::Context *CreateContext(Encryption::IV *iv) override
|
||||
{
|
||||
return new SHA1Context(iv);
|
||||
}
|
||||
|
||||
Encryption::IV GetDefaultIV() override
|
||||
{
|
||||
Encryption::IV iv;
|
||||
iv.first = sha1_iv;
|
||||
iv.second = sizeof(sha1_iv) / sizeof(uint32_t);
|
||||
return iv;
|
||||
return Anope::string(reinterpret_cast<const char *>(&digest), sizeof(digest));
|
||||
}
|
||||
};
|
||||
|
||||
class ESHA1 final
|
||||
: public Module
|
||||
{
|
||||
SHA1Provider sha1provider;
|
||||
private:
|
||||
Encryption::SimpleProvider<SHA1Context> sha1provider;
|
||||
|
||||
public:
|
||||
ESHA1(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION | VENDOR),
|
||||
sha1provider(this)
|
||||
ESHA1(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
, sha1provider(this, "sha1", 20, 64)
|
||||
{
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
throw ModuleException("enc_sha1 is deprecated and can not be used as a primary encryption method");
|
||||
@@ -214,14 +182,7 @@ public:
|
||||
|
||||
EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) override
|
||||
{
|
||||
SHA1Context context;
|
||||
|
||||
context.Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
context.Finalize();
|
||||
|
||||
Encryption::Hash hash = context.GetFinalizedHash();
|
||||
|
||||
Anope::string buf = "sha1:" + Anope::Hex(reinterpret_cast<const char *>(hash.first), hash.second);
|
||||
Anope::string buf = "sha1:" + Anope::Hex(sha1provider.Encrypt(src));
|
||||
|
||||
Log(LOG_DEBUG_2) << "(enc_sha1) hashed password from [" << src << "] to [" << buf << "]";
|
||||
dest = buf;
|
||||
|
||||
@@ -151,26 +151,22 @@ class SHA256Context final
|
||||
unsigned len;
|
||||
unsigned char block[2 * SHA256_BLOCK_SIZE];
|
||||
uint32_t h[8];
|
||||
unsigned char digest[SHA256_DIGEST_SIZE];
|
||||
|
||||
public:
|
||||
SHA256Context(Encryption::IV *iv)
|
||||
SHA256Context()
|
||||
{
|
||||
if (iv != NULL)
|
||||
{
|
||||
if (iv->second != 8)
|
||||
throw CoreException("Invalid IV size");
|
||||
for (int i = 0; i < 8; ++i)
|
||||
this->h[i] = iv->first[i];
|
||||
}
|
||||
else
|
||||
for (int i = 0; i < 8; ++i)
|
||||
this->h[i] = sha256_h0[i];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
this->h[i] = sha256_h0[i];
|
||||
|
||||
this->tot_len = 0;
|
||||
this->len = 0;
|
||||
memset(this->block, 0, sizeof(this->block));
|
||||
memset(this->digest, 0, sizeof(this->digest));
|
||||
}
|
||||
|
||||
void SetIV(uint32_t* iv)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
this->h[i] = iv[i];
|
||||
}
|
||||
|
||||
void Update(const unsigned char *message, size_t mlen) override
|
||||
@@ -195,7 +191,7 @@ public:
|
||||
this->tot_len += (block_nb + 1) << 6;
|
||||
}
|
||||
|
||||
void Finalize() override
|
||||
Anope::string Finalize() override
|
||||
{
|
||||
unsigned block_nb = 1 + ((SHA256_BLOCK_SIZE - 9) < (this->len % SHA256_BLOCK_SIZE));
|
||||
unsigned len_b = (this->tot_len + this->len) << 3;
|
||||
@@ -204,43 +200,20 @@ public:
|
||||
this->block[this->len] = 0x80;
|
||||
UNPACK32(len_b, this->block + pm_len - 4);
|
||||
this->Transform(this->block, block_nb);
|
||||
unsigned char digest[SHA256_DIGEST_SIZE];
|
||||
memset(digest, 0, sizeof(digest));
|
||||
for (int i = 0 ; i < 8; ++i)
|
||||
UNPACK32(this->h[i], &this->digest[i << 2]);
|
||||
}
|
||||
UNPACK32(this->h[i], &digest[i << 2]);
|
||||
|
||||
Encryption::Hash GetFinalizedHash() override
|
||||
{
|
||||
Encryption::Hash hash;
|
||||
hash.first = this->digest;
|
||||
hash.second = SHA256_DIGEST_SIZE;
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class SHA256Provider final
|
||||
: public Encryption::Provider
|
||||
{
|
||||
public:
|
||||
SHA256Provider(Module *creator) : Encryption::Provider(creator, "sha256") { }
|
||||
|
||||
Encryption::Context *CreateContext(Encryption::IV *iv) override
|
||||
{
|
||||
return new SHA256Context(iv);
|
||||
}
|
||||
|
||||
Encryption::IV GetDefaultIV() override
|
||||
{
|
||||
Encryption::IV iv;
|
||||
iv.first = sha256_h0;
|
||||
iv.second = sizeof(sha256_h0) / sizeof(uint32_t);
|
||||
return iv;
|
||||
return Anope::string(reinterpret_cast<const char *>(&digest), sizeof(digest));
|
||||
}
|
||||
};
|
||||
|
||||
class ESHA256 final
|
||||
: public Module
|
||||
{
|
||||
SHA256Provider sha256provider;
|
||||
private:
|
||||
Encryption::SimpleProvider<SHA256Context> sha256provider;
|
||||
|
||||
unsigned iv[8];
|
||||
bool use_iv;
|
||||
@@ -275,8 +248,9 @@ class ESHA256 final
|
||||
}
|
||||
|
||||
public:
|
||||
ESHA256(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION | VENDOR),
|
||||
sha256provider(this)
|
||||
ESHA256(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
, sha256provider(this, "sha256", SHA256_BLOCK_SIZE, SHA256_DIGEST_SIZE)
|
||||
{
|
||||
use_iv = false;
|
||||
}
|
||||
@@ -288,15 +262,13 @@ public:
|
||||
else
|
||||
use_iv = false;
|
||||
|
||||
Encryption::IV initialization(this->iv, 8);
|
||||
SHA256Context ctx(&initialization);
|
||||
SHA256Context ctx;
|
||||
ctx.SetIV(this->iv);
|
||||
ctx.Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
ctx.Finalize();
|
||||
|
||||
Encryption::Hash hash = ctx.GetFinalizedHash();
|
||||
auto hash = ctx.Finalize();
|
||||
|
||||
std::stringstream buf;
|
||||
buf << "sha256:" << Anope::Hex(reinterpret_cast<const char *>(hash.first), hash.second) << ":" << GetIVString();
|
||||
buf << "sha256:" << Anope::Hex(hash) << ":" << GetIVString();
|
||||
Log(LOG_DEBUG_2) << "(enc_sha256) hashed password from [" << src << "] to [" << buf.str() << " ]";
|
||||
dest = buf.str();
|
||||
return EVENT_ALLOW;
|
||||
|
||||
Reference in New Issue
Block a user