]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/auth_priv.cpp
Initial adding
[ssmd.git] / 3rdparty / snmp++ / src / auth_priv.cpp
1 /*_############################################################################
2   _## 
3   _##  auth_priv.cpp  
4   _##
5   _##  SNMP++v3.2.25
6   _##  -----------------------------------------------
7   _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
8   _##
9   _##  This software is based on SNMP++2.6 from Hewlett Packard:
10   _##  
11   _##    Copyright (c) 1996
12   _##    Hewlett-Packard Company
13   _##  
14   _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15   _##  Permission to use, copy, modify, distribute and/or sell this software 
16   _##  and/or its documentation is hereby granted without fee. User agrees 
17   _##  to display the above copyright notice and this license notice in all 
18   _##  copies of the software and any documentation of the software. User 
19   _##  agrees to assume all liability for the use of the software; 
20   _##  Hewlett-Packard and Jochen Katz make no representations about the 
21   _##  suitability of this software for any purpose. It is provided 
22   _##  "AS-IS" without warranty of any kind, either express or implied. User 
23   _##  hereby grants a royalty-free license to any and all derivatives based
24   _##  upon this software code base. 
25   _##  
26   _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
27   _##  
28   _##########################################################################*/
29 char auth_priv_version[]="@(#) SNMP++ $Id: auth_priv.cpp 1799 2010-08-14 20:11:45Z katz $";
30
31 #include "snmp_pp/config_snmp_pp.h"
32
33 #ifdef _SNMPv3
34
35 #include <string.h>
36 #include <stdlib.h>
37 #include <time.h>
38
39 // Only use DES, AES, SHA1 and MD5 from libtomcrypt if openssl is not used
40 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
41 #include <tomcrypt.h>
42 #endif
43
44 // Use DES, AES, SHA and MD5 from openssl
45 #ifdef _USE_OPENSSL
46 #include <openssl/des.h>
47 #include <openssl/aes.h>
48 #include <openssl/sha.h>
49 #include <openssl/md5.h>
50 #endif
51
52 // Use internal functions for SHA and MD5 and libdes only
53 // if not using libtomcrypt and openssl
54 #if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
55 #include "snmp_pp/sha.h"
56 #ifdef RSAEURO
57 #include <rsaeuro.h>
58 #else
59 #include <des.h>
60 #include "snmp_pp/md5.h"
61 #endif
62 #endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
63
64 // IDEA can only be used with a valid license
65 #ifdef _USE_IDEA
66 #include "snmp_pp/idea.h"
67 #endif
68
69 #include "snmp_pp/auth_priv.h"
70 #include "snmp_pp/v3.h"
71 #include "snmp_pp/snmperrs.h"
72 #include "snmp_pp/address.h"
73 #include "snmp_pp/log.h"
74
75 #ifdef SNMP_PP_NAMESPACE
76 namespace Snmp_pp {
77 #endif
78
79 /*-----------------[ defines for crypto libraries ]------------------*/
80
81 #ifdef _USE_OPENSSL
82
83 /* -- START: Defines for OpenSSL -- */
84 typedef SHA_CTX               SHAHashStateType;
85 #define SHA1_INIT(s)          SHA1_Init(s)
86 #define SHA1_PROCESS(s, p, l) SHA1_Update(s, p, l)
87 #define SHA1_DONE(s, k)       SHA1_Final(k, s)
88
89 typedef MD5_CTX               MD5HashStateType;
90 #define MD5_INIT(s)           MD5_Init(s)
91 #define MD5_PROCESS(s, p, l)  MD5_Update(s, p, l)
92 #define MD5_DONE(s, k)        MD5_Final(k, s)
93
94 typedef des_key_schedule      DESCBCType;
95 #define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
96                  if (des_key_sched((C_Block*)(k), s) < 0) \
97                  { \
98                    debugprintf(0, "Starting DES encryption failed."); \
99                    return SNMPv3_USM_ERROR; \
100                  }
101 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
102                  if (des_key_sched((C_Block*)(k), s) < 0) \
103                  { \
104                    debugprintf(0, "Starting DES decryption failed."); \
105                    return SNMPv3_USM_ERROR; \
106                  }
107
108 #define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
109                         des_ncbc_encrypt(pt, ct, l, \
110                                          s, (C_Block*)(iv), DES_ENCRYPT)
111 #define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
112                         des_ncbc_encrypt(ct, pt, l, \
113                                          s, (C_Block*)(iv), DES_DECRYPT)
114
115 #define DES_EDE3_CBC_ENCRYPT(pt, ct, l, k1, k2, k3, iv) \
116                des_ede3_cbc_encrypt(pt, ct, l, \
117                                     k1, k2, k3, (C_Block*)(iv), DES_ENCRYPT)
118
119 #define DES_EDE3_CBC_DECRYPT(ct, pt, l, k1, k2, k3, iv) \
120                des_ede3_cbc_encrypt(ct, pt, l, \
121                                     k1, k2, k3, (C_Block*)(iv), DES_DECRYPT)
122
123 #define DES_MEMSET(s, c, l)   memset(&(s), c, l)
124
125 /* -- END: Defines for OpenSSL -- */
126
127 #else
128
129 #ifdef _USE_LIBTOMCRYPT
130
131 /* -- START: Defines for LibTomCrypt -- */
132 typedef hash_state            SHAHashStateType;
133 #define SHA1_INIT(s)          sha1_init(s)
134 #define SHA1_PROCESS(s, p, l) sha1_process(s, p, l)
135 #define SHA1_DONE(s, k)       sha1_done(s, k)
136
137 typedef hash_state            MD5HashStateType;
138 #define MD5_INIT(s)           md5_init(s)
139 #define MD5_PROCESS(s, p, l)  md5_process(s, p, l)
140 #define MD5_DONE(s, k)        md5_done(s, k)
141
142 typedef symmetric_CBC         DESCBCType;
143 #define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
144                  if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
145                  { \
146                    debugprintf(0, "Starting DES encryption failed."); \
147                    return SNMPv3_USM_ERROR; \
148                  }
149
150 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
151                  if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
152                  { \
153                    debugprintf(0, "Starting DES decryption failed."); \
154                    return SNMPv3_USM_ERROR; \
155                  }
156
157 #define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
158                  if (cbc_encrypt(pt, ct, l, &(s)) != CRYPT_OK) \
159                  { \
160                    debugprintf(0, "Error during DES encryption."); \
161                    return SNMPv3_USM_ERROR; \
162                  }
163 #define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
164                  if (cbc_decrypt(ct, pt, l, &(s)) != CRYPT_OK) \
165                  { \
166                    debugprintf(0, "Error during DES decryption."); \
167                    return SNMPv3_USM_ERROR; \
168                  }
169 #define DES_MEMSET(s, c, l)   memset(&(s), c, l)
170 /* -- END: Defines for LibTomCrypt -- */
171
172 #else // _USE_LIBTOMCRYPT  --> libdes
173
174 /* -- START: Defines for libdes -- */
175
176 typedef SHA_CTX               SHAHashStateType;
177 #define SHA1_INIT(s)          SHAInit(s)
178 #define SHA1_PROCESS(s, p, l) SHAUpdate(s, p, l)
179 #define SHA1_DONE(s, k)       SHAFinal(k, s)
180
181 typedef MD5_CTX               MD5HashStateType;
182 #define MD5_INIT(s)           MD5Init(s)
183 #define MD5_PROCESS(s, p, l)  MD5Update(s, p, l)
184 #define MD5_DONE(s, k)        MD5Final(k, s)
185
186 #define DES_EDE3_CBC_ENCRYPT(pt, ct, l, k1, k2, k3, iv) \
187                des_ede3_cbc_encrypt((C_Block*)(pt), (C_Block*)(ct), l, \
188                                     k1, k2, k3, (C_Block*)(iv), DES_ENCRYPT)
189
190 #define DES_EDE3_CBC_DECRYPT(ct, pt, l, k1, k2, k3, iv) \
191                des_ede3_cbc_encrypt((C_Block*)(ct), (C_Block*)(pt), l, \
192                                     k1, k2, k3, (C_Block*)(iv), DES_DECRYPT)
193
194 #ifdef RSAEURO
195
196 #undef  MD5_PROCESS
197 #define MD5_PROCESS(s, p, l)  MD5Update(s, (unsigned char*)(p), l)
198
199 typedef DES_CBC_CTX           DESCBCType;
200 #define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
201                               DES_CBCInit(&(s), (unsigned char*)(k), iv, 1)
202 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
203                               DES_CBCInit(&(s),(unsigned char*)(k), iv, 0)
204 #define DES_CBC_ENCRYPT(pt, ct, s, iv, l) DES_CBCUpdate(&(s), pt, ct, l)
205 #define DES_CBC_DECRYPT(ct, pt, s, iv, l) DES_CBCUpdate(&(s), (unsigned char*)(ct), pt, l)
206 #define DES_MEMSET(s, c, l)   R_memset((POINTER)&(s), c, l)
207
208 #else // RSAEURO
209
210 typedef des_key_schedule      DESCBCType;
211 #define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
212                  if (des_key_sched((C_Block*)(k), s) < 0) \
213                  { \
214                    debugprintf(0, "Starting DES encryption failed."); \
215                    return SNMPv3_USM_ERROR; \
216                  }
217 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
218                  if (des_key_sched((C_Block*)(k), s) < 0) \
219                  { \
220                    debugprintf(0, "Starting DES decryption failed."); \
221                    return SNMPv3_USM_ERROR; \
222                  }
223
224 #define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
225                         des_ncbc_encrypt((C_Block*)(pt), (C_Block*)(ct), l, \
226                                          s, (C_Block*)(iv), DES_ENCRYPT)
227 #define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
228                         des_ncbc_encrypt((C_Block*)(ct), (C_Block*)(pt), l, \
229                                          s, (C_Block*)(iv), DES_DECRYPT)
230 #define DES_MEMSET(s, c, l)   memset(&(s), c, l)
231
232 /* -- END: Defines for libdes -- */
233
234 #endif // RSAEURO
235
236 #endif // _USE_LIBTOMCRYPT
237
238 #endif // _USE_OPENSSL
239
240 AuthPriv::AuthPriv(int &construct_state)
241 {
242   auth = new AuthPtr[10];
243   priv = new PrivPtr[10];
244
245   if (auth)
246     auth_size = 10;
247   else
248   {
249     auth_size = 0;
250
251     LOG_BEGIN(ERROR_LOG | 1);
252     LOG("AuthPriv: Error allocating array for authentication.");
253     LOG_END;
254   }
255
256   if (priv)
257     priv_size = 10;
258   else
259   {
260     priv_size = 0;
261
262     LOG_BEGIN(ERROR_LOG | 1);
263     LOG("AuthPriv: Error allocating array for privacy.");
264     LOG_END;
265   }
266
267   for (int i = 0; i < auth_size; i++)
268     auth[i] = 0;
269
270   for (int j = 0; j < priv_size; j++)
271     priv[j] = 0;
272
273   /* Check size of salt, has to be 64 bits */
274   if (sizeof(salt) != 8)
275   {
276     LOG_BEGIN(ERROR_LOG | 1);
277     LOG("AuthPriv: *BUG* sizeof(pp_uint64) is not 8 bytes. snmp++ has to be patched for this system.");
278     LOG_END;
279
280     construct_state = SNMPv3_USM_ERROR;
281     return;
282   }
283
284   /* Initialize salt. srand() has been already done in Snmp::init() */
285   unsigned int *rnd = (unsigned int*)(void *)&salt;
286   for (size_t i = 0; i < sizeof(salt); i += sizeof(unsigned int), rnd++)
287   {
288     *rnd = rand() << 1;
289     if (rand() < (RAND_MAX / 2))
290       *rnd += 1;
291   }
292
293   construct_state = SNMPv3_USM_OK;
294
295 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
296   /* register needed hashes and ciphers in libtomcrypt */
297   if (register_cipher(&rijndael_desc) < 0)
298   {
299     LOG_BEGIN(ERROR_LOG | 1);
300     LOG("AuthPriv: Error registering Rijndael.");
301     LOG_END;
302
303     construct_state = SNMPv3_USM_ERROR;
304   }
305
306   if (register_cipher(&des_desc) < 0)
307   {
308     LOG_BEGIN(ERROR_LOG | 1);
309     LOG("AuthPriv: Error registering DES.");
310     LOG_END;
311
312     construct_state = SNMPv3_USM_ERROR;
313   }
314
315   if (register_cipher(&des3_desc) < 0)
316   {
317     LOG_BEGIN(ERROR_LOG | 1);
318     LOG("AuthPriv: Error registering 3DES.");
319     LOG_END;
320
321     construct_state = SNMPv3_USM_ERROR;
322   }
323
324   if (register_hash(&sha1_desc) < 0)
325   {
326     LOG_BEGIN(ERROR_LOG | 1);
327     LOG("AuthPriv: Error registering SHA1.");
328     LOG_END;
329
330     construct_state = SNMPv3_USM_ERROR;
331   }
332
333   if (register_hash(&md5_desc) < 0)
334   {
335     LOG_BEGIN(ERROR_LOG | 1);
336     LOG("AuthPriv: Error registering MD5.");
337     LOG_END;
338
339     construct_state = SNMPv3_USM_ERROR;
340   }
341 #endif // defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
342 }
343
344 AuthPriv::~AuthPriv()
345 {
346   for (int i = 0; i < auth_size; i++)
347     if (auth[i])
348     {
349       delete auth[i];
350       auth[i] = 0;
351     }
352
353   for (int j = 0; j < priv_size; j++)
354     if (priv[j])
355     {
356       delete priv[j];
357       priv[j] = 0;
358     }
359
360   delete [] auth;
361   delete [] priv;
362 }
363
364 int AuthPriv::add_auth(Auth *new_auth)
365 {
366   if (!new_auth)
367   {
368     return SNMP_CLASS_ERROR;
369   }
370
371   int id = new_auth->get_id();
372
373   if (id < 0)
374   {
375     return SNMP_CLASS_ERROR;
376   }
377
378   if (id >= auth_size)
379   {
380     AuthPtr *new_array = new AuthPtr[id + 5];
381     if (!new_array)
382     {
383       LOG_BEGIN(ERROR_LOG | 1);
384       LOG("AuthPriv: Could not allocate new auth array.");
385       LOG_END;
386
387       return SNMP_CLASS_ERROR;
388     }
389     for (int i=0 ; i<auth_size; i++)
390       new_array[i] = auth[i];
391
392     for (int j=auth_size ; j<id + 5; j++)
393       new_array[j] = 0;
394
395     AuthPtr *victim = auth;
396     auth = new_array;
397     delete [] victim;
398     auth_size = id + 5;
399   }
400
401   new_auth->set_salt(&salt);
402
403   if (auth[id])
404   {
405     LOG_BEGIN(WARNING_LOG | 4);
406     LOG("AuthPriv: deleting old auth object before adding new one (id)");
407     LOG(id);
408     LOG_END;
409
410     delete auth[id];
411   }
412
413   auth[id] = new_auth;
414
415   LOG_BEGIN(INFO_LOG | 6);
416   LOG("AuthPriv: Added auth protocol (id)");
417   LOG(id);
418   LOG_END;
419
420   return SNMP_CLASS_SUCCESS;
421 }
422
423 int AuthPriv::del_auth(const int auth_id)
424 {
425   if ((auth_id < 0) || (auth_id >= auth_size) || (auth[auth_id] == 0))
426   {
427     LOG_BEGIN(WARNING_LOG | 4);
428     LOG("AuthPriv: Request to delete non existing auth protocol (id)");
429     LOG(auth_id);
430     LOG_END;
431
432     return SNMP_CLASS_ERROR;
433   }
434
435   delete auth[auth_id];
436   auth[auth_id] = 0;
437
438   LOG_BEGIN(INFO_LOG | 6);
439   LOG("AuthPriv: Removed auth protocol (id)");
440   LOG(auth_id);
441   LOG_END;
442
443   return SNMP_CLASS_SUCCESS;
444 }
445
446
447 int AuthPriv::add_priv(Priv *new_priv)
448 {
449   if (!new_priv)
450   {
451     return SNMP_CLASS_ERROR;
452   }
453
454   int id = new_priv->get_id();
455
456   if (id < 0)
457   {
458     return SNMP_CLASS_ERROR;
459   }
460
461   if (id >= priv_size)
462   {
463     PrivPtr *new_array = new PrivPtr[id + 5];
464     if (!new_array)
465     {
466       LOG_BEGIN(ERROR_LOG | 1);
467       LOG("AuthPriv: Could not allocate new priv array.");
468       LOG_END;
469
470       return SNMP_CLASS_ERROR;
471     }
472     for (int i=0 ; i<priv_size; i++)
473       new_array[i] = priv[i];
474
475     for (int j=priv_size ; j<id + 5; j++)
476       new_array[j] = 0;
477
478     PrivPtr *victim = priv;
479     priv = new_array;
480     delete [] victim;
481     priv_size = id + 5;
482   }
483
484   new_priv->set_salt(&salt);
485
486   if (priv[id])
487   {
488     LOG_BEGIN(WARNING_LOG | 4);
489     LOG("AuthPriv: deleting old priv object before adding new one (id)");
490     LOG(id);
491     LOG_END;
492
493     delete priv[id];
494   }
495
496   priv[id] = new_priv;
497
498   LOG_BEGIN(INFO_LOG | 6);
499   LOG("AuthPriv: Added priv protocol (id)");
500   LOG(id);
501   LOG_END;
502
503   return SNMP_CLASS_SUCCESS;
504 }
505
506 int AuthPriv::del_priv(const int priv_id)
507 {
508   if ((priv_id < 0) || (priv_id >= priv_size) || (priv[priv_id] == 0))
509   {
510     LOG_BEGIN(WARNING_LOG | 4);
511     LOG("AuthPriv: Request to delete non existing priv protocol (id)");
512     LOG(priv_id);
513     LOG_END;
514
515     return SNMP_CLASS_ERROR;
516   }
517
518   delete priv[priv_id];
519   priv[priv_id] = 0;
520
521   LOG_BEGIN(INFO_LOG | 6);
522   LOG("AuthPriv: Removed priv protocol (id)");
523   LOG(priv_id);
524   LOG_END;
525
526   return SNMP_CLASS_SUCCESS;
527 }
528
529 Auth *AuthPriv::get_auth(const int auth_prot)
530 {
531   if ((auth_prot >= 0) && (auth_prot < auth_size))
532     return auth[auth_prot];
533   return 0;
534 }
535
536 Priv *AuthPriv::get_priv(const int priv_prot)
537 {
538   if ((priv_prot >= 0) && (priv_prot < priv_size))
539     return priv[priv_prot];
540   return 0;
541 }
542
543 // Get the unique id for the given auth protocol.
544 int AuthPriv::get_auth_id(const char *string_id) const
545 {
546   for (int i = 0; i < auth_size; ++i)
547     if ((auth[i]) && (strcmp(string_id, auth[i]->get_id_string()) == 0))
548       return i;
549   return -1;
550 }
551
552 // Get the unique id for the given priv protocol.
553 int AuthPriv::get_priv_id(const char *string_id) const
554 {
555   for (int i = 0; i < priv_size; ++i)
556     if ((priv[i]) && (strcmp(string_id, priv[i]->get_id_string()) == 0))
557       return i;
558   return -1;
559 }
560
561 int AuthPriv::get_keychange_value(const int       auth_prot,
562                                   const OctetStr& old_key,
563                                   const OctetStr& new_key,
564                                   OctetStr&       keychange_value)
565 {
566
567   // uses fixed key length determined from oldkey!
568   // works with SHA and MD5
569   // modifications needed to support variable length keys
570   // algorithm according to USM-document textual convention KeyChange
571
572   keychange_value.clear();
573   int key_len = old_key.len();
574
575   Auth *a = get_auth(auth_prot);
576
577   if (!a)
578     return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
579
580   // compute random value
581   OctetStr random = "";
582
583   for (int i=0; i<key_len; i++) {
584 #ifdef _TEST
585     // do not use random values for testing
586     random += OctetStr((unsigned char*)"\0",1);
587 #else
588     char tmprand = rand();
589     random += tmprand;
590 #endif
591   }
592
593 #ifdef __DEBUG
594   debugprintf(21, "Values for keyChange:");
595   debughexcprintf(21, "old_key", old_key.data(), old_key.len());
596   debughexcprintf(21, "new_key", new_key.data(), new_key.len());
597   debughexcprintf(21, "random value", random.data(), random.len());
598 #endif
599
600   int iterations = (key_len - 1) / a->get_hash_len();
601   OctetStr tmp = old_key;
602   OctetStr delta;
603
604   for (int k = 0; k < iterations; k++)
605   {
606       unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
607       memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
608       tmp += random;
609       debughexcprintf(21, "loop tmp1", tmp.data(), tmp.len());
610       a->hash(tmp.data(), tmp.len(), digest);
611       tmp.set_data(digest, a->get_hash_len());
612       debughexcprintf(21, "loop tmp2", tmp.data(), tmp.len());
613       delta.set_len(delta.len() + a->get_hash_len());
614       for (int kk=0; kk < a->get_hash_len(); kk++)
615           delta[k * a->get_hash_len() + kk]
616               = tmp[kk] ^ new_key[k * a->get_hash_len() + kk];
617       debughexcprintf(21, "loop delta", delta.data(), delta.len());
618   }
619
620   unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
621   memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
622   tmp += random;
623   debughexcprintf(21, " tmp1", tmp.data(), tmp.len());
624   a->hash(tmp.data(), tmp.len(), digest);
625   tmp.set_data(digest, key_len - delta.len());
626   debughexcprintf(21, " tmp2", tmp.data(), tmp.len());
627   for (unsigned int j = 0; j < tmp.len(); j++)
628       tmp[j] = tmp[j] ^ new_key[iterations * a->get_hash_len() + j];
629   debughexcprintf(21, " tmp3", tmp.data(), tmp.len());
630
631   keychange_value = random;
632   keychange_value += delta;
633   keychange_value += tmp;
634
635 #ifdef __DEBUG
636   debughexcprintf(21, "keychange_value",
637                   keychange_value.data(), keychange_value.len());
638 #endif
639
640   return SNMPv3_USM_OK;
641 }
642
643 int AuthPriv::password_to_key_auth(const int            auth_prot,
644                                    const unsigned char *password,
645                                    const unsigned int   password_len,
646                                    const unsigned char *engine_id,
647                                    const unsigned int   engine_id_len,
648                                    unsigned char *key,
649                                    unsigned int  *key_len)
650 {
651   if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
652   {
653     *key_len = 0;
654     return SNMPv3_USM_OK;
655   }
656
657   if (!password || (password_len == 0))
658   {
659     LOG_BEGIN(WARNING_LOG | 2);
660     LOG("AuthPriv: Password to key auth needs a non empty password");
661     LOG_END;
662
663     return SNMPv3_USM_ERROR;
664   }
665
666   Auth *a = get_auth(auth_prot);
667
668   if (!a)
669     return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
670
671   int res = a->password_to_key(password, password_len,
672                                engine_id, engine_id_len,
673                                key, key_len);
674
675   return res;
676 }
677
678
679 int AuthPriv::password_to_key_priv(const int            auth_prot,
680                                    const int            priv_prot,
681                                    const unsigned char *password,
682                                    const unsigned int   password_len,
683                                    const unsigned char *engine_id,
684                                    const unsigned int   engine_id_len,
685                                    unsigned char *key,
686                                    unsigned int  *key_len)
687 {
688   /* check for priv protocol */
689   if (priv_prot == SNMP_PRIVPROTOCOL_NONE)
690   {
691     *key_len = 0;
692     return SNMPv3_USM_OK;
693   }
694
695   if (!password || (password_len == 0))
696   {
697     LOG_BEGIN(WARNING_LOG | 2);
698     LOG("AuthPriv: Password to key priv needs a non empty password");
699     LOG_END;
700
701     return SNMPv3_USM_ERROR;
702   }
703
704   Priv *p = get_priv(priv_prot);
705   Auth *a = get_auth(auth_prot);
706
707   if (!p)  return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
708   if (!a)  return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
709
710   unsigned int max_key_len = *key_len; /* save length of buffer! */
711   unsigned int min_key_len = p->get_min_key_len();
712
713   /* check if buffer for key is long enough */
714   if (min_key_len > max_key_len)
715     return SNMPv3_USM_ERROR; // TODO: better error code!
716
717   int res = password_to_key_auth(auth_prot,
718                                  password, password_len,
719                                  engine_id, engine_id_len,
720                                  key, key_len);
721   if (res != SNMPv3_USM_OK)
722     return res;
723
724   /* We have a too short key: Call priv protocoll to extend it */
725   if (*key_len < min_key_len)
726   {
727     res = p->extend_short_key(password, password_len,
728                               engine_id, engine_id_len,
729                               key, key_len, max_key_len, a);
730     if (res != SNMPv3_USM_OK)
731       return res;
732   }
733
734   /* make sure key length is valid */
735   p->fix_key_len(*key_len);
736
737   return SNMPv3_USM_OK;
738 }
739
740
741
742
743 int AuthPriv::encrypt_msg(const int            priv_prot,
744                           const unsigned char *key,
745                           const unsigned int   key_len,
746                           const unsigned char *buffer,
747                           const unsigned int   buffer_len,
748                           unsigned char       *out_buffer,
749                           unsigned int        *out_buffer_len,
750                           unsigned char       *privacy_params,
751                           unsigned int        *privacy_params_len,
752                           const unsigned long  engine_boots,
753                           const unsigned long  engine_time)
754 {
755   /* check for priv protocol */
756   Priv *p = get_priv(priv_prot);
757
758   if (!p)
759     return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
760
761   return p->encrypt(key, key_len, buffer, buffer_len,
762                     out_buffer, out_buffer_len,
763                     privacy_params, privacy_params_len,
764                     engine_boots, engine_time);
765 }
766
767 int AuthPriv::decrypt_msg(const int            priv_prot,
768                           const unsigned char *key,
769                           const unsigned int   key_len,
770                           const unsigned char *buffer,
771                           const unsigned int   buffer_len,
772                           unsigned char       *out_buffer,
773                           unsigned int        *out_buffer_len,
774                           const unsigned char *privacy_params,
775                           const unsigned int   privacy_params_len,
776                           const unsigned long  engine_boots,
777                           const unsigned long  engine_time)
778 {
779   /* check for priv protocol */
780   Priv *p = get_priv(priv_prot);
781
782   if (!p)
783     return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
784
785   return p->decrypt(key, key_len, buffer, buffer_len,
786                     out_buffer, out_buffer_len,
787                     privacy_params, privacy_params_len,
788                     engine_boots, engine_time);
789 }
790
791
792 int AuthPriv::add_default_modules()
793 {
794   int ret = SNMP_CLASS_SUCCESS;
795
796   if (add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
797   {
798     LOG_BEGIN(ERROR_LOG | 1);
799     LOG("AuthPriv: Could not add default protocol AuthSHA.");
800     LOG_END;
801
802     ret = SNMP_CLASS_ERROR;
803   }
804
805   if (add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
806   {
807     LOG_BEGIN(ERROR_LOG | 1);
808     LOG("AuthPriv: Could not add default protocol AuthMD5.");
809     LOG_END;
810
811     ret = SNMP_CLASS_ERROR;
812   }
813
814   if (add_priv(new PrivDES()) != SNMP_ERROR_SUCCESS)
815   {
816     LOG_BEGIN(ERROR_LOG | 1);
817     LOG("AuthPriv: Could not add default protocol PrivDES.");
818     LOG_END;
819
820     ret = SNMP_CLASS_ERROR;
821   }
822
823 #ifdef _USE_IDEA
824   if (add_priv(new PrivIDEA()) != SNMP_ERROR_SUCCESS)
825   {
826     LOG_BEGIN(ERROR_LOG | 1);
827     LOG("AuthPriv: Could not add default protocol PrivIDEA.");
828     LOG_END;
829
830     ret = SNMP_CLASS_ERROR;
831   }
832 #endif
833
834 #if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
835   if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES128)) != SNMP_ERROR_SUCCESS)
836   {
837     LOG_BEGIN(ERROR_LOG | 1);
838     LOG("AuthPriv: Could not add default protocol PrivAES 128.");
839     LOG_END;
840
841     ret = SNMP_CLASS_ERROR;
842   }
843
844   if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES192)) != SNMP_ERROR_SUCCESS)
845   {
846     LOG_BEGIN(ERROR_LOG | 1);
847     LOG("AuthPriv: Could not add default protocol PrivAES 192.");
848     LOG_END;
849
850     ret = SNMP_CLASS_ERROR;
851   }
852
853   if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES256)) != SNMP_ERROR_SUCCESS)
854   {
855     LOG_BEGIN(ERROR_LOG | 1);
856     LOG("AuthPriv: Could not add default protocol PrivAES 256.");
857     LOG_END;
858
859     ret = SNMP_CLASS_ERROR;
860   }
861 #endif
862
863 #ifdef _USE_3DES_EDE
864   if (add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
865   {
866     LOG_BEGIN(ERROR_LOG | 1);
867     LOG("AuthPriv: Could not add default protocol Priv3DES_EDE.");
868     LOG_END;
869
870     ret = SNMP_CLASS_ERROR;
871   }
872 #endif
873
874
875   if (ret == SNMP_CLASS_SUCCESS)
876   {
877     LOG_BEGIN(INFO_LOG | 3);
878     LOG("AuthPriv: Added default Auth and Priv protocols.");
879     LOG_END;
880   }
881
882   return ret;
883 }
884
885 int AuthPriv::get_auth_params_len(const int auth_prot)
886 {
887   Auth *a = get_auth(auth_prot);
888
889   if (!a)
890     return 0;
891
892   return a->get_auth_params_len();
893 }
894
895 int AuthPriv::get_priv_params_len(const int priv_prot)
896 {
897   Priv *p = get_priv(priv_prot);
898
899   if (!p)
900     return 0;
901
902   return p->get_priv_params_len();
903 }
904
905 int AuthPriv::auth_out_msg(const int            auth_prot,
906                            const unsigned char *key,
907                            unsigned char       *msg,
908                            const int            msg_len,
909                            unsigned char       *auth_par_ptr)
910 {
911   if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
912     return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
913
914   Auth *a = get_auth(auth_prot);
915
916   if (!a)
917     return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
918
919   return a->auth_out_msg(key, msg, msg_len, auth_par_ptr);
920 }
921
922 int AuthPriv::auth_inc_msg(const int            auth_prot,
923                            const unsigned char *key,
924                            unsigned char       *msg,
925                            const int            msg_len,
926                            unsigned char       *auth_par_ptr,
927                            const int            auth_par_len)
928 {
929   if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
930     return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
931
932   Auth *a = get_auth(auth_prot);
933
934   if (!a)
935     return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
936
937   /* @todo check if auth par is inside msg
938   if ((auth_par_ptr < msg) ||
939       (msg + msg_len < auth_par_ptr + auth_par_len))
940   {
941     LOG_BEGIN(WARNING_LOG | 1);
942     LOG("AuthPriv: Authentication data is not within message (msg start) (len) (auth start) (len)");
943     LOG(msg);
944     LOG(msg_len);
945     LOG(auth_par_ptr);
946     LOG(auth_par_len);
947     LOG_END;
948
949     return SNMPv3_USM_ERROR;
950   }
951   */
952
953   return a->auth_inc_msg(key, msg, msg_len, auth_par_ptr, auth_par_len);
954 }
955
956 /* ========================================================== */
957
958 /* ----------------------- AuthSHA ---------------------------------------*/
959
960 int AuthSHA::password_to_key(const unsigned char *password,
961                              const unsigned int   password_len,
962                              const unsigned char *engine_id,
963                              const unsigned int   engine_id_len,
964                              unsigned char *key,
965                              unsigned int *key_len)
966 {
967   *key_len = 20; /* All SHA keys have 20 bytes length */
968
969 #ifdef __DEBUG
970   debugprintf(5,"password_to_key SHA: password: (%s).",
971               OctetStr(password, password_len).get_printable());
972   debugprintf(5,"password_to_key SHA: engine_id: (%s).",
973               OctetStr(engine_id, engine_id_len).get_printable());
974 #endif
975
976   SHAHashStateType sha_hash_state;
977   unsigned char *cp, password_buf[72];
978   unsigned long  password_index = 0;
979   unsigned long  count = 0, i;
980
981   SHA1_INIT(&sha_hash_state);   /* initialize SHA */
982
983   /**********************************************/
984   /* Use while loop until we've done 1 Megabyte */
985   /**********************************************/
986   while (count < 1048576) {
987     cp = password_buf;
988     for (i = 0; i < 64; i++) {
989       /*************************************************/
990       /* Take the next octet of the password, wrapping */
991       /* to the beginning of the password as necessary.*/
992       /*************************************************/
993       *cp++ = password[password_index++ % password_len];
994     }
995
996     SHA1_PROCESS(&sha_hash_state, password_buf, 64);
997     count += 64;
998   }
999
1000   SHA1_DONE(&sha_hash_state, key);          /* tell SHA we're done */
1001
1002 #ifdef __DEBUG
1003   debughexcprintf(21, "key", key, *key_len);
1004 #endif
1005
1006   /*****************************************************/
1007   /* Now localize the key with the engine_id and pass  */
1008   /* through SHA to produce final key                  */
1009   /* May want to ensure that engine_id_len <= 32,      */
1010   /* otherwise need to use a buffer larger than 72     */
1011   /*****************************************************/
1012   memcpy(password_buf,                            key,       *key_len);
1013   memcpy(password_buf + *key_len,                 engine_id, engine_id_len);
1014   memcpy(password_buf + *key_len + engine_id_len, key,       *key_len);
1015
1016   SHA1_INIT(&sha_hash_state);
1017   SHA1_PROCESS(&sha_hash_state, password_buf, (2 * *key_len) + engine_id_len);
1018   SHA1_DONE(&sha_hash_state, key);
1019
1020 #ifdef __DEBUG
1021   debughexcprintf(21, "localized key", key, *key_len);
1022 #endif
1023
1024   return SNMPv3_USM_OK;
1025 }
1026
1027 int AuthSHA::hash(const unsigned char *data,
1028                   const unsigned int   data_len,
1029                   unsigned char       *digest) const
1030 {
1031   SHAHashStateType sha_hash_state;
1032
1033   SHA1_INIT(&sha_hash_state);
1034   SHA1_PROCESS(&sha_hash_state, data, data_len);
1035   SHA1_DONE(&sha_hash_state, digest);
1036
1037   return SNMPv3_USM_OK;
1038 }
1039
1040 int AuthSHA::auth_out_msg(const unsigned char *key,
1041                           unsigned char *msg,
1042                           const int msg_len,
1043                           unsigned char *auth_par_ptr)
1044 {
1045   SHAHashStateType sha_hash_state;
1046   int           key_len = 20; /* We use only 20 Byte Key! */
1047   unsigned char digest[20];
1048   unsigned char k_ipad[65];   /* inner padding - key XORd with ipad */
1049   unsigned char k_opad[65];   /* outer padding - key XORd with opad */
1050
1051   memset((char*)(auth_par_ptr), 0, 12);
1052
1053 #ifdef __DEBUG
1054   debughexcprintf(21, "key", key, 16);
1055 #endif
1056
1057   /*
1058    * the HMAC_SHA transform looks like:
1059    *
1060    * SHA(K XOR opad, SHA(K XOR ipad, msg))
1061    *
1062    * where K is an n byte key
1063    * ipad is the byte 0x36 repeated 64 times
1064    * opad is the byte 0x5c repeated 64 times
1065    * and text is the data being protected
1066    */
1067
1068   /* start out by storing ipads and opads in pads */
1069   memset( (char*)k_ipad, 0x36, sizeof k_ipad);
1070   memset( (char*)k_opad, 0x5c, sizeof k_opad);
1071
1072   /* XOR pads with key */
1073   for (int i=0; i < key_len; ++i) {
1074     k_ipad[i] ^= key[i];
1075     k_opad[i] ^= key[i];
1076   }
1077
1078   /* perform inner SHA */
1079   SHA1_INIT(&sha_hash_state);           /* init sha_hash_state for 1st pass */
1080   SHA1_PROCESS(&sha_hash_state, k_ipad, 64);   /* start with inner pad      */
1081   SHA1_PROCESS(&sha_hash_state, msg, msg_len); /* then text of datagram     */
1082   SHA1_DONE(&sha_hash_state, digest);          /* finish up 1st pass        */
1083   /* perform outer SHA */
1084   SHA1_INIT(&sha_hash_state);           /* init sha_hash_state for 2nd pass */
1085   SHA1_PROCESS(&sha_hash_state, k_opad, 64);   /* start with outer pad      */
1086   SHA1_PROCESS(&sha_hash_state, digest, 20);   /* then results of 1st hash  */
1087   SHA1_DONE(&sha_hash_state, digest);          /* finish up 2nd pass        */
1088
1089 #ifdef __DEBUG
1090   debughexcprintf(21,"digest", digest, 160 / 8);
1091 #endif
1092
1093   memcpy(auth_par_ptr, digest, 12);
1094
1095   return SNMPv3_USM_OK;
1096 }
1097
1098
1099 int AuthSHA::auth_inc_msg(const unsigned char *key,
1100                           unsigned char *msg,
1101                           const int msg_len,
1102                           unsigned char *auth_par_ptr,
1103                           const int      auth_par_len)
1104 {
1105   unsigned char receivedDigest[20];
1106
1107   if (auth_par_len != 12)
1108   {
1109     debugprintf(4, "SHA illegal digest length (%d), authentication FAILED.",
1110                 auth_par_len);
1111     return SNMPv3_USM_AUTHENTICATION_FAILURE;
1112   }
1113
1114 #ifdef __DEBUG
1115   debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
1116   debughexcprintf(21, "key", key, 20);
1117 #endif
1118
1119   /* Save received digest */
1120   memcpy(receivedDigest, auth_par_ptr, 12);
1121
1122   if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
1123   {
1124     /* copy digest back into message and return error */
1125     memcpy(auth_par_ptr, receivedDigest, 12);
1126     debugprintf(4, "SHA authentication FAILED (1).");
1127     return SNMPv3_USM_AUTHENTICATION_FAILURE;
1128   }
1129
1130   /* compare digest to received digest */
1131   for (int i=0; i < 12 ; ++i)
1132   {
1133     if (auth_par_ptr[i] != receivedDigest[i])
1134     {
1135       /* copy digest back into message and return error */
1136       memcpy(auth_par_ptr, receivedDigest, 12);
1137       debugprintf(4, "SHA authentication FAILED.");
1138       return SNMPv3_USM_AUTHENTICATION_FAILURE;
1139     }
1140   }
1141   debugprintf(4, "SHA authentication OK.");
1142   return SNMPv3_USM_OK;
1143 }
1144
1145
1146 /* ----------------------- AuthMD5 ---------------------------------------*/
1147
1148 int AuthMD5::password_to_key(const unsigned char *password,
1149                              const unsigned int   password_len,
1150                              const unsigned char *engine_id,
1151                              const unsigned int   engine_id_len,
1152                              unsigned char *key,
1153                              unsigned int *key_len)
1154 {
1155   *key_len = 16; /* All MD5 keys have 16 bytes length */
1156
1157 #ifdef __DEBUG
1158   debugprintf(5,"password: %s.",
1159               OctetStr(password, password_len).get_printable());
1160   debugprintf(5,"engineID: %s.",
1161               OctetStr(engine_id, engine_id_len).get_printable());
1162 #endif
1163
1164   MD5HashStateType md5_hash_state;
1165   unsigned char  *cp, password_buf[65];
1166   unsigned long   password_index = 0;
1167   unsigned long   count = 0, i;
1168
1169   MD5_INIT(&md5_hash_state);   /* initialize MD5 */
1170
1171   /**********************************************/
1172   /* Use while loop until we've done 1 Megabyte */
1173   /**********************************************/
1174   while (count < 1048576) {
1175     cp = password_buf;
1176     for (i = 0; i < 64; i++) {
1177       /*************************************************/
1178       /* Take the next octet of the password, wrapping */
1179       /* to the beginning of the password as necessary.*/
1180       /*************************************************/
1181       *cp++ = password[password_index++ % password_len];
1182     }
1183     MD5_PROCESS(&md5_hash_state, password_buf, 64);
1184     count += 64;
1185   }
1186   MD5_DONE(&md5_hash_state, key);      /* tell MD5 we're done */
1187
1188 #ifdef __DEBUG
1189   debughexcprintf(21, "key", key, *key_len);
1190 #endif
1191
1192   /*****************************************************/
1193   /* Now localize the key with the engine_id and pass  */
1194   /* through MD5 to produce final key                  */
1195   /* May want to ensure that engine_id_len <= 32,      */
1196   /* otherwise need to use a buffer larger than 64     */
1197   /*****************************************************/
1198   memcpy(password_buf,                            key,       *key_len);
1199   memcpy(password_buf + *key_len,                 engine_id, engine_id_len);
1200   memcpy(password_buf + *key_len + engine_id_len, key,       *key_len);
1201
1202   MD5_INIT(&md5_hash_state);
1203   MD5_PROCESS(&md5_hash_state, password_buf, (2 * *key_len) + engine_id_len);
1204   MD5_DONE(&md5_hash_state, key);
1205
1206 #ifdef __DEBUG
1207   debughexcprintf(21, "localized key", key, *key_len);
1208 #endif
1209
1210   return SNMPv3_USM_OK;
1211 }
1212
1213 int AuthMD5::hash(const unsigned char *data,
1214                   const unsigned int   data_len,
1215                   unsigned char       *digest) const
1216 {
1217   MD5HashStateType md5_hash_state;
1218
1219   MD5_INIT(&md5_hash_state);
1220   MD5_PROCESS(&md5_hash_state, data, data_len);
1221   MD5_DONE(&md5_hash_state, digest);
1222
1223   return SNMPv3_USM_OK;
1224 }
1225
1226 int AuthMD5::auth_out_msg(const unsigned char *key,
1227                           unsigned char *msg,
1228                           const int      msg_len,
1229                           unsigned char *auth_par_ptr)
1230 {
1231   MD5HashStateType md5_hash_state;
1232   int           key_len = 16; /* We use only 16 Byte Key! */
1233   unsigned char digest[16];
1234   unsigned char k_ipad[65];   /* inner padding - key XORd with ipad */
1235   unsigned char k_opad[65];   /* outer padding - key XORd with opad */
1236
1237   memset((char*)(auth_par_ptr), 0, 12);
1238
1239 #ifdef __DEBUG
1240   debughexcprintf(21, "key", key, 16);
1241 #endif
1242
1243   /*
1244    * the HMAC_MD5 transform looks like:
1245    *
1246    * MD5(K XOR opad, MD5(K XOR ipad, msg))
1247    *
1248    * where K is an n byte key
1249    * ipad is the byte 0x36 repeated 64 times
1250    * opad is the byte 0x5c repeated 64 times
1251    * and text is the data being protected
1252    */
1253
1254   /* start out by storing key in pads */
1255   memset( (char*)k_ipad, 0, sizeof k_ipad);
1256   memset( (char*)k_opad, 0, sizeof k_opad);
1257   memcpy( (char*)k_ipad, (char*)key, key_len);
1258   memcpy( (char*)k_opad, (char*)key, key_len);
1259
1260   /* XOR key with ipad and opad values */
1261   for (int i=0; i<64; i++) {
1262     k_ipad[i] ^= 0x36;
1263     k_opad[i] ^= 0x5c;
1264   }
1265
1266   /* perform inner MD5 */
1267   MD5_INIT(&md5_hash_state);            /* init md5_hash_state for 1st pass */
1268   MD5_PROCESS(&md5_hash_state, k_ipad, 64);    /* start with inner pad      */
1269   MD5_PROCESS(&md5_hash_state, msg, msg_len);  /* then text of datagram     */
1270   MD5_DONE(&md5_hash_state, digest);           /* finish up 1st pass        */
1271   /* perform outer MD5 */
1272   MD5_INIT(&md5_hash_state);            /* init md5_hash_state for 2nd pass */
1273   MD5_PROCESS(&md5_hash_state, k_opad, 64);    /* start with outer pad      */
1274   MD5_PROCESS(&md5_hash_state, digest, 16);    /* then results of 1st hash  */
1275   MD5_DONE(&md5_hash_state, digest);           /* finish up 2nd pass        */
1276
1277 #ifdef __DEBUG
1278   debughexcprintf(21, "digest", digest, 128 / 8);
1279 #endif
1280
1281   memcpy(auth_par_ptr, digest, 12);
1282
1283   return SNMPv3_USM_OK;
1284 }
1285
1286 int AuthMD5::auth_inc_msg(const unsigned char *key,
1287                           unsigned char *msg,
1288                           const int msg_len,
1289                           unsigned char *auth_par_ptr,
1290                           const int      auth_par_len)
1291 {
1292   unsigned char receivedDigest[16];
1293
1294   if (auth_par_len != 12)
1295   {
1296     debugprintf(4, "MD5 illegal digest length (%d), authentication FAILED.",
1297                 auth_par_len);
1298     return SNMPv3_USM_AUTHENTICATION_FAILURE;
1299   }
1300
1301 #ifdef __DEBUG
1302   debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
1303   debughexcprintf(21, "key", key, 16);
1304 #endif
1305
1306   memcpy(receivedDigest, auth_par_ptr, 12);
1307
1308   if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
1309   {
1310     /* copy digest back into message and return error */
1311     memcpy(auth_par_ptr, receivedDigest, 12);
1312     debugprintf(4, "MD5 authentication FAILED (1).");
1313     return SNMPv3_USM_AUTHENTICATION_FAILURE;
1314   }
1315
1316   /* compare digest to received digest */
1317   for (int i=0; i < 12 ; ++i)
1318   {
1319     if (auth_par_ptr[i] != receivedDigest[i])
1320     {
1321       /* copy digest back into message and return error */
1322       memcpy(auth_par_ptr, receivedDigest, 12);
1323       debugprintf(4, "MD5 authentication FAILED.");
1324       return SNMPv3_USM_AUTHENTICATION_FAILURE;
1325     }
1326   }
1327   debugprintf(4, "MD5 authentication OK.");
1328   return SNMPv3_USM_OK;
1329 }
1330
1331 /* ========================= PRIV ================================*/
1332
1333 /* ----------------------- PrivDES ---------------------------------------*/
1334
1335 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1336 PrivDES::PrivDES()
1337 {
1338   cipher = find_cipher("des");
1339 }
1340 #endif
1341
1342 int PrivDES::encrypt(const unsigned char *key,
1343                      const unsigned int   /*key_len*/,
1344                      const unsigned char *buffer,
1345                      const unsigned int   buffer_len,
1346                      unsigned char       *out_buffer,
1347                      unsigned int        *out_buffer_len,
1348                      unsigned char       *privacy_params,
1349                      unsigned int        *privacy_params_len,
1350                      const unsigned long  engine_boots,
1351                      const unsigned long  /*engine_time*/)
1352 {
1353   unsigned char initVect[8];
1354   pp_uint64     my_salt = (*salt)++;
1355
1356 #ifdef INVALID_ENCRYPTION
1357   debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1358   my_salt = 0;
1359 #endif
1360
1361   /* check space in privacy_params buffer */
1362   if (*privacy_params_len < 8)
1363   {
1364     debugprintf(4, "Buffer too small: should be 8, is (%i).",
1365                 *privacy_params_len);
1366     return SNMPv3_USM_ENCRYPTION_ERROR;
1367   }
1368   /* Length is always 8 */
1369   *privacy_params_len = 8;
1370
1371   // last 8 bytes of key are used as base for initialization vector
1372   memcpy((char*)initVect, key+8, 8);
1373
1374   // put salt in privacy_params
1375   for (int j=0; j<4; j++)
1376   {
1377     privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
1378     privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
1379   }
1380
1381   // xor initVect with salt
1382   for (int i=0; i<8; i++)
1383     initVect[i] ^= privacy_params[i];
1384
1385 #ifdef __DEBUG
1386   debughexcprintf(21, "apDESEncryptData: Data to encrypt",
1387                  buffer, buffer_len);
1388   debughexcprintf(21, "apDESEncryptData: used key (only 8 bytes used)",
1389                   key, 16);
1390   debughexcprintf(21, "apDESEncryptData: used iv",
1391                   initVect, 8);
1392 #endif
1393
1394   DESCBCType symcbc;
1395   DES_CBC_START_ENCRYPT(cipher, initVect, key, 8, 16, symcbc);
1396
1397   for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
1398     DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
1399   }
1400
1401   /* last part of buffer */
1402   if (buffer_len % 8)
1403   {
1404     unsigned char tmp_buf[8];
1405     unsigned char *tmp_buf_ptr = tmp_buf;
1406     int start = buffer_len - (buffer_len % 8);
1407     memset(tmp_buf, 0, 8);
1408     for (unsigned int l = start; l < buffer_len; l++)
1409       *tmp_buf_ptr++ = buffer[l];
1410     DES_CBC_ENCRYPT(tmp_buf, out_buffer + start, symcbc, initVect, 8);
1411     *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
1412   }
1413   else
1414     *out_buffer_len = buffer_len;
1415
1416   /* Clear context buffer (paranoia!)*/
1417   DES_MEMSET(symcbc, 0, sizeof(symcbc));
1418
1419 #ifdef __DEBUG
1420   debughexcprintf(21, "apDESEncryptData: created privacy_params",
1421                   privacy_params, 8);
1422   debughexcprintf(21, "apDESEncryptData: encrypted Data",
1423                   out_buffer, *out_buffer_len);
1424 #endif
1425
1426   return SNMPv3_USM_OK;
1427 }
1428
1429
1430
1431 int PrivDES::decrypt(const unsigned char *key,
1432                      const unsigned int   /*key_len*/,
1433                      const unsigned char *buffer,
1434                      const unsigned int   buffer_len,
1435                      unsigned char *outBuffer,
1436                      unsigned int  *outBuffer_len,
1437                      const unsigned char *privacy_params,
1438                      const unsigned int   privacy_params_len,
1439                      const unsigned long  /*engine_boots*/,
1440                      const unsigned long  /*engine_time*/)
1441 {
1442   unsigned char initVect[8];
1443
1444   /* Privacy params length has to be 8  && Length has to be a multiple of 8 */
1445   if (( buffer_len % 8 ) || (privacy_params_len != 8))
1446     return SNMPv3_USM_DECRYPTION_ERROR;
1447
1448   for (int i=0; i<8; i++)
1449     initVect[i] = privacy_params[i] ^ key[i+8];
1450
1451   memset((char*)outBuffer, 0, *outBuffer_len);
1452
1453 #ifdef __DEBUG
1454   debughexcprintf(21, "apDESDecryptData: Data to decrypt",
1455                   buffer, buffer_len);
1456   debughexcprintf(21, "apDESDecryptData: used key (only 8 bytes used)",
1457                   key, 16);
1458   debughexcprintf(21, "apDESDecryptData: used privacy_params",
1459                   privacy_params, 8);
1460   debughexcprintf(21, "apDESDecryptData: used iv",
1461                   initVect, 8);
1462 #endif
1463
1464   DESCBCType symcbc;
1465   DES_CBC_START_DECRYPT(cipher, initVect, key, 8, 16, symcbc);
1466   for(unsigned int j=0; j<buffer_len; j+=8 ) {
1467     DES_CBC_DECRYPT(buffer + j, outBuffer + j, symcbc, initVect, 8);
1468   }
1469   /* Clear context (paranoia!) */
1470   DES_MEMSET(symcbc, 0, sizeof(symcbc));
1471
1472   *outBuffer_len = buffer_len;
1473
1474 #ifdef __DEBUG
1475   debughexcprintf(21, "apDESDecryptData: decrypted Data",
1476                   outBuffer, *outBuffer_len);
1477 #endif
1478
1479   return SNMPv3_USM_OK;
1480 }
1481
1482
1483 /* ----------------------- PrivIDEA --------------------------------------*/
1484
1485 #ifdef _USE_IDEA
1486
1487 int PrivIDEA::encrypt(const unsigned char *key,
1488                       const unsigned int   /*key_len*/,
1489                       const unsigned char *buffer,
1490                       const unsigned int   buffer_len,
1491                       unsigned char       *out_buffer,
1492                       unsigned int        *out_buffer_len,
1493                       unsigned char       *privacy_params,
1494                       unsigned int        *privacy_params_len,
1495                       const unsigned long  engine_boots,
1496                       const unsigned long  /*engine_time*/)
1497 {
1498   IDEAContext CFB_Context;
1499   pp_uint64 my_salt = (*salt)++;
1500
1501 #ifdef INVALID_ENCRYPTION
1502   debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1503   my_salt = 0;
1504 #endif
1505
1506   /* check space in privacy_params buffer */
1507   if (*privacy_params_len < 8)
1508   {
1509     debugprintf(4, "Buffer too small: should be 8, is (%i).", *privacy_params_len);
1510     return SNMPv3_USM_ENCRYPTION_ERROR;
1511   }
1512   /* Length is always 8 */
1513   *privacy_params_len = 8;
1514
1515   // last 8 bytes of key are used as base for initialization vector
1516   unsigned char iv[8];
1517
1518   memcpy((char*)iv, key+8, 8);
1519
1520   // put salt in privacy_params
1521   for (int j=0; j<4; j++)
1522   {
1523     privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
1524     privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
1525   }
1526   // xor iv with privacy_params
1527   for (int i=0; i<8; i++)
1528     iv[i] ^= privacy_params[i];
1529
1530   idea_set_key(&CFB_Context, key);
1531
1532   idea_cfb_encrypt(&CFB_Context, iv, out_buffer,
1533                    buffer, buffer_len);
1534
1535   /* Clear context (paranoia!) */
1536   idea_destroy_context(&CFB_Context);
1537
1538   *out_buffer_len = buffer_len;
1539
1540 #ifdef __DEBUG
1541   debughexcprintf(21, "apIDEAEncryptData: Data to encrypt",
1542                   buffer, buffer_len);
1543   debughexcprintf(21, "apIDEAEncryptData: key",
1544                   key, 16);
1545   debughexcprintf(21, "apIDEAEncryptData: privacy_params",
1546                   privacy_params, 8);
1547   debughexcprintf(21, "apIDEAEncryptData: encrypted Data",
1548                   out_buffer, *out_buffer_len);
1549 #endif
1550
1551   return SNMPv3_USM_OK;
1552 }
1553
1554 int PrivIDEA::decrypt(const unsigned char *key,
1555                       const unsigned int   /*key_len*/,
1556                       const unsigned char *buffer,
1557                       const unsigned int   buffer_len,
1558                       unsigned char *out_buffer,
1559                       unsigned int  *out_buffer_len,
1560                       const unsigned char *privacy_params,
1561                       const unsigned int   privacy_params_len,
1562                       const unsigned long  /*engine_boots*/,
1563                       const unsigned long  /*engine_time*/)
1564 {
1565   unsigned char iv[8];
1566   IDEAContext CFB_Context;
1567
1568   /* privacy params length has to be 8 */
1569   if (privacy_params_len != 8)
1570     return SNMPv3_USM_DECRYPTION_ERROR;
1571
1572   idea_set_key(&CFB_Context, key);
1573
1574   memset((char*)out_buffer, 0, *out_buffer_len);
1575
1576   /* Initialize iv with last 8 bytes of key and xor with privacy_params */
1577   memcpy((char*)iv, key+8, 8);
1578   for (int i=0; i<8; i++)
1579     iv[i] ^= privacy_params[i];
1580
1581   idea_cfb_decrypt(&CFB_Context, iv, out_buffer,
1582                    buffer, buffer_len);
1583
1584   /* Clear context (paranoia!) */
1585   idea_destroy_context(&CFB_Context);
1586   memset((char*)iv, 0, 8);
1587
1588   *out_buffer_len = buffer_len;
1589
1590 #ifdef __DEBUG
1591   debughexcprintf(21, "apIDEADecryptData: Data to decrypt",
1592                   buffer, buffer_len);
1593   debughexcprintf(21, "apIDEADecryptData: key", key, 16);
1594   debughexcprintf(21, "apIDEAEncryptData: privacy_params", privacy_params, 8);
1595   debughexcprintf(21, "apIDEADecryptData: decrypted Data",
1596                   out_buffer, *out_buffer_len);
1597 #endif
1598
1599   return SNMPv3_USM_OK;
1600 }
1601
1602 #endif // _USE_IDEA
1603
1604 #if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
1605
1606 PrivAES::PrivAES(const int aes_type_)
1607   : aes_type(aes_type_)
1608 {
1609 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1610   cipher = find_cipher("rijndael");
1611 #endif
1612
1613   switch (aes_type)
1614   {
1615     case SNMP_PRIVPROTOCOL_AES128:
1616       key_bytes = 16;
1617       rounds = 10;
1618       break;
1619     case SNMP_PRIVPROTOCOL_AES192:
1620       key_bytes = 24;
1621       rounds = 12;
1622       break;
1623     case SNMP_PRIVPROTOCOL_AES256:
1624       key_bytes = 32;
1625       rounds = 14;
1626       break;
1627     default:
1628       debugprintf(0, "Wrong AES type: %i.", aes_type);
1629       key_bytes = 0;
1630       rounds = 0;
1631       aes_type = -1; // will cause an error in AuthPriv::add_priv()
1632   }
1633
1634   unsigned int testswap = htonl(0x01020304);
1635   if (testswap == 0x01020304)
1636     need_byteswap = FALSE;
1637   else
1638     need_byteswap = TRUE;
1639 }
1640
1641 const char *PrivAES::get_id_string() const
1642 {
1643   switch (aes_type)
1644   {
1645     case SNMP_PRIVPROTOCOL_AES128: return "AES128";  break;
1646     case SNMP_PRIVPROTOCOL_AES192: return "AES192";  break;
1647     case SNMP_PRIVPROTOCOL_AES256: return "AES256";  break;
1648     default:                       return "error";   break;
1649   }
1650 };
1651
1652 int PrivAES::encrypt(const unsigned char *key,
1653                      const unsigned int   key_len,
1654                      const unsigned char *buffer,
1655                      const unsigned int   buffer_len,
1656                      unsigned char       *out_buffer,
1657                      unsigned int        *out_buffer_len,
1658                      unsigned char       *privacy_params,
1659                      unsigned int        *privacy_params_len,
1660                      const unsigned long  engine_boots,
1661                      const unsigned long  engine_time)
1662 {
1663   unsigned char initVect[16];
1664   pp_uint64 my_salt = (*salt)++;
1665
1666 #ifdef INVALID_ENCRYPTION
1667   debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1668   my_salt = 0;
1669 #endif
1670
1671   /* check space in privacy_params buffer */
1672   if (*privacy_params_len < 8)
1673   {
1674     debugprintf(4, "Buffer too small: should be 8, is (%i).",
1675                 *privacy_params_len);
1676     return SNMPv3_USM_ENCRYPTION_ERROR;
1677   }
1678   /* Length is always 8 */
1679   *privacy_params_len = 8;
1680
1681   /* Set IV as engine_boots + engine_time + salt */
1682   unsigned int *tmpi = (unsigned int *)initVect;
1683   *tmpi++ = htonl(engine_boots);
1684   *tmpi++ = htonl(engine_time);
1685   if (need_byteswap)
1686   {
1687     *tmpi++ = htonl(my_salt & 0xFFFFFFFF);
1688     *tmpi   = htonl((my_salt >> 32) & 0xFFFFFFFF);
1689   }
1690   else
1691     memcpy(tmpi, &my_salt, 8);
1692
1693   /* put byteswapped salt in privacy_params */
1694   memcpy(privacy_params, initVect + 8, 8);
1695   debughexcprintf(21, "aes initVect:", initVect, 16);
1696
1697 #ifdef _USE_OPENSSL
1698   AES_KEY symcfb;
1699   int dummy = 0;
1700
1701   if (AES_set_encrypt_key(key, key_len * 8, &symcfb) < 0)
1702   {
1703     
1704     debugprintf(1, "AES_set_encrypt_key(%p, %d, %p) failed.",
1705                 key, key_len * 8, &symcfb);
1706     return SNMPv3_USM_ERROR;
1707   }
1708
1709   AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
1710                      &symcfb, initVect, &dummy, AES_ENCRYPT);
1711 #else
1712   symmetric_CFB symcfb;
1713
1714   cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
1715   cfb_encrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
1716 #endif
1717
1718   /* Clear context and plaintext buffer (paranoia!)*/
1719   memset(&symcfb, 0, sizeof(symcfb));
1720
1721   *out_buffer_len = buffer_len;
1722
1723 #ifdef __DEBUG
1724   debughexcprintf(21, "aes EncryptData: Data to encrypt", buffer, buffer_len);
1725   debughexcprintf(21, "aes EncryptData: used key", key, key_len);
1726   debughexcprintf(21, "aes EncryptData: created privacy_params",
1727                   privacy_params, 8);
1728   debughexcprintf(21, "aes EncryptData: encrypted Data",
1729                   out_buffer, *out_buffer_len);
1730 #endif
1731
1732   return SNMPv3_USM_OK;
1733 }
1734
1735 int PrivAES::decrypt(const unsigned char *key,
1736                      const unsigned int   key_len,
1737                      const unsigned char *buffer,
1738                      const unsigned int   buffer_len,
1739                      unsigned char       *out_buffer,
1740                      unsigned int        *out_buffer_len,
1741                      const unsigned char *privacy_params,
1742                      const unsigned int   privacy_params_len,
1743                      const unsigned long  engine_boots,
1744                      const unsigned long  engine_time)
1745 {
1746   unsigned char initVect[16];
1747
1748   /* Privacy params length has to be 8 */
1749   if (privacy_params_len != 8)
1750     return SNMPv3_USM_DECRYPTION_ERROR;
1751
1752   /* build IV */
1753   unsigned int *tmp;
1754   tmp = (unsigned int *)initVect;
1755   *tmp++ = htonl(engine_boots);
1756   *tmp = htonl(engine_time);
1757   memcpy(initVect + 8, privacy_params, 8);
1758   debughexcprintf(21, "aes initVect:", initVect, 16);
1759
1760 #ifdef _USE_OPENSSL
1761   int dummy = 0;
1762   AES_KEY symcfb;
1763
1764   AES_set_encrypt_key(key, key_len * 8, &symcfb);
1765   AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
1766                      &symcfb, initVect, &dummy, AES_DECRYPT);
1767 #else
1768   symmetric_CFB symcfb;
1769
1770   cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
1771   cfb_decrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
1772 #endif
1773
1774   /* Clear context and plaintext buffer (paranoia!)*/
1775   memset(&symcfb, 0, sizeof(symcfb));
1776
1777   *out_buffer_len = buffer_len;
1778
1779 #ifdef __DEBUG
1780   debughexcprintf(21, "aes DecryptData: Data to decrypt", buffer, buffer_len);
1781   debughexcprintf(21, "aes DecryptData: used key", key, key_len);
1782   debughexcprintf(21, "aes DecryptData: used privacy_params",
1783                   privacy_params, 8);
1784   debughexcprintf(21, "aes DecryptData: decrypted Data",
1785                   out_buffer, *out_buffer_len);
1786 #endif
1787
1788   return SNMPv3_USM_OK;
1789 }
1790
1791 int PrivAES::extend_short_key(const unsigned char *password,
1792                               const unsigned int   password_len,
1793                               const unsigned char *engine_id,
1794                               const unsigned int   engine_id_len,
1795                               unsigned char       *key,
1796                               unsigned int        *key_len,
1797                               const unsigned int   max_key_len,
1798                               Auth                *auth)
1799 {
1800   if (max_key_len < (unsigned)key_bytes)
1801       return SNMPv3_USM_ERROR;
1802
1803   int res = 0;
1804   unsigned char *hash_buf = new unsigned char[auth->get_hash_len()];
1805
1806   if (!hash_buf)
1807   {
1808     debugprintf(0, "Out of mem. Did not get %i bytes.", auth->get_hash_len());
1809     return SNMPv3_USM_ERROR;
1810   }
1811
1812   while (*key_len < (unsigned)key_bytes)
1813   {
1814     res = auth->hash(key, *key_len, hash_buf);
1815     if (res != SNMPv3_USM_OK)
1816       break;
1817
1818     int copy_bytes = key_bytes - *key_len;
1819     if (copy_bytes > auth->get_hash_len())
1820       copy_bytes = auth->get_hash_len();
1821     if (*key_len + copy_bytes > max_key_len)
1822         copy_bytes = max_key_len - *key_len;
1823     memcpy(key + *key_len, hash_buf, copy_bytes);
1824     *key_len += copy_bytes;
1825   }
1826
1827   if (hash_buf) delete [] hash_buf;
1828
1829   return res;
1830 }
1831
1832
1833 #endif // _USE_LIBTOMCRYPT or _USE_OPENSSL
1834
1835
1836 #ifdef _USE_3DES_EDE
1837
1838 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1839 Priv3DES_EDE::Priv3DES_EDE()
1840 {
1841   cipher = find_cipher("3des");
1842   debugprintf(10, "tomcrypt returned cipher %d", cipher);
1843 }
1844 #endif
1845
1846
1847 int 
1848 Priv3DES_EDE::encrypt(const unsigned char *key,
1849                       const unsigned int   key_len,
1850                       const unsigned char *buffer,
1851                       const unsigned int   buffer_len,
1852                       unsigned char       *out_buffer,
1853                       unsigned int        *out_buffer_len,
1854                       unsigned char       *privacy_params,
1855                       unsigned int        *privacy_params_len,
1856                       const unsigned long  engine_boots,
1857                       const unsigned long  engine_time)
1858 {
1859   unsigned char initVect[8];
1860   pp_uint64     my_salt = (*salt)++;
1861   
1862 #ifdef INVALID_ENCRYPTION
1863   debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1864   my_salt = 0;
1865 #endif
1866
1867   /* check space in privacy_params buffer */
1868   if (*privacy_params_len < 8)
1869   {
1870     debugprintf(4, "Buffer too small: should be 8, is (%i).",
1871                 *privacy_params_len);
1872     return SNMPv3_USM_ENCRYPTION_ERROR;
1873   }
1874   /* Length is always 8 */
1875   *privacy_params_len = 8;
1876
1877   /* check key length */
1878   if (key_len < TRIPLEDES_EDE_KEY_LEN)
1879   {
1880     debugprintf(4, "Key too small: should be %d, is (%d).",
1881                 TRIPLEDES_EDE_KEY_LEN, key_len);
1882     return SNMPv3_USM_ENCRYPTION_ERROR;
1883   }
1884
1885   /* TODO: check if K1 != K2 != K3 */
1886
1887   // last 8 bytes of key are used as base for initialization vector
1888   memcpy((char*)initVect, key+24, 8);
1889
1890   /* TODO: generate salt as specified in draft */
1891
1892   // put salt in privacy_params
1893   for (int j=0; j<4; j++)
1894   {
1895     privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
1896     privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
1897   }
1898
1899   // xor initVect with salt
1900   for (int i=0; i<8; i++)
1901     initVect[i] ^= privacy_params[i];
1902
1903
1904 #ifdef __DEBUG
1905   debughexcprintf(21, "3DES Data to encrypt", buffer, buffer_len);
1906   debughexcprintf(21, "3DES used iv", initVect, 8);
1907   debughexcprintf(21, "3DES key", key, key_len);
1908 #endif
1909
1910   // The first 24 octets of the 32-octet secret are used as a 3DES-EDE
1911   // key. Since 3DES-EDE uses only 168 bits the least significant bit
1912   // in each octet is disregarded
1913
1914 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1915   DESCBCType symcbc;
1916   DES_CBC_START_ENCRYPT(cipher, initVect, key, 24, 16, symcbc);
1917
1918   for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
1919     DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
1920   }
1921
1922   /* last part of buffer */
1923   if (buffer_len % 8)
1924   {
1925     unsigned char tmp_buf[8];
1926     unsigned char *tmp_buf_ptr = tmp_buf;
1927     int start = buffer_len - (buffer_len % 8);
1928     memset(tmp_buf, 0, 8);
1929     for (unsigned int l = start; l < buffer_len; l++)
1930       *tmp_buf_ptr++ = buffer[l];
1931     DES_CBC_ENCRYPT(tmp_buf, out_buffer + start, symcbc, initVect, 8);
1932     *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
1933   }
1934   else
1935     *out_buffer_len = buffer_len;
1936
1937   /* Clear context buffer (paranoia!)*/
1938   DES_MEMSET(symcbc, 0, sizeof(symcbc));
1939
1940 #else
1941   DESCBCType ks1, ks2, ks3;
1942
1943   if ((des_key_sched((C_Block*)(key),     ks1) < 0) ||
1944       (des_key_sched((C_Block*)(key +8),  ks2) < 0) ||
1945       (des_key_sched((C_Block*)(key +16), ks3) < 0))
1946   {
1947       debugprintf(0, "Starting 3DES-EDE encryption failed.");
1948       return SNMPv3_USM_ERROR;
1949   }
1950
1951   if (buffer_len >= 8)
1952     for(unsigned int k = 0; k <= (buffer_len - 8); k += 8) 
1953     {
1954       DES_EDE3_CBC_ENCRYPT(buffer+k, out_buffer+k, 8,
1955                            ks1, ks2, ks3, initVect);
1956     }
1957
1958   // Last part
1959   if (buffer_len % 8)
1960     {
1961       unsigned char tmp_buf[8];
1962       unsigned char *tmp_buf_ptr = tmp_buf;
1963       int start = buffer_len - (buffer_len % 8);
1964       memset(tmp_buf, 0, 8);
1965       for (unsigned int l = start; l < buffer_len; l++)
1966         *tmp_buf_ptr++ = buffer[l];
1967       DES_EDE3_CBC_ENCRYPT(tmp_buf, out_buffer + start, 8,
1968                            ks1, ks2, ks3, initVect);
1969       
1970       *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
1971     }
1972   else
1973     *out_buffer_len = buffer_len;
1974
1975   /* Clear context buffer (paranoia!)*/
1976   DES_MEMSET(ks1, 0, sizeof(ks1));
1977   DES_MEMSET(ks2, 0, sizeof(ks2));
1978   DES_MEMSET(ks3, 0, sizeof(ks3));
1979 #endif
1980
1981 #ifdef __DEBUG
1982   debughexcprintf(21, "3DES created privacy_params", privacy_params, 8);
1983   debughexcprintf(21, "3DES encrypted Data", out_buffer, *out_buffer_len);
1984 #endif
1985
1986   return SNMPv3_USM_OK;
1987 }
1988
1989
1990 int 
1991 Priv3DES_EDE::decrypt(const unsigned char *key,
1992                       const unsigned int   key_len,
1993                       const unsigned char *buffer,
1994                       const unsigned int   buffer_len,
1995                       unsigned char       *out_buffer,
1996                       unsigned int        *out_buffer_len,
1997                       const unsigned char *privacy_params,
1998                       const unsigned int   privacy_params_len,
1999                       const unsigned long  engine_boots,
2000                       const unsigned long  engine_time)
2001 {
2002   unsigned char initVect[8];
2003
2004   /* Privacy params length has to be 8  && Length has to be a multiple of 8 */
2005   if (( buffer_len % 8 ) || (privacy_params_len != 8))
2006     return SNMPv3_USM_DECRYPTION_ERROR;
2007
2008   for (int i=0; i<8; i++)
2009     initVect[i] = privacy_params[i] ^ key[i+24];
2010
2011   memset((char*)out_buffer, 0, *out_buffer_len);
2012
2013 #ifdef __DEBUG
2014   debughexcprintf(21, "3DES Data to decrypt", buffer, buffer_len);
2015   debughexcprintf(21, "3DES privacy_params",  privacy_params, 8);
2016   debughexcprintf(21, "3DES used iv",   initVect, 8);
2017   debughexcprintf(21, "3DES key", key, key_len);
2018 #endif
2019
2020 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
2021   DESCBCType symcbc;
2022   DES_CBC_START_DECRYPT(cipher, initVect, key, 24, 16, symcbc);
2023   for(unsigned int j=0; j<buffer_len; j+=8 ) {
2024     DES_CBC_DECRYPT(buffer + j, out_buffer + j, symcbc, initVect, 8);
2025   }
2026   /* Clear context (paranoia!) */
2027   DES_MEMSET(symcbc, 0, sizeof(symcbc));
2028
2029 #else
2030   DESCBCType ks1, ks2, ks3;
2031
2032   if ((des_key_sched((C_Block*)(key),     ks1) < 0) ||
2033       (des_key_sched((C_Block*)(key+8),  ks2) < 0) ||
2034       (des_key_sched((C_Block*)(key+16), ks3) < 0))
2035     {
2036       debugprintf(0, "Starting 3DES-EDE decryption failed.");
2037       return SNMPv3_USM_ERROR;
2038     }
2039
2040   for(unsigned int k=0; k<buffer_len; k+=8 ) 
2041     {
2042       DES_EDE3_CBC_DECRYPT(buffer+k, out_buffer+k, 8,
2043                            ks1, ks2, ks3, initVect);
2044     }
2045   /* Clear context (paranoia!) */
2046   DES_MEMSET(ks1, 0, sizeof(ks1));
2047   DES_MEMSET(ks2, 0, sizeof(ks2));
2048   DES_MEMSET(ks3, 0, sizeof(ks3));
2049 #endif
2050
2051   *out_buffer_len = buffer_len;
2052
2053 #ifdef __DEBUG
2054   debughexcprintf(21, "3DES decrypted Data", out_buffer, *out_buffer_len);
2055 #endif
2056
2057   return SNMPv3_USM_OK;  
2058 }
2059
2060
2061 int 
2062 Priv3DES_EDE::extend_short_key(const unsigned char *password,
2063                                const unsigned int   password_len,
2064                                const unsigned char *engine_id,
2065                                const unsigned int   engine_id_len,
2066                                unsigned char       *key,
2067                                unsigned int        *key_len,
2068                                const unsigned int   max_key_len,
2069                                Auth                *auth)
2070 {
2071   if (max_key_len < TRIPLEDES_EDE_KEY_LEN)
2072     return SNMPv3_USM_ERROR;
2073
2074   unsigned int p2k_output_len = *key_len;
2075   unsigned char *p2k_buf = new unsigned char[p2k_output_len];
2076   int res = 0;
2077
2078   if (!p2k_buf) return SNMPv3_USM_ERROR;
2079
2080   while (*key_len < TRIPLEDES_EDE_KEY_LEN)
2081   {
2082     unsigned int p2k_buf_len = p2k_output_len;
2083
2084     res = auth->password_to_key(key, *key_len,
2085                                 engine_id, engine_id_len,
2086                                 p2k_buf, &p2k_buf_len);
2087
2088     if (res != SNMPv3_USM_OK)
2089       break;
2090
2091     unsigned int copy_bytes = TRIPLEDES_EDE_KEY_LEN - *key_len;
2092
2093     if (copy_bytes > p2k_buf_len)
2094         copy_bytes = p2k_buf_len;
2095
2096     if (*key_len + copy_bytes > max_key_len)
2097         copy_bytes = max_key_len - *key_len;
2098
2099     memcpy(key + *key_len, p2k_buf, copy_bytes);
2100
2101     *key_len += copy_bytes;
2102   }
2103
2104   if (p2k_buf) delete [] p2k_buf;
2105
2106   return res;
2107 }
2108
2109 #ifdef _TEST
2110 bool Priv3DES_EDE::test()
2111 {
2112   int status;
2113   AuthPriv ap(status);
2114   if (status != SNMPv3_USM_OK)
2115       return false;
2116
2117   if (ap.add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
2118   {
2119       debugprintf(0, "Error: could not add AuthSHA.");
2120       return false;
2121   }
2122
2123   if (ap.add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
2124   {
2125       debugprintf(0, "Error: could not add AuthMD5.");
2126       return false;
2127   }
2128
2129   if (ap.add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
2130   {
2131       debugprintf(0, "Error: could not add Priv3DES_EDE.");
2132       return false;
2133   }
2134
2135   unsigned char password[11] = "maplesyrup";
2136   unsigned char engine_id[12];
2137
2138   memset(engine_id, 0, 11);
2139   engine_id[11] = 2;
2140
2141   unsigned char key[TRIPLEDES_EDE_KEY_LEN];
2142   unsigned int key_len = TRIPLEDES_EDE_KEY_LEN;
2143
2144   status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
2145                                    SNMP_PRIVPROTOCOL_3DESEDE,
2146                                    password, 10,
2147                                    engine_id, 12,
2148                                    key,  &key_len);
2149
2150   debughexcprintf(1, "result key 3DES SHA",
2151                   key, key_len);
2152
2153   key_len = TRIPLEDES_EDE_KEY_LEN;
2154   status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACMD5,
2155                                    SNMP_PRIVPROTOCOL_3DESEDE,
2156                                    password, 10,
2157                                    engine_id, 12,
2158                                    key,  &key_len);
2159
2160   debughexcprintf(1, "result key 3DES MD5",
2161                   key, key_len);
2162
2163   unsigned char msg[80] = "This is the secret message, that has to be encrypted!";
2164   unsigned char enc_buffer[80];
2165   unsigned int enc_buffer_len = 80;
2166   unsigned char dec_buffer[80];
2167   unsigned int dec_buffer_len = 80;
2168   unsigned char priv_params[64];
2169   unsigned int priv_params_len = 64;
2170
2171
2172   status = ap.encrypt_msg(SNMP_PRIVPROTOCOL_3DESEDE,
2173                           key, key_len, msg, 53,
2174                           enc_buffer, &enc_buffer_len,
2175                           priv_params, &priv_params_len, 0x5abc, 0x6def);
2176   
2177   debughexcprintf(1, "encrypted text",
2178                   enc_buffer, enc_buffer_len);
2179
2180   status = ap.decrypt_msg(SNMP_PRIVPROTOCOL_3DESEDE,
2181                           key, key_len, enc_buffer, enc_buffer_len,
2182                           dec_buffer, &dec_buffer_len,
2183                           priv_params, priv_params_len, 0x5abc, 0x6def);
2184
2185   dec_buffer[dec_buffer_len] = 0;
2186   debugprintf(1, "decrypted text: %s",
2187                   dec_buffer);
2188   // TODO: check keys and return real value
2189   return true;
2190 }
2191 #endif
2192
2193 #endif // _USE_3DES_EDE
2194
2195
2196 #ifdef SNMP_PP_NAMESPACE
2197 }; // end of namespace Snmp_pp
2198 #endif 
2199
2200 #endif // _SNMPv3