mirror of
https://github.com/anope/anope.git
synced 2026-07-04 05:33:12 +02:00
Add a db-upgrade to convert base64-encoded encrypted passwords to hexadecimal strings of the raw data, add in Anope::Hex for C-style strings and added Anope::Unhex, modified the encryption modules to use Hex and Unhex.
This commit is contained in:
@@ -322,6 +322,14 @@ namespace Anope
|
||||
* @return a anope::string containing the hex value
|
||||
*/
|
||||
extern CoreExport string Hex(const string &data);
|
||||
extern CoreExport string Hex(const char *data, unsigned len);
|
||||
|
||||
/** Converts a string from hex
|
||||
* @param src The data to be converted
|
||||
* @param dest The destination string
|
||||
*/
|
||||
extern CoreExport void Unhex(const Anope::string &src, Anope::string &dest);
|
||||
extern CoreExport void Unhex(const Anope::string &src, char *dest);
|
||||
}
|
||||
|
||||
/** sepstream allows for splitting token seperated lists.
|
||||
|
||||
@@ -330,14 +330,12 @@ class EMD5 : public Module
|
||||
MD5_CTX context;
|
||||
char digest[17] = "";
|
||||
Anope::string buf = "md5:";
|
||||
Anope::string cpass;
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
MD5Final(reinterpret_cast<char *>(digest), &context);
|
||||
MD5Final(reinterpret_cast<unsigned char *>(digest), &context);
|
||||
|
||||
b64_encode(digest, cpass);
|
||||
buf += cpass;
|
||||
buf += Anope::Hex(digest, 16);
|
||||
Alog(LOG_DEBUG_2) << "(enc_md5) hashed password from [" << src << "] to [" << buf << "]";
|
||||
dest = buf;
|
||||
return EVENT_ALLOW;
|
||||
|
||||
@@ -334,7 +334,6 @@ class EOld : public Module
|
||||
{
|
||||
MD5_CTX context;
|
||||
char digest[33] = "", digest2[17] = "";
|
||||
Anope::string cpass;
|
||||
int i;
|
||||
Anope::string buf = "oldmd5:";
|
||||
|
||||
@@ -346,8 +345,7 @@ class EOld : public Module
|
||||
for (i = 0; i < 32; i += 2)
|
||||
digest2[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]);
|
||||
|
||||
b64_encode(digest2, cpass);
|
||||
buf += cpass;
|
||||
buf += Anope::Hex(digest2, 16);
|
||||
Alog(LOG_DEBUG_2) << "(enc_old) hashed password from [" << src << "] to [" << buf << "]";
|
||||
dest = buf;
|
||||
return EVENT_ALLOW;
|
||||
|
||||
@@ -184,14 +184,12 @@ class ESHA1 : public Module
|
||||
SHA1_CTX context;
|
||||
char digest[21] = "";
|
||||
Anope::string buf = "sha1:";
|
||||
Anope::string cpass;
|
||||
|
||||
SHA1Init(&context);
|
||||
SHA1Update(&context, reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
SHA1Final(reinterpret_cast<unsigned char *>(digest), &context);
|
||||
|
||||
b64_encode(digest, cpass);
|
||||
buf += cpass;
|
||||
buf += Anope::Hex(digest, 20);
|
||||
Alog(LOG_DEBUG_2) << "(enc_sha1) hashed password from [" << src << "] to [" << buf << "]";
|
||||
dest = buf;
|
||||
return EVENT_ALLOW;
|
||||
|
||||
@@ -135,12 +135,10 @@ class ESHA256 : public Module
|
||||
Anope::string GetIVString()
|
||||
{
|
||||
char buf[33];
|
||||
Anope::string buf2;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
UNPACK32(iv[i], reinterpret_cast<unsigned char *>(&buf[i << 2]));
|
||||
buf[32] = '\0';
|
||||
b64_encode(buf, buf2);
|
||||
return buf2;
|
||||
return Anope::Hex(buf, 32);
|
||||
}
|
||||
|
||||
/* splits the appended IV from the password string so it can be used for the next encryption */
|
||||
@@ -149,8 +147,8 @@ class ESHA256 : public Module
|
||||
{
|
||||
size_t pos = password.find(':');
|
||||
Anope::string buf = password.substr(password.find(':', pos + 1) + 1, password.length());
|
||||
Anope::string buf2;
|
||||
b64_decode(buf, buf2);
|
||||
char buf2[33];
|
||||
Anope::Unhex(buf, buf2);
|
||||
for (int i = 0 ; i < 8; ++i)
|
||||
PACK32(reinterpret_cast<unsigned char *>(&buf2[i << 2]), iv[i]);
|
||||
}
|
||||
@@ -263,8 +261,7 @@ class ESHA256 : public Module
|
||||
|
||||
EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest)
|
||||
{
|
||||
char digest[SHA256_DIGEST_SIZE+1];
|
||||
Anope::string cpass;
|
||||
char digest[SHA256_DIGEST_SIZE + 1];
|
||||
SHA256Context ctx;
|
||||
std::stringstream buf;
|
||||
|
||||
@@ -277,8 +274,7 @@ class ESHA256 : public Module
|
||||
SHA256Update(&ctx, reinterpret_cast<const unsigned char *>(src.c_str()), src.length());
|
||||
SHA256Final(&ctx, reinterpret_cast<unsigned char *>(digest));
|
||||
digest[SHA256_DIGEST_SIZE] = '\0';
|
||||
b64_encode(digest, cpass);
|
||||
buf << "sha256:" << cpass << ":" << GetIVString();
|
||||
buf << "sha256:" << Anope::Hex(digest, SHA256_DIGEST_SIZE) << ":" << GetIVString();
|
||||
Alog(LOG_DEBUG_2) << "(enc_sha256) hashed password from [" << src << "] to [" << buf.str() << " ]";
|
||||
dest = buf.str();
|
||||
return EVENT_ALLOW;
|
||||
|
||||
+44
-1
@@ -1319,7 +1319,6 @@ bool str_is_cidr(const Anope::string &str, uint32 &ip, uint32 &mask, Anope::stri
|
||||
* @param the data to be converted
|
||||
* @return a anope::string containing the hex value
|
||||
*/
|
||||
|
||||
Anope::string Anope::Hex(const Anope::string &data)
|
||||
{
|
||||
const char hextable[] = "0123456789abcdef";
|
||||
@@ -1335,3 +1334,47 @@ Anope::string Anope::Hex(const Anope::string &data)
|
||||
return rv;
|
||||
}
|
||||
|
||||
Anope::string Anope::Hex(const char *data, unsigned len)
|
||||
{
|
||||
const char hextable[] = "0123456789abcdef";
|
||||
|
||||
Anope::string rv;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
unsigned char c = data[i];
|
||||
rv += hextable[c >> 4];
|
||||
rv += hextable[c & 0xF];
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Converts a string from hex
|
||||
* @param src The data to be converted
|
||||
* @param dest The destination string
|
||||
*/
|
||||
void Anope::Unhex(const Anope::string &src, Anope::string &dest)
|
||||
{
|
||||
size_t len = src.length();
|
||||
Anope::string rv;
|
||||
for (size_t i = 0; i < len; i += 2)
|
||||
{
|
||||
char h = src[i], l = src[i + 1];
|
||||
unsigned char byte = (h >= 'a' ? h - 'a' + 10 : h - '0') << 4;
|
||||
byte += (l >= 'a' ? l - 'a' + 10 : l - '0');
|
||||
rv += byte;
|
||||
}
|
||||
dest = rv;
|
||||
}
|
||||
|
||||
void Anope::Unhex(const Anope::string &src, char *dest)
|
||||
{
|
||||
size_t len = src.length(), destpos = 0;
|
||||
for (size_t i = 0; i < len; i += 2)
|
||||
{
|
||||
char h = src[i], l = src[i + 1];
|
||||
unsigned char byte = (h >= 'a' ? h - 'a' + 10 : h - '0') << 4;
|
||||
byte += (l >= 'a' ? l - 'a' + 10 : l - '0');
|
||||
dest[destpos++] = byte;
|
||||
}
|
||||
dest[destpos] = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#ifndef _WIN32
|
||||
static const std::string C_LBLUE = "\033[1;34m";
|
||||
static const std::string C_NONE = "\033[m";
|
||||
#else
|
||||
static const std::string C_LBLUE = "";
|
||||
static const std::string C_NONE = "";
|
||||
#endif
|
||||
|
||||
/** sepstream allows for splitting token seperated lists.
|
||||
* Each successive call to sepstream::GetToken() returns
|
||||
* the next token, until none remain, at which point the method returns
|
||||
* an empty string.
|
||||
*/
|
||||
class sepstream
|
||||
{
|
||||
private:
|
||||
/** Original string.
|
||||
*/
|
||||
std::string tokens;
|
||||
/** Last position of a seperator token
|
||||
*/
|
||||
std::string::iterator last_starting_position;
|
||||
/** Current string position
|
||||
*/
|
||||
std::string::iterator n;
|
||||
/** Seperator value
|
||||
*/
|
||||
char sep;
|
||||
public:
|
||||
/** Create a sepstream and fill it with the provided data
|
||||
*/
|
||||
sepstream(const std::string &source, char seperator);
|
||||
virtual ~sepstream() { }
|
||||
|
||||
/** Fetch the next token from the stream
|
||||
* @param token The next token from the stream is placed here
|
||||
* @return True if tokens still remain, false if there are none left
|
||||
*/
|
||||
virtual bool GetToken(std::string &token);
|
||||
|
||||
/** Fetch the entire remaining stream, without tokenizing
|
||||
* @return The remaining part of the stream
|
||||
*/
|
||||
virtual const std::string GetRemaining();
|
||||
|
||||
/** Returns true if the end of the stream has been reached
|
||||
* @return True if the end of the stream has been reached, otherwise false
|
||||
*/
|
||||
virtual bool StreamEnd();
|
||||
};
|
||||
|
||||
sepstream::sepstream(const std::string &source, char seperator) : tokens(source), sep(seperator)
|
||||
{
|
||||
last_starting_position = n = tokens.begin();
|
||||
}
|
||||
|
||||
bool sepstream::GetToken(std::string &token)
|
||||
{
|
||||
std::string::iterator lsp = last_starting_position;
|
||||
|
||||
while (n != tokens.end())
|
||||
{
|
||||
if (*n == sep || n + 1 == tokens.end())
|
||||
{
|
||||
last_starting_position = n + 1;
|
||||
token = std::string(lsp, n + 1 == tokens.end() ? n + 1 : n);
|
||||
|
||||
while (token.length() && token.rfind(sep) == token.length() - 1)
|
||||
token.erase(token.end() - 1);
|
||||
|
||||
++n;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
token.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string sepstream::GetRemaining()
|
||||
{
|
||||
return std::string(n, tokens.end());
|
||||
}
|
||||
|
||||
bool sepstream::StreamEnd()
|
||||
{
|
||||
return n == tokens.end();
|
||||
}
|
||||
|
||||
std::vector<std::string> BuildStringVector(const std::string &src, char delim = ' ')
|
||||
{
|
||||
sepstream tokens(src, delim);
|
||||
std::string token;
|
||||
std::vector<std::string> Ret;
|
||||
|
||||
while (tokens.GetToken(token))
|
||||
Ret.push_back(token);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
std::string Hex(const char *data, size_t len)
|
||||
{
|
||||
const char hextable[] = "0123456789abcdef";
|
||||
|
||||
std::string rv;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
unsigned char c = data[i];
|
||||
rv += hextable[c >> 4];
|
||||
rv += hextable[c & 0xF];
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static const std::string Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
|
||||
unsigned b64_decode(const std::string &src, char *target)
|
||||
{
|
||||
unsigned state = 0, tarindex = 0;
|
||||
std::string::const_iterator ch = src.begin(), end = src.end();
|
||||
for (; ch != end; ++ch)
|
||||
{
|
||||
if (isspace(*ch)) /* Skip whitespace anywhere */
|
||||
continue;
|
||||
|
||||
if (*ch == Pad64)
|
||||
break;
|
||||
|
||||
size_t pos = Base64.find(*ch);
|
||||
if (pos == std::string::npos) /* A non-base64 character */
|
||||
return 0;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
target[tarindex] = pos << 2;
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
target[tarindex++] |= pos >> 4;
|
||||
target[tarindex] = (pos & 0x0f) << 4;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
target[tarindex++] |= pos >> 2;
|
||||
target[tarindex] = (pos & 0x03) << 6;
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
target[tarindex++] |= pos;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
return tarindex;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::cout << C_LBLUE << "Anope 1.9.2 -> 1.9.3 database upgrader" << C_NONE << std::endl << std::endl;
|
||||
|
||||
std::ifstream in("anope.db.old");
|
||||
if (!in.is_open())
|
||||
{
|
||||
std::cout << C_LBLUE << "Could not open anope.db.old for reading" << C_NONE << std::endl << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ofstream out("anope.db");
|
||||
if (!out.is_open())
|
||||
{
|
||||
std::cout << C_LBLUE << "Could not open anope.db for writing" << C_NONE << std::endl << std::endl;
|
||||
in.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (getline(in, line))
|
||||
{
|
||||
if (line.substr(0, 2) == "NC")
|
||||
{
|
||||
std::vector<std::string> parts = BuildStringVector(line);
|
||||
std::string password = parts[2];
|
||||
size_t colon = password.find(':');
|
||||
if (colon != std::string::npos && password.substr(0, colon) != "plain")
|
||||
{
|
||||
std::string hash = password.substr(colon + 1), iv;
|
||||
unsigned len;
|
||||
if (password.substr(0, colon) == "sha256")
|
||||
{
|
||||
colon = hash.find(':');
|
||||
iv = hash.substr(colon + 1);
|
||||
hash = hash.substr(0, colon);
|
||||
|
||||
char *iv_decoded = new char[iv.length() * 3 / 4 + 1];
|
||||
memset(iv_decoded, 0, iv.length() * 3 / 4 + 1);
|
||||
len = b64_decode(iv, iv_decoded);
|
||||
if (len)
|
||||
iv = Hex(iv_decoded, len);
|
||||
else
|
||||
iv.clear();
|
||||
delete [] iv_decoded;
|
||||
}
|
||||
char *hash_decoded = new char[hash.length() * 3 / 4 + 1];
|
||||
memset(hash_decoded, 0, hash.length() * 3 / 4 + 1);
|
||||
len = b64_decode(hash, hash_decoded);
|
||||
if (len)
|
||||
hash = Hex(hash_decoded, len);
|
||||
else
|
||||
hash.clear();
|
||||
delete [] hash_decoded;
|
||||
password = password.substr(0, colon + 1);
|
||||
if (!hash.empty())
|
||||
password += hash;
|
||||
if (!iv.empty())
|
||||
password += ":" + iv;
|
||||
parts[2] = password;
|
||||
}
|
||||
line.clear();
|
||||
for (unsigned part = 0, end = parts.size(); part < end; ++part)
|
||||
{
|
||||
if (part)
|
||||
line += ' ';
|
||||
line += parts[part];
|
||||
}
|
||||
}
|
||||
out << line << std::endl;
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user