Anope IRC Services  Version 2.0
m_sasl_dh-blowfish.cpp
Go to the documentation of this file.
1 /* RequiredLibraries: ssl,crypto */
2 /* RequiredWindowsLibraries: ssleay32,libeay32 */
3 
4 #include "module.h"
5 #include "modules/sasl.h"
6 
7 #include <openssl/bn.h>
8 #include <openssl/dh.h>
9 #include <openssl/blowfish.h>
10 
11 using namespace SASL;
12 
13 class DHBS : public Mechanism
14 {
15  void Err(Session* sess, BIGNUM* key = NULL)
16  {
17  if (key)
18  BN_free(key);
19 
20  sasl->Fail(sess);
21  delete sess;
22  }
23 
24  public:
26  {
27  DH* dh;
28  DHBSSession(Mechanism *m, const Anope::string &u, DH* dh_params) : SASL::Session(m, u)
29  {
30  if (!(dh = DH_new()))
31  return;
32 
33  dh->g = BN_dup(dh_params->g);
34  dh->p = BN_dup(dh_params->p);
35 
36  if (!DH_generate_key(dh))
37  {
38  DH_free(dh);
39  dh = NULL;
40  }
41  }
42 
44  {
45  if (dh)
46  DH_free(dh);
47  }
48  };
49 
50  DH* dh_params;
51  const size_t keysize;
53  {
54  return new DHBSSession(this, uid, dh_params);
55  }
56 
57  DHBS(Module *o) : Mechanism(o, "DH-BLOWFISH"), keysize(256 / 8)
58  {
59  if (!(dh_params = DH_new()))
60  throw ModuleException("DH_new() failed!");
61 
62  if (!DH_generate_parameters_ex(dh_params, keysize * 8, 5, NULL))
63  {
64  DH_free(dh_params);
65  throw ModuleException("Could not generate DH-params");
66  }
67  }
68 
70  {
71  DH_free(dh_params);
72  }
73 
75  {
77 
78  if (!sess->dh)
79  {
80  sasl->SendMessage(sess, "D", "A");
81  delete sess;
82  return;
83  }
84 
85  if (m.type == "S")
86  {
87  // Format: [ss]<p>[ss]<g>[ss]<pub_key>
88  // Where ss is a unsigned short with the size of the key
89  const BIGNUM* dhval[] = { sess->dh->p, sess->dh->g, sess->dh->pub_key };
90 
91  // Find the size of our buffer - initialized at 6 because of string size data
92  size_t size = 6;
93  for (size_t i = 0; i < 3; i++)
94  size += BN_num_bytes(dhval[i]);
95 
96  // Fill in the DH data
97  std::vector<unsigned char> buffer(size);
98  for (size_t i = 0, pos = 0; i < 3; i++)
99  {
100  *reinterpret_cast<uint16_t*>(&buffer[pos]) = htons(BN_num_bytes(dhval[i]));
101  pos += 2;
102  BN_bn2bin(dhval[i], &buffer[pos]);
103  pos += BN_num_bytes(dhval[i]);
104  }
105 
106  Anope::string encoded;
107  Anope::B64Encode(Anope::string(buffer.begin(), buffer.end()), encoded);
108  sasl->SendMessage(sess, "C", encoded);
109  }
110  else if (m.type == "C")
111  {
112  // Make sure we have some data - actual size check is done later
113  if (m.data.length() < 10)
114  return Err(sess);
115 
116  // Format: [ss]<key><username><\0><encrypted>
117 
118  Anope::string decoded;
119  Anope::B64Decode(m.data, decoded);
120 
121  // As we rely on the client giving us a null terminator at the right place,
122  // let's add one extra in case the client tries to crash us
123  const size_t decodedlen = decoded.length();
124  decoded.push_back('\0');
125 
126  // Make sure we have enough data for at least the key, a one letter username, and a block of data
127  if (decodedlen < keysize + 2 + 2 + 8)
128  return Err(sess);
129 
130  const unsigned char* data = reinterpret_cast<const unsigned char*>(decoded.data());
131 
132  // Control the size of the key
133  if (ntohs(*reinterpret_cast<const uint16_t*>(&data[0])) != keysize)
134  return Err(sess);
135 
136  // Convert pubkey from binary
137  size_t pos = 2;
138  BIGNUM* pubkey = BN_bin2bn(&data[pos], keysize, NULL);
139  if (!pubkey)
140  return Err(sess);
141 
142  // Find shared key
143  std::vector<unsigned char> secretkey(DH_size(sess->dh) + 1, 0);
144  if (DH_compute_key(&secretkey[0], pubkey, sess->dh) != static_cast<int>(keysize))
145  return Err(sess, pubkey);
146 
147  // Set decryption key
148  BF_KEY BFKey;
149  BF_set_key(&BFKey, keysize, &secretkey[0]);
150 
151  pos += keysize;
152  const Anope::string username = reinterpret_cast<const char*>(&data[pos]);
153  // Check that the username is valid, and that we have at least one block of data
154  // 2 + 1 + 8 = uint16_t size for keylen, \0 for username, 8 for one block of data
155  if (username.empty() || username.length() + keysize + 2 + 1 + 8 > decodedlen)
156  return Err(sess, pubkey);
157 
158  pos += username.length() + 1;
159  size_t size = decodedlen - pos;
160 
161  // Blowfish data blocks are 64 bits wide - valid format?
162  if (size % 8)
163  return Err(sess, pubkey);
164 
165  std::vector<char> decrypted(size + 1, 0);
166  for (size_t i = 0; i < size; i += 8)
167  BF_ecb_encrypt(&data[pos + i], reinterpret_cast<unsigned char*>(&decrypted[i]), &BFKey, BF_DECRYPT);
168 
169  std::string password = &decrypted[0];
170  if (password.empty())
171  return Err(sess, pubkey);
172 
173  SASL::IdentifyRequest* req = new SASL::IdentifyRequest(this->owner, m.source, username, password);
174  FOREACH_MOD(OnCheckAuthentication, (NULL, req));
175  req->Dispatch();
176 
177  BN_free(pubkey);
178  }
179  }
180 };
181 
182 
183 class ModuleSASLDHBS : public Module
184 {
186 
187  public:
188  ModuleSASLDHBS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR | EXTRA),
189  dhbs(this)
190  {
191  }
192 };
193 
SASL::Session * CreateSession(const Anope::string &uid) anope_override
void push_back(char c)
Definition: anope.h:142
const char * data() const
Definition: anope.h:118
void Dispatch()
Definition: account.cpp:57
void Err(Session *sess, BIGNUM *key=NULL)
ModuleSASLDHBS(const Anope::string &modname, const Anope::string &creator)
const size_t keysize
#define FOREACH_MOD(ename, args)
Definition: modules.h:62
void ProcessMessage(SASL::Session *session, const SASL::Message &m) anope_override
size_type length() const
Definition: anope.h:131
CoreExport void B64Encode(const string &src, string &target)
Definition: base64.cpp:82
static ServiceReference< SASL::Service > sasl("SASL::Service","sasl")
CoreExport void B64Decode(const string &src, string &target)
Definition: base64.cpp:123
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
DHBS(Module *o)
std::basic_string< char, ci_char_traits, std::allocator< char > > string
Definition: hashcomp.h:133
#define MODULE_INIT(x)
Definition: modules.h:45
T anope_dynamic_static_cast(O ptr)
Definition: anope.h:774
static void BF_set_key(const char *key, BF_key expanded, BF_key initial, unsigned char flags)
Definition: enc_bcrypt.cpp:539
Definition: defs.h:55
Definition: modules.h:163
DHBSSession(Mechanism *m, const Anope::string &u, DH *dh_params)