]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Add Base64 encode/decode functions to the core
authordanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Sun, 21 Feb 2010 17:08:45 +0000 (17:08 +0000)
committerdanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Sun, 21 Feb 2010 17:08:45 +0000 (17:08 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@12507 e03df62e-2008-0410-955e-edbf42e46eb7

include/inspstring.h
src/inspstring.cpp
src/modules/extra/m_ziplink.cpp [deleted file]
src/modules/m_hash.h
src/modules/m_httpd_acl.cpp
src/modules/m_password_hash.cpp

index dc7e00152898e3186b7cc37f0ad08ff6da858808..b11739999a70442ca8a4b449bcc531f48681bc9e 100644 (file)
@@ -41,6 +41,10 @@ CoreExport bool charremove(char* mp, char remove);
 
 /** Binary to hexadecimal conversion */
 CoreExport std::string BinToHex(const std::string& data);
+/** Base64 encode */
+CoreExport std::string BinToBase64(const std::string& data, const char* table = NULL, char pad = 0);
+/** Base64 decode */
+CoreExport std::string Base64ToBin(const std::string& data, const char* table = NULL);
 
 #endif
 
index 816e37a19648027ac619734049e8869b796e1eb9..74629bf5561de7c5945466d2e7f88c1332b05a90 100644 (file)
@@ -152,3 +152,75 @@ std::string BinToHex(const std::string& data)
        }
        return rv;
 }
+
+static const char b64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+std::string BinToBase64(const std::string& data_str, const char* table, char pad)
+{
+       if (!table)
+               table = b64table;
+
+       uint32_t buffer;
+       uint8_t* data = (uint8_t*)data_str.data();
+       std::string rv;
+       size_t i = 0;
+       while (i + 2 < data_str.length())
+       {
+               buffer = (data[i] << 16 | data[i+1] << 8 | data[i+2]);
+               rv.push_back(table[0x3F & (buffer >> 18)]);
+               rv.push_back(table[0x3F & (buffer >> 12)]);
+               rv.push_back(table[0x3F & (buffer >>  6)]);
+               rv.push_back(table[0x3F & (buffer >>  0)]);
+               i += 3;
+       }
+       if (data_str.length() == i)
+       {
+               // no extra characters
+       }
+       else if (data_str.length() == i + 1)
+       {
+               buffer = data[i] << 16;
+               rv.push_back(table[0x3F & (buffer >> 18)]);
+               rv.push_back(table[0x3F & (buffer >> 12)]);
+               if (pad)
+               {
+                       rv.push_back(pad);
+                       rv.push_back(pad);
+               }
+       }
+       else if (data_str.length() == i + 2)
+       {
+               buffer = (data[i] << 16 | data[i] << 8);
+               rv.push_back(table[0x3F & (buffer >> 18)]);
+               rv.push_back(table[0x3F & (buffer >> 12)]);
+               rv.push_back(table[0x3F & (buffer >>  6)]);
+               if (pad)
+                       rv.push_back(pad);
+       }
+       return rv;
+}
+
+std::string Base64ToBin(const std::string& data_str, const char* table)
+{
+       if (!table)
+               table = b64table;
+
+       bool ok = true;
+       int bitcount = 0;
+       uint32_t buffer;
+       const char* data = data_str.c_str();
+       std::string rv;
+       while (ok)
+       {
+               const char* find = strchr(table, *data);
+               ok = (find && find < table + 64);
+               buffer = (buffer << 6) | (ok ? find - table : 0);
+               bitcount += 6;
+               if (bitcount >= 8)
+               {
+                       bitcount -= 8;
+                       rv.push_back((buffer >> bitcount) & 0xFF);
+               }
+       }
+       return rv;
+}
diff --git a/src/modules/extra/m_ziplink.cpp b/src/modules/extra/m_ziplink.cpp
deleted file mode 100644 (file)
index 391ba75..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*       +------------------------------------+
- *       | Inspire Internet Relay Chat Daemon |
- *       +------------------------------------+
- *
- *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
- * See: http://wiki.inspircd.org/Credits
- *
- * This program is free but copyrighted software; see
- *            the file COPYING for details.
- *
- * ---------------------------------------------------
- */
-
-#include "inspircd.h"
-#include <zlib.h>
-#include <iostream>
-
-/* $ModDesc: Provides zlib link support for servers */
-/* $LinkerFlags: -lz */
-
-/*
- * ZLIB_BEST_COMPRESSION (9) is used for all sending of data with
- * a flush after each chunk. A frame may contain multiple lines
- * and should be treated as raw binary data.
- */
-
-/* Status of a connection */
-enum izip_status { IZIP_CLOSED = 0, IZIP_OPEN };
-
-/** Represents an zipped connections extra data
- */
-class izip_session
-{
- public:
-       z_stream c_stream;      /* compression stream */
-       z_stream d_stream;      /* uncompress stream */
-       izip_status status;     /* Connection status */
-       std::string outbuf;     /* Holds output buffer (compressed) */
-       std::string inbuf;      /* Holds input buffer (compressed) */
-};
-
-class ModuleZLib : public Module
-{
-       izip_session* sessions;
-
-       /* Used for stats z extensions */
-       float total_out_compressed;
-       float total_in_compressed;
-       float total_out_uncompressed;
-       float total_in_uncompressed;
-
-       /* Used for reading data from the wire and compressing data to. */
-       char *net_buffer;
-       unsigned int net_buffer_size;
- public:
-
-       ModuleZLib()
-       {
-               sessions = new izip_session[ServerInstance->SE->GetMaxFds()];
-               for (int i = 0; i < ServerInstance->SE->GetMaxFds(); i++)
-                       sessions[i].status = IZIP_CLOSED;
-
-               total_out_compressed = total_in_compressed = 0;
-               total_out_uncompressed = total_in_uncompressed = 0;
-               Implementation eventlist[] = { I_OnStats };
-               ServerInstance->Modules->Attach(eventlist, this, 1);
-
-               // Allocate a buffer which is used for reading and writing data
-               net_buffer_size = ServerInstance->Config->NetBufferSize;
-               net_buffer = new char[net_buffer_size];
-       }
-
-       ~ModuleZLib()
-       {
-               delete[] sessions;
-               delete[] net_buffer;
-       }
-
-       Version GetVersion()
-       {
-               return Version("Provides zlib link support for servers", VF_VENDOR);
-       }
-
-       /* Handle stats z (misc stats) */
-       ModResult OnStats(char symbol, User* user, string_list &results)
-       {
-               if (symbol == 'z')
-               {
-                       std::string sn = ServerInstance->Config->ServerName;
-
-                       /* Yeah yeah, i know, floats are ew.
-                        * We used them here because we'd be casting to float anyway to do this maths,
-                        * and also only floating point numbers can deal with the pretty large numbers
-                        * involved in the total throughput of a server over a large period of time.
-                        * (we dont count 64 bit ints because not all systems have 64 bit ints, and floats
-                        * can still hold more.
-                        */
-                       float outbound_r = (total_out_compressed / (total_out_uncompressed + 0.001)) * 100;
-                       float inbound_r = (total_in_compressed / (total_in_uncompressed + 0.001)) * 100;
-
-                       float total_compressed = total_in_compressed + total_out_compressed;
-                       float total_uncompressed = total_in_uncompressed + total_out_uncompressed;
-
-                       float total_r = (total_compressed / (total_uncompressed + 0.001)) * 100;
-
-                       char outbound_ratio[MAXBUF], inbound_ratio[MAXBUF], combined_ratio[MAXBUF];
-
-                       sprintf(outbound_ratio, "%3.2f%%", outbound_r);
-                       sprintf(inbound_ratio, "%3.2f%%", inbound_r);
-                       sprintf(combined_ratio, "%3.2f%%", total_r);
-
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_compressed   = "+ConvToStr(total_out_compressed));
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_compressed    = "+ConvToStr(total_in_compressed));
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_uncompressed = "+ConvToStr(total_out_uncompressed));
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_uncompressed  = "+ConvToStr(total_in_uncompressed));
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS percentage_of_original_outbound_traffic        = "+outbound_ratio);
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS percentage_of_orignal_inbound_traffic         = "+inbound_ratio);
-                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS total_size_of_original_traffic        = "+combined_ratio);
-                       return MOD_RES_PASSTHRU;
-               }
-
-               return MOD_RES_PASSTHRU;
-       }
-
-       void OnStreamSocketConnect(StreamSocket* user)
-       {
-               OnStreamSocketAccept(user, 0, 0);
-       }
-
-       void OnRawSocketAccept(StreamSocket* user, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*)
-       {
-               int fd = user->GetFd();
-
-               izip_session* session = &sessions[fd];
-
-               /* Just in case... */
-               session->outbuf.clear();
-
-               session->c_stream.zalloc = (alloc_func)0;
-               session->c_stream.zfree = (free_func)0;
-               session->c_stream.opaque = (voidpf)0;
-
-               session->d_stream.zalloc = (alloc_func)0;
-               session->d_stream.zfree = (free_func)0;
-               session->d_stream.opaque = (voidpf)0;
-
-               /* If we cant call this, well, we're boned. */
-               if (inflateInit(&session->d_stream) != Z_OK)
-               {
-                       session->status = IZIP_CLOSED;
-                       return;
-               }
-
-               /* Same here */
-               if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK)
-               {
-                       inflateEnd(&session->d_stream);
-                       session->status = IZIP_CLOSED;
-                       return;
-               }
-
-               /* Just in case, do this last */
-               session->status = IZIP_OPEN;
-       }
-
-       void OnStreamSocketClose(StreamSocket* user)
-       {
-               int fd = user->GetFd();
-               CloseSession(&sessions[fd]);
-       }
-
-       int OnStreamSocketRead(StreamSocket* user, std::string& recvq)
-       {
-               int fd = user->GetFd();
-               /* Find the sockets session */
-               izip_session* session = &sessions[fd];
-
-               if (session->status == IZIP_CLOSED)
-                       return -1;
-
-               if (session->inbuf.empty())
-               {
-                       /* Read read_buffer_size bytes at a time to the buffer (usually 2.5k) */
-                       int readresult = read(fd, net_buffer, net_buffer_size);
-
-                       if (readresult < 0)
-                       {
-                               if (errno == EINTR || errno == EAGAIN)
-                                       return 0;
-                       }
-                       if (readresult <= 0)
-                               return -1;
-
-                       total_in_compressed += readresult;
-
-                       /* Copy the compressed data into our input buffer */
-                       session->inbuf.append(net_buffer, readresult);
-               }
-
-               size_t in_len = session->inbuf.length();
-               char* buffer = ServerInstance->GetReadBuffer();
-               int count = ServerInstance->Config->NetBufferSize;
-
-               /* Prepare decompression */
-               session->d_stream.next_in = (Bytef *)session->inbuf.c_str();
-               session->d_stream.avail_in = in_len;
-
-               session->d_stream.next_out = (Bytef*)buffer;
-               /* Last byte is reserved for NULL terminating that beast */
-               session->d_stream.avail_out = count - 1;
-
-               /* Z_SYNC_FLUSH: Do as much as possible */
-               int ret = inflate(&session->d_stream, Z_SYNC_FLUSH);
-               /* TODO CloseStream() in here at random places */
-               switch (ret)
-               {
-                       case Z_NEED_DICT:
-                       case Z_STREAM_ERROR:
-                               /* This is one of the 'not supposed to happen' things.
-                                * Memory corruption, anyone?
-                                */
-                               Error(session, "General Error. This is not supposed to happen :/");
-                               break;
-                       case Z_DATA_ERROR:
-                               Error(session, "Decompression failed, malformed data");
-                               break;
-                       case Z_MEM_ERROR:
-                               Error(session, "Out of memory");
-                               break;
-                       case Z_BUF_ERROR:
-                               /* This one is non-fatal, buffer is just full
-                                * (can't happen here).
-                                */
-                               Error(session, "Internal error. This is not supposed to happen.");
-                               break;
-                       case Z_STREAM_END:
-                               /* This module *never* generates these :/ */
-                               Error(session, "End-of-stream marker received");
-                               break;
-                       case Z_OK:
-                               break;
-                       default:
-                               /* NO WAI! This can't happen. All errors are handled above. */
-                               Error(session, "Unknown error");
-                               break;
-               }
-               if (ret != Z_OK)
-               {
-                       return -1;
-               }
-
-               /* Update the inbut buffer */
-               unsigned int input_compressed = in_len - session->d_stream.avail_in;
-               session->inbuf = session->inbuf.substr(input_compressed);
-
-               /* Update counters (Old size - new size) */
-               unsigned int uncompressed_length = (count - 1) - session->d_stream.avail_out;
-               total_in_uncompressed += uncompressed_length;
-
-               /* Null-terminate the buffer -- this doesnt harm binary data */
-               recvq.append(buffer, uncompressed_length);
-               return 1;
-       }
-
-       int OnStreamSocketWrite(StreamSocket* user, std::string& sendq)
-       {
-               int fd = user->GetFd();
-               izip_session* session = &sessions[fd];
-
-               if(session->status != IZIP_OPEN)
-                       /* Seriously, wtf? */
-                       return -1;
-
-               int ret;
-
-               /* This loop is really only supposed to run once, but in case 'compr'
-                * is filled up somehow we are prepared to handle this situation.
-                */
-               unsigned int offset = 0;
-               do
-               {
-                       /* Prepare compression */
-                       session->c_stream.next_in = (Bytef*)sendq.data() + offset;
-                       session->c_stream.avail_in = sendq.length() - offset;
-
-                       session->c_stream.next_out = (Bytef*)net_buffer;
-                       session->c_stream.avail_out = net_buffer_size;
-
-                       /* Compress the text */
-                       ret = deflate(&session->c_stream, Z_SYNC_FLUSH);
-                       /* TODO CloseStream() in here at random places */
-                       switch (ret)
-                       {
-                               case Z_OK:
-                                       break;
-                               case Z_BUF_ERROR:
-                                       /* This one is non-fatal, buffer is just full
-                                        * (can't happen here).
-                                        */
-                                       Error(session, "Internal error. This is not supposed to happen.");
-                                       break;
-                               case Z_STREAM_ERROR:
-                                       /* This is one of the 'not supposed to happen' things.
-                                        * Memory corruption, anyone?
-                                        */
-                                       Error(session, "General Error. This is also not supposed to happen.");
-                                       break;
-                               default:
-                                       Error(session, "Unknown error");
-                                       break;
-                       }
-
-                       if (ret != Z_OK)
-                               return 0;
-
-                       /* Space before - space after stuff was added to this */
-                       unsigned int compressed = net_buffer_size - session->c_stream.avail_out;
-                       unsigned int uncompressed = sendq.length() - session->c_stream.avail_in;
-
-                       /* Make it skip the data which was compressed already */
-                       offset += uncompressed;
-
-                       /* Update stats */
-                       total_out_uncompressed += uncompressed;
-                       total_out_compressed += compressed;
-
-                       /* Add compressed to the output buffer */
-                       session->outbuf.append((const char*)net_buffer, compressed);
-               } while (session->c_stream.avail_in != 0);
-
-               /* Lets see how much we can send out */
-               ret = write(fd, session->outbuf.data(), session->outbuf.length());
-
-               /* Check for errors, and advance the buffer if any was sent */
-               if (ret > 0)
-                       session->outbuf = session->outbuf.substr(ret);
-               else if (ret < 1)
-               {
-                       if (errno == EAGAIN)
-                               return 0;
-                       else
-                       {
-                               session->outbuf.clear();
-                               return -1;
-                       }
-               }
-
-               return 1;
-       }
-
-       void Error(izip_session* session, const std::string &text)
-       {
-               ServerInstance->SNO->WriteToSnoMask('l', "ziplink error: " + text);
-       }
-
-       void CloseSession(izip_session* session)
-       {
-               if (session->status == IZIP_OPEN)
-               {
-                       session->status = IZIP_CLOSED;
-                       session->outbuf.clear();
-                       inflateEnd(&session->d_stream);
-                       deflateEnd(&session->c_stream);
-               }
-       }
-
-};
-
-MODULE_INIT(ModuleZLib)
-
index 7deb4c68c74305a62144fa3443b6cffabf6954f1..edc9688b80d19d3089b5a1111b8b366b5b77caea 100644 (file)
@@ -29,18 +29,21 @@ class HashProvider : public DataProvider
                return BinToHex(sum(data));
        }
 
+       inline std::string b64sum(const std::string& data)
+       {
+               return BinToBase64(sum(data), NULL, 0);
+       }
+
        /** Allows the IVs for the hash to be specified. As the choice of initial IV is
         * important for the security of a hash, this should not be used except to
         * maintain backwards compatability. This also allows you to change the hex
         * sequence from its default of "0123456789abcdef", which does not improve the
         * strength of the output, but helps confuse those attempting to implement it.
         *
-        * Only m_md5 implements this request; only m_cloaking should use it.
-        *
         * Example:
         * \code
         * unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC };
-        * std::string result = Hash.sumIV(iv, "0123456789abcdef", "data");
+        * std::string result = Hash.sumIV(iv, "fedcba9876543210", "data");
         * \endcode
         */
        virtual std::string sumIV(unsigned int* IV, const char* HexMap, const std::string &sdata) = 0;
index 94cc4045f0b86869342708d2e7df9ecab2ff2723..86d06fd25fa35d18896e08a1252e80c140cdf94f 100644 (file)
@@ -105,61 +105,6 @@ class ModuleHTTPAccessList : public Module
                response.Send();
        }
 
-       bool IsBase64(unsigned char c)
-       {
-               return (isalnum(c) || (c == '+') || (c == '/'));
-       }
-
-       std::string Base64Decode(const std::string &base64)
-       {
-               const std::string base64_chars("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
-               int inputlen = base64.length();
-               int i = 0, j = 0, input = 0;
-               unsigned char longbuf[4], shortbuf[3];
-               std::string retval;
-
-               if (inputlen == 0)
-                       return "";
-
-               while (inputlen-- && (base64[input] != '=') && IsBase64(base64[input]))
-               {
-                       longbuf[i++] = base64[input];
-                       input++;
-                       if (i == 4)
-                       {
-                               for (i = 0; i < 4; ++i)
-                                       longbuf[i] = base64_chars.find(longbuf[i]);
-
-                               shortbuf[0] = (longbuf[0] << 2)         + ((longbuf[1] & 0x30) >> 4);
-                               shortbuf[1] = ((longbuf[1] & 0xf) << 4) + ((longbuf[2] & 0x3c) >> 2);
-                               shortbuf[2] = ((longbuf[2] & 0x3) << 6) + longbuf[3];
-
-                               for (i = 0; i < 3; ++i)
-                                       retval += shortbuf[i];
-
-                               i = 0;
-                       }
-               }
-
-               if (i)
-               {
-                       for (j = i; j < 4; ++j)
-                               longbuf[j] = 0;
-
-                       for (j = 0; j < 4; ++j)
-                               longbuf[j] = base64_chars.find(longbuf[j]);
-
-                       shortbuf[0] = (longbuf[0] << 2)         + ((longbuf[1] & 0x30) >> 4);
-                       shortbuf[1] = ((longbuf[1] & 0xf) << 4) + ((longbuf[2] & 0x3c) >> 2);
-                       shortbuf[2] = ((longbuf[2] & 0x3) << 6) + longbuf[3];
-
-                       for (j = 0; j < i - 1; ++j)
-                               retval += shortbuf[j];
-               }
-
-               return retval;
-       }
-
        void OnEvent(Event& event)
        {
                if (event.id == "httpd_acl")
@@ -230,7 +175,7 @@ class ModuleHTTPAccessList : public Module
                                                                std::string pass;
 
                                                                sep.GetToken(base64);
-                                                               std::string userpass = Base64Decode(base64);
+                                                               std::string userpass = Base64ToBin(base64);
                                                                ServerInstance->Logs->Log("m_httpd_acl", DEBUG, "HTTP authorization: %s (%s)", userpass.c_str(), base64.c_str());
 
                                                                irc::sepstream userpasspair(userpass, ':');
index a9870c05773eab98de1a0811491c5dc8418eb766..d27856b3e31d16fdfeab8036391bc822565b08fc 100644 (file)
 #include "inspircd.h"
 #include "m_hash.h"
 
+static std::string hmac(HashProvider* hp, const std::string& key, const std::string& msg)
+{
+       std::string hmac1, hmac2;
+       for (size_t n = 0; n < key.length(); n++)
+       {
+               hmac1.push_back(static_cast<char>(key[n] ^ 0x5C));
+               hmac2.push_back(static_cast<char>(key[n] ^ 0x36));
+       }
+       hmac2.append(msg);
+       hmac1.append(hp->sum(hmac2));
+       return hp->sum(hmac1);
+}
+
 /* Handle /MKPASSWD
  */
 class CommandMkpasswd : public Command
@@ -29,6 +42,22 @@ class CommandMkpasswd : public Command
 
        void MakeHash(User* user, const std::string& algo, const std::string& stuff)
        {
+               if (algo.substr(0,5) == "hmac-")
+               {
+                       std::string type = algo.substr(5);
+                       HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type);
+                       if (!hp)
+                       {
+                               user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str());
+                               return;
+                       }
+                       std::string salt = GenRandomStr(6, false);
+                       std::string target = hmac(hp, salt, stuff);
+                       std::string str = BinToBase64(salt) + "$" + BinToBase64(target, NULL, 0);
+
+                       user->WriteServ("NOTICE %s :%s hashed password for %s is %s",
+                               user->nick.c_str(), algo.c_str(), stuff.c_str(), str.c_str());
+               }
                HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + algo);
                if (hp)
                {
@@ -38,7 +67,6 @@ class CommandMkpasswd : public Command
                }
                else
                {
-                       /* I dont do flying, bob. */
                        user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str());
                }
        }
@@ -68,6 +96,33 @@ class ModuleOperHash : public Module
 
        virtual ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
        {
+               if (hashtype.substr(0,5) == "hmac-")
+               {
+                       std::string type = hashtype.substr(5);
+                       HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type);
+                       if (!hp)
+                               return MOD_RES_PASSTHRU;
+                       // this is a valid hash, from here on we either accept or deny
+                       std::string::size_type sep = data.find('$');
+                       if (sep == std::string::npos)
+                               return MOD_RES_DENY;
+                       std::string salt = Base64ToBin(data.substr(0, sep));
+                       std::string target = Base64ToBin(data.substr(sep + 1));
+
+                       std::string hmac1, hmac2;
+                       for (size_t n = 0; n < salt.length(); n++)
+                       {
+                               hmac1.push_back(static_cast<char>(salt[n] ^ 0x5C));
+                               hmac2.push_back(static_cast<char>(salt[n] ^ 0x36));
+                       }
+                       hmac2.append(input);
+                       hmac1.append(hp->sum(hmac2));
+                       if (target == hp->sum(hmac1))
+                               return MOD_RES_ALLOW;
+                       else
+                               return MOD_RES_DENY;
+               }
+
                HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + hashtype);
 
                /* Is this a valid hash name? */