diff options
-rw-r--r-- | include/anope.h | 8 | ||||
-rw-r--r-- | modules/core/enc_md5.cpp | 6 | ||||
-rw-r--r-- | modules/core/enc_old.cpp | 4 | ||||
-rw-r--r-- | modules/core/enc_sha1.cpp | 4 | ||||
-rw-r--r-- | modules/core/enc_sha256.cpp | 14 | ||||
-rw-r--r-- | src/misc.cpp | 45 | ||||
-rw-r--r-- | src/tools/db-upgrade.cpp | 243 |
7 files changed, 304 insertions, 20 deletions
diff --git a/include/anope.h b/include/anope.h index be5c2f964..84f68ac45 100644 --- a/include/anope.h +++ b/include/anope.h @@ -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. diff --git a/modules/core/enc_md5.cpp b/modules/core/enc_md5.cpp index 63ac5f101..3ec3f8ecd 100644 --- a/modules/core/enc_md5.cpp +++ b/modules/core/enc_md5.cpp @@ -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; diff --git a/modules/core/enc_old.cpp b/modules/core/enc_old.cpp index 2928b4d0d..dfaa838a9 100644 --- a/modules/core/enc_old.cpp +++ b/modules/core/enc_old.cpp @@ -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; diff --git a/modules/core/enc_sha1.cpp b/modules/core/enc_sha1.cpp index 4047f539a..5c4f2b066 100644 --- a/modules/core/enc_sha1.cpp +++ b/modules/core/enc_sha1.cpp @@ -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; diff --git a/modules/core/enc_sha256.cpp b/modules/core/enc_sha256.cpp index 15dfce120..4fb076b8a 100644 --- a/modules/core/enc_sha256.cpp +++ b/modules/core/enc_sha256.cpp @@ -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; diff --git a/src/misc.cpp b/src/misc.cpp index 048949d0c..b3c298dcd 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -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; +} diff --git a/src/tools/db-upgrade.cpp b/src/tools/db-upgrade.cpp new file mode 100644 index 000000000..fe9480803 --- /dev/null +++ b/src/tools/db-upgrade.cpp @@ -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; +} |