ソースを参照

Merge branch 'crypt-updates'

* crypt-updates:
  * Show salted-Sha1 in cmd_sha1 and cmd_hash
  * Add cmd_hash which returns the MD5, SHA1 and SHA256 of the given string.
  * Update LICENSE to reflect work by dirtirc
  * Add help entry for new blowfish cmds
  * Add cmd_encrypt_fish and cmd_decrypt_fish which uses eggdrop's blowfish (same as FiSH)
  * Search in lib/ for libraries
  * Add eggdrop's blowfish which will enable FiSH support
  * Add SHA256
Bryan Drewery 16 年 前
コミット
bc1c90d649
12 ファイル変更447 行追加13 行削除
  1. 2 0
      LICENSE
  2. 3 0
      doc/UPDATES
  3. 34 10
      doc/help.txt
  4. 80 0
      src/cmds.c
  5. 1 1
      src/compat/Makefile.in
  6. 47 0
      src/crypt.c
  7. 6 0
      src/crypt.h
  8. 4 2
      src/crypto/Makefile.in
  9. 232 0
      src/crypto/bf_util.c
  10. 22 0
      src/crypto/bf_util.h
  11. 2 0
      src/crypto/crypto.h
  12. 14 0
      src/mod/irc.mod/msgcmds.c

+ 2 - 0
LICENSE

@@ -25,6 +25,8 @@ This package includes a mix of licenses:
  * It may be used for any purpose as long as this notice remains intact
  * on all source code distributions
 
+ This contains code derived from dirtirc (which is mostly derived from eggdrop): http://dirtirc.sf.net/
+
 /*
  * Copyright (C) 1997 Robey Pointer
  * Copyright (C) 1999 - 2008 Eggheads Development Team (http://www.eggheads.org)

+ 3 - 0
doc/UPDATES

@@ -92,6 +92,9 @@
   * Floodbots (+f) and Resolvbots (+r) are now listed in cmd_userlist
   * Floodbots (+f) will automatically unDEAF themselves to they can monitor the channel for floods (namely flood-chan).
     Note that this is done about 10 seconds after adding +f to a bot. Removing +f will set DEAF again.
+  * Added SHA256 support (cmd_sha256, Auth cmd: sha256)
+  * Add cmd_encrypt_fish and cmd_decrypt_fish which uses eggdrop's blowfish (same as FiSH)
+  * Add cmd_hash which returns the MD5, SHA1 and SHA256 of the given string.
 
 1.2.16.1
 * Fix linux compile errors

+ 34 - 10
doc/help.txt

@@ -265,7 +265,7 @@ See also: cmdpass
 ###  $bbotjoin$b <bot> <channel> [options]
    Adds a channel to the bot's channel list. If options are specified, the 
    channel will be configured with the options.
-
+ 
    $bTHIS CMD IS CURRENTLY EXPERIMENTAL AND WILL NOT ACTUALLY SAVE STATE$b
    $bMEANING, ALL BOTS WILL JOIN EVENTUALLY AFTER DOING BOTJOIN$b
  
@@ -904,7 +904,14 @@ See also: down
 ###  $bdecrypt$b <key> <string>
    Decrypts the string using the specified key.
  
-See also: encrypt, randstring, md5, sha1
+See also: decrypt_fish, encrypt, encrypt_fish, randstring, md5, sha1, sha256, hash
+::decrypt_fish
+###  $bdecrypt_fish$b <key> <string>
+   Decrypts the string using the specified key.
+ 
+   This algorithm is eggdrop's blowfish, same as FiSH.
+ 
+See also: decrypt, encrypt, encrypt_fish, randstring, md5, sha1, sha256, hash
 :leaf:deluser
 ###  $bdeluser$b <nickname>
    Deletes a user record for a user on the channel, using their
@@ -971,7 +978,14 @@ See also: color, console, login, page, strip
 ###  $bencrypt$b <key> <string>
    Encrypts the string using the specified key.
  
-See also: decrypt, randstring, md5, sha1
+See also: encrypt_fish, decrypt, decrypt_fish, randstring, md5, sha1, sha256, hash
+::encrypt_fish
+###  $bencrypt_fish$b <key> <string>
+   Encrypts the string using the specified key.
+ 
+   This algorithm is eggdrop's blowfish, same as FiSH.
+ 
+See also: encrypt, decrypt, decrypt_fish, randstring, md5, sha1, sha256, hash
 ::exec:
 ###  $bexec$b <params>
    The bot will execute the specified program with each param specified,
@@ -1048,6 +1062,11 @@ See also: console, channels%{+m}, status%{-}
    Perm owners may not change their handle without recompiling binaries first. 
  
 See also: newpass%{+mi}, chhandle, chpass%{-}%{+n}, chsecpass%{-}
+::hash
+###  $bhash$b <string>
+   Returns the MD5, SHA1, and SHA256 hash of the specified string.
+ 
+See also: randstring, md5, sha1, sha256, encrypt, encrypt_fish, decrypt, decrypt_fish
 ::help:
 ###  $bhelp$b [cmd]
    Alone, will show all cmds that match your flags. With a cmd it will show
@@ -1262,7 +1281,7 @@ See also: echo, color, console, page, strip, whois
      '%dmatch *.edu 16 25'
    This would show results 16 through 25 matching any users with a hostmask
    that ends with ".edu".
-
+ 
    $bThis command will not match on bots. You must use 'matchbot' for that.$b
 See also: matchbot
 ::matchbot
@@ -1274,7 +1293,7 @@ See also: match
 ###  $bmd5$b <string>
    Returns the MD5 hash of the specified string.
  
-See also: randstring, sha1, encrypt, decrypt
+See also: randstring, sha1, sha256, hash, encrypt, encrypt_fish, decrypt, decrypt_fish
 ::me
 ###  $bme$b <text>
    Performs an action on the party line. This appears as "* bryan is leaving",
@@ -1453,7 +1472,7 @@ See also: color, console, echo, login, strip
 ###  $brandstring$b <len>
    Displays a random string of length 'len' up to 300 chars.
  
-See also: md5, sha1, encrypt, decrypt
+See also: md5, sha1, sha256, hash, encrypt, encrypt_fish, decrypt, decrypt_fish
 ::rehash
 ###  $brehash$b 
    Don't use this cmd, it doesn't do what you think it does, and can result
@@ -1599,7 +1618,7 @@ See also: reload, backup
  
 [L]  $bservers$b         Comma-separated list of servers the bot will use.
 [L]  $bservers6$b        Comma-separated list of servers the bot will use (FOR IPv6).
-
+ 
 [L]  $brbl-servers$b     Servers to use for RBL checking in channels that are +rbl.
  
 [S]  $brealname$b        The bot's "real name" when connecting. (supports '$n' expansion)
@@ -1626,11 +1645,11 @@ See also: reload, backup
  
 [B]  $bident-botnick$b   Send botnick instead of shell username on connect (non-ident)
 [B]  $boidentd$b         Make bot try and use oidentd spoofing as BOTNICK.
-
+ 
 [B]  $blink_cleartext$b  Allows bots to link without an encryption scheme. This is needed
                          for allowing older bots to link in. Be sure to never leave this on
                          unless upgrading or letting an older bot link in to upgrade.
-
+ 
 [B]  $bdccauth$b         Boolean (0 or 1). Set to use auth checking on dcc/telnet login.
 [N]  $bop-bots$b         Number of bots to ask every time an oprequest is to be made.
 [N]  $bin-bots$b         Number of bots to ask every time an inrequest is to be made.
@@ -1665,7 +1684,12 @@ See also: botset
 ###  $bsha1$b <string>
    Returns the SHA1 hash of the specified string.
  
-See also: randstring, md5, encrypt, decrypt
+See also: randstring, md5, sha256, hash, encrypt, encrypt_fish, decrypt, decrypt_fish
+::sha256
+###  $bsha256$b <string>
+   Returns the SHA256 hash of the specified string.
+ 
+See also: randstring, md5, sha1, hash, encrypt, encrypt_fish, decrypt, decrypt_fish
 ::simul
 ###  $bsimul$b <handle> <text>
    This allows you to simulate the specified handle typing the given text.

+ 80 - 0
src/cmds.c

@@ -66,6 +66,7 @@
 #include <bdlib/src/String.h>
 #include <bdlib/src/Stream.h>
 #include <bdlib/src/Array.h>
+#include <bdlib/src/base64.h>
 
 #include <ctype.h>
 #include <stdlib.h>
@@ -1613,6 +1614,22 @@ static void cmd_randstring(int idx, char *par)
     dprintf(idx, "Too long, must be <= 300\n");
 }
 
+static void cmd_hash(int idx, char *par)
+{
+  if (!par[0]) {
+    dprintf(idx, "Usage: hash <string>\n");
+    return;
+  }
+
+  putlog(LOG_CMDS, "*", "#%s# hash ...", dcc[idx].nick);
+  dprintf(idx, "MD5(%s) = %s\n", par, MD5(par));
+  dprintf(idx, "SHA1(%s) = %s\n", par, SHA1(par));
+  char *salted = salted_sha1(par);
+  dprintf(idx, "SALTED-SHA1(%s) = %s\n", par, salted);
+  free(salted);
+  dprintf(idx, "SHA256(%s) = %s\n", par, SHA256(par));
+}
+
 static void cmd_md5(int idx, char *par)
 {
   if (!par[0]) {
@@ -1633,6 +1650,21 @@ static void cmd_sha1(int idx, char *par)
 
   putlog(LOG_CMDS, "*", "#%s# sha1 ...", dcc[idx].nick);
   dprintf(idx, "SHA1(%s) = %s\n", par, SHA1(par));
+
+  char *salted = salted_sha1(par);
+  dprintf(idx, "SALTED-SHA1(%s) = %s\n", par, salted);
+  free(salted);
+}
+
+static void cmd_sha256(int idx, char *par)
+{
+  if (!par[0]) {
+    dprintf(idx, "Usage: sha256 <string>\n");
+    return;
+  }
+
+  putlog(LOG_CMDS, "*", "#%s# sha256 ...", dcc[idx].nick);
+  dprintf(idx, "SHA256(%s) = %s\n", par, SHA256(par));
 }
 
 static void cmd_conf(int idx, char *par)
@@ -1848,6 +1880,50 @@ static void cmd_encrypt(int idx, char *par)
   free(buf);
 }
 
+static void cmd_encrypt_fish(int idx, char *par)
+{
+  if (!par[0]) {
+    dprintf(idx, "Usage: encrypt_fish <key> <string>\n");
+    return;
+  }
+
+  putlog(LOG_CMDS, "*", "#%s# encrypt_fish ...", dcc[idx].nick);
+
+  char *key = newsplit(&par);
+
+  if (!par[0]) {
+    dprintf(idx, "Usage: encrypt_fish <key> <string>\n");
+    return;
+  }
+
+  const char salt2[] = SALT2;
+
+  bd::String bf_crypt = egg_bf_encrypt(bd::String(par), bd::String(key ? key : salt2));
+  dprintf(idx, "encrypt_fish(%s) = %s\n", par, bf_crypt.c_str());
+}
+
+static void cmd_decrypt_fish(int idx, char *par)
+{
+  if (!par[0]) {
+    dprintf(idx, "Usage: decrypt_fish <key> <string>\n");
+    return;
+  }
+
+  putlog(LOG_CMDS, "*", "#%s# decrypt_fish ...", dcc[idx].nick);
+
+  char *key = newsplit(&par);
+
+  if (!par[0]) {
+    dprintf(idx, "Usage: decrypt_fish <key> <string>\n");
+    return;
+  }
+
+  const char salt2[] = SALT2;
+
+  bd::String bf_decrypt = egg_bf_decrypt(bd::String(par), bd::String(key ? key : salt2));
+  dprintf(idx, "decrypt_fish(%s) = %s\n", par, bf_decrypt.c_str());
+}
+
 static void cmd_decrypt(int idx, char *par)
 {
   if (!par[0]) {
@@ -4567,11 +4643,15 @@ cmd_t C_dcc[] =
   {"test",		"",	(Function) cmd_test,		NULL, 0},
   {"botlink",		"a",	(Function) cmd_botlink,		NULL, 0},
   {"randstring", 	"", 	(Function) cmd_randstring, 	NULL, AUTH_ALL},
+  {"hash",		"",	(Function) cmd_hash,		NULL, AUTH_ALL},
   {"md5",		"",	(Function) cmd_md5,		NULL, AUTH_ALL},
   {"sha1",		"",	(Function) cmd_sha1,		NULL, AUTH_ALL},
+  {"sha256",		"",	(Function) cmd_sha256,		NULL, AUTH_ALL},
   {"conf",		"a",	(Function) cmd_conf,		NULL, 0},
   {"encrypt",		"",	(Function) cmd_encrypt,		NULL, AUTH_ALL},
+  {"encrypt_fish",	"",	(Function) cmd_encrypt_fish,	NULL, AUTH_ALL},
   {"decrypt",		"",	(Function) cmd_decrypt,		NULL, AUTH_ALL},
+  {"decrypt_fish",	"",	(Function) cmd_decrypt_fish,	NULL, AUTH_ALL},
   {"botcmd",		"i",	(Function) cmd_botcmd, 		NULL, HUB},
   {"hublevel", 		"a", 	(Function) cmd_hublevel, 	NULL, HUB},
   {"lagged", 		"m", 	(Function) cmd_lagged, 		NULL, HUB},

+ 1 - 1
src/compat/Makefile.in

@@ -9,7 +9,7 @@ depcomp = /bin/sh $(top_srcdir)/autotools/depcomp
 @SET_MAKE@
 
 STRIP = @STRIP@
-CXXFLAGS = @CXXFLAGS@ -I../.. -I$(top_srcdir) -I$(top_srcdir)/src @DEFS@ $(CFLGS)
+CXXFLAGS = @CXXFLAGS@ -I../.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_srcdir)/src @DEFS@ $(CFLGS)
 CPPFLAGS = @CPPFLAGS@
 
 OBJS = dirname.o \

+ 47 - 0
src/crypt.c

@@ -50,6 +50,23 @@ bd::String encrypt_string(const bd::String& key, const bd::String& data) {
   return encrypted;
 }
 
+#ifdef not_needed
+/**
+ * @brief Encrypt a string with Blowfish ECB
+ * @param key The key to encrypt with
+ * @param data The string to encrypt
+ * @return A new, encrypted string
+ */
+bd::String encrypt_string_bf(const bd::String& key, const bd::String& data) {
+  if (!key) return data;
+  size_t len = data.length();
+  char *bdata = (char*) bf_encrypt_ecb_binary(key.c_str(), (unsigned char*) data.c_str(), &len);
+  bd::String encrypted(bdata, len);
+  free(bdata);
+  return encrypted;
+}
+#endif
+
 /**
  * @brief Encrypt a string with AES 256 CBC
  * @param key The key to encrypt with
@@ -236,6 +253,36 @@ int sha1cmp(const char *hash, const char *string) {
   return n;
 }
 
+char *SHA256(const char *string)
+{
+  static int n = 0;
+  static char ret[5][SHA256_HASH_LENGTH + 1];
+  //Cleanse the current buffer
+  if (!string) {
+    OPENSSL_cleanse(ret[n], SHA256_HASH_LENGTH + 1);
+    return NULL;
+  }
+  char* sha256string = ret[n++];
+  unsigned char   sha256out[SHA256_HASH_LENGTH + 1] = "";
+  SHA256_CTX ctx;
+
+  SHA256_Init(&ctx);
+  SHA256_Update(&ctx, string, strlen(string));
+  SHA256_Final(sha256out, &ctx);
+  btoh(sha256out, SHA256_DIGEST_LENGTH, sha256string, SHA256_HASH_LENGTH + 1);
+  OPENSSL_cleanse(&ctx, sizeof(ctx));
+
+  if (n == 5) n = 0;
+
+  return sha256string;
+}
+
+int sha256cmp(const char *hash, const char *string) {
+  int n = strcmp(hash, SHA256(string));
+  SHA256(NULL);
+  return n;
+}
+
 void btoh(const unsigned char *md, size_t md_len, char *buf, const size_t buf_len)
 {
 #define doblock(n) simple_snprintf(&(buf[(i + n) << 1]), buf_len - ((i + n) << 1), "%02x", md[i + n]);

+ 6 - 0
src/crypt.h

@@ -16,6 +16,7 @@ namespace bd {
 };
 
 #define SHA_HASH_LENGTH (SHA_DIGEST_LENGTH << 1)
+#define SHA256_HASH_LENGTH (SHA256_DIGEST_LENGTH << 1)
 #define MD5_HASH_LENGTH (MD5_DIGEST_LENGTH << 1)
 
 #define SHA1_SALT_LEN 5
@@ -25,9 +26,14 @@ char *MD5(const char *);
 int md5cmp(const char *, const char*);
 char *SHA1(const char *);
 int sha1cmp(const char *, const char*);
+char *SHA256(const char *);
+int sha256cmp(const char *, const char*);
 
 char *encrypt_string(const char *, char *);
 bd::String encrypt_string(const bd::String&, const bd::String&);
+#ifdef not_needed
+bd::String encrypt_string_bf(const bd::String&, const bd::String&);
+#endif
 bd::String encrypt_string_cbc(const bd::String&, const bd::String&, unsigned char *);
 char *decrypt_string(const char *, char *);
 char *salted_sha1(const char *, const char* = NULL);

+ 4 - 2
src/crypto/Makefile.in

@@ -3,7 +3,7 @@ top_srcdir = @top_srcdir@
 srcdir = @srcdir@
 
 SHELL = @SHELL@
-CXXFLAGS = @CXXFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/pack @DEFS@ $(CFLGS)
+CXXFLAGS = @CXXFLAGS@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @DEFS@ $(CFLGS)
 CPPFLAGS = @CPPFLAGS@
 STRIP = @STRIP@
 
@@ -12,7 +12,9 @@ depcomp = /bin/sh $(top_srcdir)/autotools/depcomp
 
 @SET_MAKE@
 
-OBJS = aes_util.o
+OBJS = \
+       aes_util.o \
+       bf_util.o
 
 doofus:
 	@echo ""

+ 232 - 0
src/crypto/bf_util.c

@@ -0,0 +1,232 @@
+/* bf_util.c
+ *
+ */
+
+#include "crypto.h"
+#include "src/compat/compat.h"
+#include <bdlib/src/String.h>
+
+#define CRYPT_BLOCKSIZE BF_BLOCK
+
+BF_KEY bf_e_key, bf_d_key;
+
+static const char eggdrop_blowfish_base64[65] = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const char eggdrop_blowfish_base64_index[256] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  0,  1,
+   2,  3,  4,  5,  6,  7,  8,  9, 10, 11, -1, -1, -1, -1, -1, -1,
+  -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+  53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1,
+  -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+  27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+union bf_data {
+  struct {
+    unsigned long left;
+    unsigned long right;
+  } lr;
+  BF_LONG bf_long;
+};
+
+/* These were adapted from eggdrop's blowfish.mod as well as dirtirc */
+
+/*
+ * @brief Encrypt a string using eggdrop's blowfish
+ * @param in The string to encrypt.
+ * @param key The key to use.
+ * @returns The encrypted string.
+ */
+bd::String egg_bf_encrypt(bd::String in, const bd::String& key)
+{
+  /* No key, no encryption */
+  if (!key.length()) return in;
+
+  bd::String out(size_t(in.length() * 1.5));
+  size_t datalen = in.length();
+  if (datalen % 8 != 0) {
+    datalen += 8 - (datalen % 8);
+    in.resize(datalen, 0);
+  }
+  BF_set_key(&bf_e_key, key.length(), (unsigned char *)key.data());
+  bf_data data;
+  size_t part;
+  unsigned char *s = (unsigned char *)in.data();
+  for (size_t i = 0; i < in.length(); i += 8) {
+    data.lr.left = *s++ << 24;
+    data.lr.left += *s++ << 16;
+    data.lr.left += *s++ << 8;
+    data.lr.left += *s++;
+    data.lr.right = *s++ << 24;
+    data.lr.right += *s++ << 16;
+    data.lr.right += *s++ << 8;
+    data.lr.right += *s++;
+    BF_encrypt(&data.bf_long, &bf_e_key);
+    for (part = 0; part < 6; part++) {
+      out += eggdrop_blowfish_base64[data.lr.right & 0x3f];
+      data.lr.right = data.lr.right >> 6;
+    }
+    for (part = 0; part < 6; part++) {
+      out += eggdrop_blowfish_base64[data.lr.left & 0x3f];
+      data.lr.left = data.lr.left >> 6;
+    }
+  }
+  return out;
+}
+
+/*
+ * @brief Decrypt a string using eggdrop's blowfish
+ * @param in The string to decrypt.
+ * @param key The key to use.
+ * @returns The decrypted string if valid. The string passed in if no key is given. A truncated decrypted string in the case of error.
+ */
+bd::String egg_bf_decrypt(bd::String in, const bd::String& key)
+{
+  bd::String out(size_t(in.length() * .9));
+  // Too small to process
+  if (in.size() < 12) return out;
+
+  // Not valid base64
+  if (eggdrop_blowfish_base64_index[in[0]] == -1) return out;
+
+  int cut_off = in.length() % 12;
+  if (cut_off > 0)
+    in.resize(in.length() - cut_off);
+
+  BF_set_key(&bf_d_key, key.length(), (unsigned char *)key.data());
+  bf_data data;
+  char val;
+  size_t part;
+  char *s = (char *)in.data();
+  for (size_t i = 0; i < in.length(); i += 12) {
+    data.lr.left = 0;
+    data.lr.right = 0;
+    for (part = 0; part < 6; part++) {
+      if ((val = eggdrop_blowfish_base64_index[int(*s++)]) == -1) return out;
+      data.lr.right |= val << part * 6;
+    }
+    for (part = 0; part < 6; part++) {
+      if ((val = eggdrop_blowfish_base64_index[int(*s++)]) == -1) return out;
+      data.lr.left |= val << part * 6;
+    }
+    BF_decrypt(&data.bf_long, &bf_d_key);
+    for (part = 0; part < 4; part++) out += char((data.lr.left & (0xff << ((3 - part) * 8))) >> ((3 - part) * 8));
+    for (part = 0; part < 4; part++) out += char((data.lr.right & (0xff << ((3 - part) * 8))) >> ((3 - part) * 8));
+  }
+
+  return out;
+}
+
+#ifdef not_needed
+unsigned char *
+bf_encrypt_ecb_binary(const char *keydata, unsigned char *in, size_t *inlen)
+{
+  size_t len = *inlen;
+  int blocks = 0, block = 0;
+  unsigned char *out = NULL;
+
+  /* First pad indata to CRYPT_BLOCKSIZE multiple */
+  if (len % CRYPT_BLOCKSIZE)             /* more than 1 block? */
+    len += (CRYPT_BLOCKSIZE - (len % CRYPT_BLOCKSIZE));
+
+  out = (unsigned char *) my_calloc(1, len + 1);
+  memcpy(out, in, *inlen);
+  *inlen = len;
+
+  if (!keydata || !*keydata) {
+    /* No key, no encryption */
+    memcpy(out, in, len);
+  } else {
+    BF_set_key(&bf_e_key, strlen(keydata), (const unsigned char*) keydata);
+    /* Now loop through the blocks and crypt them */
+    blocks = len / CRYPT_BLOCKSIZE;
+    for (block = blocks - 1; block >= 0; --block)
+      BF_ecb_encrypt(&out[block * CRYPT_BLOCKSIZE], &out[block * CRYPT_BLOCKSIZE], &bf_e_key, BF_ENCRYPT);
+    OPENSSL_cleanse(&bf_e_key, sizeof(bf_e_key));
+  }
+  out[len] = 0;
+  return out;
+}
+
+unsigned char *
+bf_decrypt_ecb_binary(const char *keydata, unsigned char *in, size_t *len)
+{
+  int blocks = 0, block = 0;
+  unsigned char *out = NULL;
+
+  *len -= *len % CRYPT_BLOCKSIZE;
+  out = (unsigned char *) my_calloc(1, *len + 1);
+  memcpy(out, in, *len);
+
+  if (!keydata || !*keydata) {
+    /* No key, no decryption */
+  } else {
+    BF_set_key(&bf_d_key, strlen(keydata), (const unsigned char*) keydata);
+    /* Now loop through the blocks and decrypt them */
+    blocks = *len / CRYPT_BLOCKSIZE;
+
+    for (block = blocks - 1; block >= 0; --block)
+      BF_ecb_encrypt(&out[block * CRYPT_BLOCKSIZE], &out[block * CRYPT_BLOCKSIZE], &bf_d_key, BF_DECRYPT);
+    OPENSSL_cleanse(&bf_d_key, sizeof(bf_d_key));
+  }
+
+  *len = strlen((char*) out);
+  out[*len] = 0;
+  return out;
+}
+
+unsigned char *
+bf_encrypt_cbc_binary(const char *keydata, unsigned char *in, size_t *inlen, unsigned char *ivec)
+{
+  size_t len = *inlen;
+  unsigned char *out = NULL;
+
+  /* First pad indata to CRYPT_BLOCKSIZE multiple */
+  if (len % CRYPT_BLOCKSIZE)             /* more than 1 block? */
+    len += (CRYPT_BLOCKSIZE - (len % CRYPT_BLOCKSIZE));
+
+  out = (unsigned char *) my_calloc(1, len + 1);
+  *inlen = len;
+
+  if (!keydata || !*keydata) {
+    /* No key, no encryption */
+    memcpy(out, in, len);
+  } else {
+    BF_set_key(&bf_e_key, strlen(keydata), (const unsigned char*) keydata);
+    BF_cbc_encrypt(in, out, len, &bf_e_key, ivec, BF_ENCRYPT);
+    OPENSSL_cleanse(&bf_e_key, sizeof(bf_e_key));
+  }
+  out[len] = 0;
+  return out;
+}
+
+unsigned char *
+bf_decrypt_cbc_binary(const char *keydata, unsigned char *in, size_t *len, unsigned char* ivec)
+{
+  unsigned char *out = NULL;
+
+  *len -= *len % CRYPT_BLOCKSIZE;
+  out = (unsigned char *) my_calloc(1, *len + 1);
+
+  if (!keydata || !*keydata) {
+    /* No key, no decryption */
+  } else {
+    BF_set_key(&bf_d_key, strlen(keydata), (const unsigned char*) keydata);
+    BF_cbc_encrypt(in, out, *len, &bf_d_key, ivec, BF_DECRYPT);
+    OPENSSL_cleanse(&bf_d_key, sizeof(bf_d_key));
+  }
+
+  *len = strlen((char*) out);
+  out[*len] = 0;
+  return out;
+}
+#endif

+ 22 - 0
src/crypto/bf_util.h

@@ -0,0 +1,22 @@
+/* bf_util.h
+ *
+ */
+
+#ifndef _BF_UTIL_H
+#define _BF_UTIL_H 1
+
+#include <sys/types.h>
+
+namespace bd {
+  class String;
+}
+
+bd::String egg_bf_encrypt(bd::String in, const bd::String& key);
+bd::String egg_bf_decrypt(bd::String in, const bd::String& key);
+#ifdef not_needed
+unsigned char *bf_encrypt_ecb_binary(const char *, unsigned char *, size_t *);
+unsigned char *bf_decrypt_ecb_binary(const char *, unsigned char *, size_t *);
+unsigned char *bf_encrypt_cbc_binary(const char *, unsigned char *, size_t *, unsigned char *);
+unsigned char *bf_decrypt_cbc_binary(const char *, unsigned char *, size_t *, unsigned char *);
+#endif
+#endif

+ 2 - 0
src/crypto/crypto.h

@@ -2,8 +2,10 @@
 #define _CRYPTO_H
 
 #include "aes_util.h"
+#include "bf_util.h"
 #include <openssl/crypto.h>
 #include <openssl/aes.h>
+#include <openssl/blowfish.h>
 #include <openssl/md5.h>
 #include <openssl/sha.h>
 

+ 14 - 0
src/mod/irc.mod/msgcmds.c

@@ -654,6 +654,19 @@ static int msgc_sha1(Auth *a, char *chname, char *par)
   return BIND_RET_BREAK;
 }
 
+static int msgc_sha256(Auth *a, char *chname, char *par)
+{
+  struct chanset_t *chan = NULL;
+
+  LOGC("SHA256");
+
+  if (chname && chname[0])
+    chan = findchan_by_dname(chname);
+
+  reply(a->nick, chan, "SHA256(%s) = %s\n", par, SHA256(par));
+  return BIND_RET_BREAK;
+}
+
 static int msgc_invite(Auth *a, char *chname, char *par)
 {
   struct chanset_t *chan = NULL;
@@ -713,6 +726,7 @@ static cmd_t C_msgc[] =
   {"md5",		"",	(Function) msgc_md5,		NULL, LEAF|AUTH_MSG|AUTH_CHAN},
   {"op",		"",	(Function) msgc_op,		NULL, LEAF|AUTH_CHAN|AUTH_MSG},
   {"sha1",		"",	(Function) msgc_sha1,		NULL, LEAF|AUTH_CHAN|AUTH_MSG},
+  {"sha256",		"",	(Function) msgc_sha256,		NULL, LEAF|AUTH_CHAN|AUTH_MSG},
   {"voice",		"",	(Function) msgc_voice,		NULL, LEAF|AUTH_CHAN|AUTH_MSG},
   {NULL,		NULL,	NULL,				NULL, 0}
 };