summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/anope.h8
-rw-r--r--modules/core/enc_md5.cpp6
-rw-r--r--modules/core/enc_old.cpp4
-rw-r--r--modules/core/enc_sha1.cpp4
-rw-r--r--modules/core/enc_sha256.cpp14
-rw-r--r--src/misc.cpp45
-rw-r--r--src/tools/db-upgrade.cpp243
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;
+}