Просмотр исходного кода

Merge branch 'FiSH' into next

* FiSH:
  * Use tokens to be more compatible with other FiSH implementations
  * Prevent keyx on channels
  * Use bd::base64(Encode|Decode) with helper functions to match FiSH base64 encoding
  * Only initialize the prime and generator once
Bryan Drewery 15 лет назад
Родитель
Сommit
a9d0460ca2
7 измененных файлов с 83 добавлено и 124 удалено
  1. 64 111
      src/crypto/dh_util.c
  2. 3 0
      src/crypto/dh_util.h
  3. 1 0
      src/libcrypto.c
  4. 2 1
      src/libcrypto.h
  5. 1 0
      src/main.c
  6. 5 0
      src/mod/server.mod/cmdsserv.c
  7. 7 12
      src/mod/server.mod/servmsg.c

+ 64 - 111
src/crypto/dh_util.c

@@ -9,108 +9,77 @@
 #include <bdlib/src/base64.h>
 #include "dh_util.h"
 
-/*
-   int b64toh(lpBase64String, lpDestinationBuffer);
-   Converts base64 string b to hexnumber d.
-   Returns size of hexnumber in bytes.
-   */
-int b64toh(char *b, char *d){
-  int i,k,l;
-
-  l=strlen(b);
-  if (l<2) return 0;
-  for (i=l-1;i>-1;i--){
-    if (bd::b64_indexes[(unsigned char)(b[i])]==0) l--;
-    else break;
+static BIGNUM* b_prime = NULL;
+static BIGNUM* b_generator = NULL;
+
+void DH1080_init() {
+  // ### new sophie-germain 1080bit prime number ###
+  //const char *prime1080 = "++ECLiPSE+is+proud+to+present+latest+FiSH+release+featuring+even+more+security+for+you+++shouts+go+out+to+TMG+for+helping+to+generate+this+cool+sophie+germain+prime+number++++/C32L";
+  // Base16: FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B
+  // Base10: 12745216229761186769575009943944198619149164746831579719941140425076456621824834322853258804883232842877311723249782818608677050956745409379781245497526069657222703636504651898833151008222772087491045206203033063108075098874712912417029101508315117935752962862335062591404043092163187352352197487303798807791605274487594646923
+  const char *prime1080 = "FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B";
+
+  if (!BN_hex2bn(&b_prime, prime1080)) {
+    sdprintf("BAD PRIME");
+    return;
   }
 
-  if (l<2) return 0;
-  i=0, k=0;
-  while (1) {
-    i++;
-    if (k+1<l) d[i-1]=((bd::b64_indexes[(unsigned char)(b[k])])<<2);
-    else break;
-    k++;
-    if (k<l) d[i-1]|=((bd::b64_indexes[(unsigned char)(b[k])])>>4);
-    else break;
-    i++;
-    if (k+1<l) d[i-1]=((bd::b64_indexes[(unsigned char)(b[k])])<<4);
-    else break;
-    k++;
-    if (k<l) d[i-1]|=((bd::b64_indexes[(unsigned char)(b[k])])>>2);
-    else break;
-    i++;
-    if (k+1<l) d[i-1]=((bd::b64_indexes[(unsigned char)(b[k])])<<6);
-    else break;
-    k++;
-    if (k<l) d[i-1]|=(bd::b64_indexes[(unsigned char)(b[k])]);
-    else break;
-    k++;
+  if (!BN_dec2bn(&b_generator, "2")) {
+    sdprintf("BAD GENERATOR");
+    return;
   }
-  return i-1;
 }
 
-/*
-   int htob64(lpHexNumber, lpDestinationBuffer);
-   Converts hexnumber h (with length l bytes) to base64 string d.
-   Returns length of base64 string.
-   */
-int htob64(char *h, char *d, unsigned int l){
-  unsigned int i,j,k;
-  unsigned char m,t;
-
-  if (!l) return 0;
-  l<<=3;                              // no. bits
-  m=0x80;
-  for (i=0,j=0,k=0,t=0; i<l; i++){
-    if (h[(i>>3)]&m) t|=1;
-    j++;
-    if (!(m>>=1)) m=0x80;
-    if (!(j%6)) {
-      d[k]=bd::b64_charset[t];
-      t&=0;
-      k++;
+/**
+ * @brief Encode a string using FiSH's base64 algorithm (from FiSH/mIRC)
+ * @note Any = padding is removed, and an 'A' is added if no padding was needed
+ * @param bd::String str The string to encode
+ * @returns Encoded string
+ * @note Adapated from FiSH code
+ */
+bd::String fishBase64Encode(const bd::String& str) {
+  bd::String result(bd::base64Encode(str));
+
+  // No padding, add an A on the end (base64-encoded NULL-terminator)
+  if (result.rfind('=') == result.npos) {
+    result += 'A';
+  } else {
+    // Remove padding
+    while (result.rfind('=') != result.npos) {
+      --result;
     }
-    t<<=1;
   }
-  m=5-(j%6);
-  t<<=m;
-  if (m) {
-    d[k]=bd::b64_charset[t];
-    k++;
-  }
-  d[k]&=0;
-  return strlen(d);
+  return result;
 }
 
+/**
+ * @brief Decode a string using FiSH's base64 algorithm (from FiSH/mIRC)
+ * @param bd::String str The string to decode
+ * @returns Decoded data
+ * @note Adapated from FiSH code
+ */
+bd::String fishBase64Decode(const bd::String& str) {
+  bd::String temp(str);
 
-// ### new sophie-germain 1080bit prime number ###
-//static const char *prime1080 = "++ECLiPSE+is+proud+to+present+latest+FiSH+release+featuring+even+more+security+for+you+++shouts+go+out+to+TMG+for+helping+to+generate+this+cool+sophie+germain+prime+number++++/C32L";
-static const char *prime1080 = "FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B";
-
-// Base16: FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B
-// Base10: 12745216229761186769575009943944198619149164746831579719941140425076456621824834322853258804883232842877311723249782818608677050956745409379781245497526069657222703636504651898833151008222772087491045206203033063108075098874712912417029101508315117935752962862335062591404043092163187352352197487303798807791605274487594646923
-
-
-void DH1080_gen(bd::String& privateKey, bd::String& publicKeyB64) {
-  BIGNUM *b_prime = NULL;
-  BIGNUM *b_generator = NULL;
-
-  if (!BN_hex2bn(&b_prime, prime1080)) {
-    sdprintf("BAD PRIME");
-    return;
+  // Remove the 'A' NULL-terminator if present
+  if (temp.length() % 4 == 1 && temp(-1, 1) == 'A') {
+    --temp;
   }
 
-  if (!BN_dec2bn(&b_generator, "2")) {
-    sdprintf("BAD GENERATOR");
-    return;
+  while (temp.length() % 4) {
+    temp += '=';
   }
 
+  return bd::base64Decode(temp);
+}
+
+
+void DH1080_gen(bd::String& privateKey, bd::String& publicKeyB64) {
   DH *dh = NULL;
 
   dh = DH_new();
-  dh->p = b_prime;
-  dh->g = b_generator;
+  dh->p = BN_dup(b_prime);
+  dh->g = BN_dup(b_generator);
 
   if (!DH_generate_key(dh)) {
     DH_free(dh);
@@ -128,46 +97,31 @@ void DH1080_gen(bd::String& privateKey, bd::String& publicKeyB64) {
   BN_bn2bin(dh->pub_key, reinterpret_cast<unsigned char*>(publicKey.mdata()));;
 
   // base64 encode
-  publicKeyB64 = bd::base64Encode(publicKey);
+  publicKeyB64 = fishBase64Encode(publicKey);
 
   DH_free(dh);
 }
 
 bool DH1080_comp(const bd::String privateKey, const bd::String theirPublicKeyB64, bd::String& sharedKey) {
-  BIGNUM *b_prime = NULL, *b_generator = NULL;
-
-  if (!BN_hex2bn(&b_prime, prime1080)) {
-    sharedKey = "Bad prime";
-    return false;
-  }
-
-  if (!BN_dec2bn(&b_generator, "2")) {
-    sharedKey = "Bad generator";
-    return false;
-  }
-
-  size_t len = 0;
-  unsigned char raw_buf[200] = "";
   BIGNUM *b_myPrivkey = NULL, *b_HisPubkey = NULL;
   DH *dh = NULL;
 
 
   dh = DH_new();
-  dh->p = b_prime;
-  dh->g = b_generator;
+  dh->p = BN_dup(b_prime);
+  dh->g = BN_dup(b_generator);
 
   // Setup my private key
   b_myPrivkey = BN_bin2bn(reinterpret_cast<const unsigned char*>(privateKey.data()), privateKey.length(), NULL);
   dh->priv_key = b_myPrivkey;
 
   // Prep their public key
-  len = theirPublicKeyB64.length();
-  bd::b64dec_buf(reinterpret_cast<const unsigned char*>(theirPublicKeyB64.data()), &len, reinterpret_cast<char*>(raw_buf));
-  b_HisPubkey = BN_bin2bn(reinterpret_cast<const unsigned char*>(raw_buf), len, NULL);
+  bd::String theirPublicKey(fishBase64Decode(theirPublicKeyB64));
+  b_HisPubkey = BN_bin2bn(reinterpret_cast<const unsigned char*>(theirPublicKey.data()), theirPublicKey.length(), NULL);
 
   // Compute the Shared key
   char *key = (char *)my_calloc(1, DH_size(dh));
-  len = DH_compute_key((unsigned char *)key, b_HisPubkey, dh);
+  size_t len = DH_compute_key((unsigned char *)key, b_HisPubkey, dh);
   DH_free(dh);
   BN_clear_free(b_HisPubkey);
   if (len == static_cast<size_t>(-1)) {
@@ -181,14 +135,13 @@ bool DH1080_comp(const bd::String privateKey, const bd::String theirPublicKeyB64
   }
 
   SHA256_CTX c;
-  unsigned char SHA256digest[SHA256_DIGEST_LENGTH] = "";
+  bd::String SHA256Digest(static_cast<size_t>(SHA256_DIGEST_LENGTH));
+  SHA256Digest.resize(SHA256_DIGEST_LENGTH);
 
   SHA256_Init(&c);
   SHA256_Update(&c, key, len);
-  SHA256_Final(SHA256digest, &c);
-  memset(raw_buf, 0, sizeof(raw_buf));
-  len = htob64((char *)SHA256digest, (char *)raw_buf, sizeof(SHA256digest));
-  sharedKey = bd::String(reinterpret_cast<char *>(raw_buf), len);
+  SHA256_Final(reinterpret_cast<unsigned char*>(SHA256Digest.mdata()), &c);
+  sharedKey = fishBase64Encode(SHA256Digest);
 
   free(key);
 

+ 3 - 0
src/crypto/dh_util.h

@@ -13,6 +13,9 @@ namespace bd {
 }
 
 // Adapated from znc-fish
+bd::String fishBase64Encode(const bd::String& str);
+bd::String fishBase64Decode(const bd::String& str);
 void DH1080_gen(bd::String& privateKey, bd::String& publicKeyB64);
 bool DH1080_comp(const bd::String privateKey, const bd::String theirPublicKeyB64, bd::String& sharedKey);
+void DH1080_init();
 #endif

+ 1 - 0
src/libcrypto.c

@@ -69,6 +69,7 @@ static int load_symbols(void *handle) {
   DLSYM_GLOBAL(handle, BN_bn2bin);
   DLSYM_GLOBAL(handle, BN_clear_free);
   DLSYM_GLOBAL(handle, BN_dec2bn);
+  DLSYM_GLOBAL(handle, BN_dup);
   DLSYM_GLOBAL(handle, BN_hex2bn);
   DLSYM_GLOBAL(handle, BN_num_bits);
 

+ 2 - 1
src/libcrypto.h

@@ -46,11 +46,12 @@ typedef int (*SHA256_Init_t)(SHA256_CTX*);
 typedef int (*SHA256_Update_t)(SHA256_CTX*, const void*, size_t);
 
 typedef BIGNUM* (*BN_bin2bn_t)(const unsigned char*, int, BIGNUM*);
+typedef BIGNUM* (*BN_dup_t)(const BIGNUM*);
 typedef int (*BN_bn2bin_t)(BIGNUM*, unsigned char*);
-typedef void (*BN_clear_free_t)(BIGNUM*);
 typedef int (*BN_dec2bn_t)(BIGNUM**, const char*);
 typedef int (*BN_hex2bn_t)(BIGNUM**, const char*);
 typedef int (*BN_num_bits_t)(const BIGNUM*);
+typedef void (*BN_clear_free_t)(BIGNUM*);
 
 typedef int (*DH_compute_key_t)(unsigned char*, const BIGNUM*, DH*);
 typedef void (*DH_free_t)(DH*);

+ 1 - 0
src/main.c

@@ -694,6 +694,7 @@ int main(int argc, char **argv)
   if (load_libcrypto()) {
     fatal("Unable to load libcrypto.", 0);
   }
+  DH1080_init();
 
   /* Initialize variables and stuff */
   timer_update_now(&egg_timeval_now);

+ 5 - 0
src/mod/server.mod/cmdsserv.c

@@ -113,6 +113,11 @@ static void cmd_keyx(int idx, char *par) {
     return;
   }
 
+  if (strchr(CHANMETA, par[0])) {
+    dprintf(idx, "Error: Cannot key-exchange with a channel.\n");
+    return;
+  }
+
   if (!server_online) {
     dprintf(idx, "Error: Not online.\n");
     return;

+ 7 - 12
src/mod/server.mod/servmsg.c

@@ -888,19 +888,14 @@ static int gotnotice(char *from, char *msg)
         detect_flood(nick, uhost, from, FLOOD_NOTICE);
         u = get_user_by_host(from);
 
-        if (!strncmp(msg, "DH1080_INIT ", 12)) {
-          bd::String theirPublicKeyB64(msg + 12);
-          // Some FiSH implementations improperly encode their NULL terminator (A) on the end, just trim it off.
-          if (theirPublicKeyB64(-1, 1) == 'A' && theirPublicKeyB64.length() == 181) {
-            theirPublicKeyB64.resize(180, 0);
-          }
+        bd::String smsg(msg);
+        bd::String which = newsplit(smsg);
+
+        if (which == "DH1080_INIT") {
+          bd::String theirPublicKeyB64(newsplit(smsg));
           handle_DH1080_init(nick, uhost, from, u, theirPublicKeyB64);
-        } else if (!strncmp(msg, "DH1080_FINISH ", 14)) {
-          bd::String theirPublicKeyB64(msg + 14);
-          // Some FiSH implementations improperly encode their NULL terminator (A) on the end, just trim it off.
-          if (theirPublicKeyB64(-1, 1) == 'A' && theirPublicKeyB64.length() == 181) {
-            theirPublicKeyB64.resize(180, 0);
-          }
+        } else if (which == "DH1080_FINISH") {
+          bd::String theirPublicKeyB64(newsplit(smsg));
           handle_DH1080_finish(nick, uhost, from, u, theirPublicKeyB64);
         } else {
           putlog(LOG_MSGS, "*", "-%s (%s)- %s", nick, uhost, msg);