1 /*_############################################################################
6 _## -----------------------------------------------
7 _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
9 _## This software is based on SNMP++2.6 from Hewlett Packard:
11 _## Copyright (c) 1996
12 _## Hewlett-Packard Company
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.
26 _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
28 _##########################################################################*/
29 char auth_priv_version[]="@(#) SNMP++ $Id: auth_priv.cpp 1799 2010-08-14 20:11:45Z katz $";
31 #include "snmp_pp/config_snmp_pp.h"
39 // Only use DES, AES, SHA1 and MD5 from libtomcrypt if openssl is not used
40 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
44 // Use DES, AES, SHA and MD5 from openssl
46 #include <openssl/des.h>
47 #include <openssl/aes.h>
48 #include <openssl/sha.h>
49 #include <openssl/md5.h>
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"
60 #include "snmp_pp/md5.h"
62 #endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
64 // IDEA can only be used with a valid license
66 #include "snmp_pp/idea.h"
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"
75 #ifdef SNMP_PP_NAMESPACE
79 /*-----------------[ defines for crypto libraries ]------------------*/
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)
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)
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) \
98 debugprintf(0, "Starting DES encryption failed."); \
99 return SNMPv3_USM_ERROR; \
101 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
102 if (des_key_sched((C_Block*)(k), s) < 0) \
104 debugprintf(0, "Starting DES decryption failed."); \
105 return SNMPv3_USM_ERROR; \
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)
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)
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)
123 #define DES_MEMSET(s, c, l) memset(&(s), c, l)
125 /* -- END: Defines for OpenSSL -- */
129 #ifdef _USE_LIBTOMCRYPT
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)
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)
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) \
146 debugprintf(0, "Starting DES encryption failed."); \
147 return SNMPv3_USM_ERROR; \
150 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
151 if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
153 debugprintf(0, "Starting DES decryption failed."); \
154 return SNMPv3_USM_ERROR; \
157 #define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
158 if (cbc_encrypt(pt, ct, l, &(s)) != CRYPT_OK) \
160 debugprintf(0, "Error during DES encryption."); \
161 return SNMPv3_USM_ERROR; \
163 #define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
164 if (cbc_decrypt(ct, pt, l, &(s)) != CRYPT_OK) \
166 debugprintf(0, "Error during DES decryption."); \
167 return SNMPv3_USM_ERROR; \
169 #define DES_MEMSET(s, c, l) memset(&(s), c, l)
170 /* -- END: Defines for LibTomCrypt -- */
172 #else // _USE_LIBTOMCRYPT --> libdes
174 /* -- START: Defines for libdes -- */
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)
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)
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)
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)
197 #define MD5_PROCESS(s, p, l) MD5Update(s, (unsigned char*)(p), l)
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)
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) \
214 debugprintf(0, "Starting DES encryption failed."); \
215 return SNMPv3_USM_ERROR; \
217 #define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
218 if (des_key_sched((C_Block*)(k), s) < 0) \
220 debugprintf(0, "Starting DES decryption failed."); \
221 return SNMPv3_USM_ERROR; \
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)
232 /* -- END: Defines for libdes -- */
236 #endif // _USE_LIBTOMCRYPT
238 #endif // _USE_OPENSSL
240 AuthPriv::AuthPriv(int &construct_state)
242 auth = new AuthPtr[10];
243 priv = new PrivPtr[10];
251 LOG_BEGIN(ERROR_LOG | 1);
252 LOG("AuthPriv: Error allocating array for authentication.");
262 LOG_BEGIN(ERROR_LOG | 1);
263 LOG("AuthPriv: Error allocating array for privacy.");
267 for (int i = 0; i < auth_size; i++)
270 for (int j = 0; j < priv_size; j++)
273 /* Check size of salt, has to be 64 bits */
274 if (sizeof(salt) != 8)
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.");
280 construct_state = SNMPv3_USM_ERROR;
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++)
289 if (rand() < (RAND_MAX / 2))
293 construct_state = SNMPv3_USM_OK;
295 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
296 /* register needed hashes and ciphers in libtomcrypt */
297 if (register_cipher(&rijndael_desc) < 0)
299 LOG_BEGIN(ERROR_LOG | 1);
300 LOG("AuthPriv: Error registering Rijndael.");
303 construct_state = SNMPv3_USM_ERROR;
306 if (register_cipher(&des_desc) < 0)
308 LOG_BEGIN(ERROR_LOG | 1);
309 LOG("AuthPriv: Error registering DES.");
312 construct_state = SNMPv3_USM_ERROR;
315 if (register_cipher(&des3_desc) < 0)
317 LOG_BEGIN(ERROR_LOG | 1);
318 LOG("AuthPriv: Error registering 3DES.");
321 construct_state = SNMPv3_USM_ERROR;
324 if (register_hash(&sha1_desc) < 0)
326 LOG_BEGIN(ERROR_LOG | 1);
327 LOG("AuthPriv: Error registering SHA1.");
330 construct_state = SNMPv3_USM_ERROR;
333 if (register_hash(&md5_desc) < 0)
335 LOG_BEGIN(ERROR_LOG | 1);
336 LOG("AuthPriv: Error registering MD5.");
339 construct_state = SNMPv3_USM_ERROR;
341 #endif // defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
344 AuthPriv::~AuthPriv()
346 for (int i = 0; i < auth_size; i++)
353 for (int j = 0; j < priv_size; j++)
364 int AuthPriv::add_auth(Auth *new_auth)
368 return SNMP_CLASS_ERROR;
371 int id = new_auth->get_id();
375 return SNMP_CLASS_ERROR;
380 AuthPtr *new_array = new AuthPtr[id + 5];
383 LOG_BEGIN(ERROR_LOG | 1);
384 LOG("AuthPriv: Could not allocate new auth array.");
387 return SNMP_CLASS_ERROR;
389 for (int i=0 ; i<auth_size; i++)
390 new_array[i] = auth[i];
392 for (int j=auth_size ; j<id + 5; j++)
395 AuthPtr *victim = auth;
401 new_auth->set_salt(&salt);
405 LOG_BEGIN(WARNING_LOG | 4);
406 LOG("AuthPriv: deleting old auth object before adding new one (id)");
415 LOG_BEGIN(INFO_LOG | 6);
416 LOG("AuthPriv: Added auth protocol (id)");
420 return SNMP_CLASS_SUCCESS;
423 int AuthPriv::del_auth(const int auth_id)
425 if ((auth_id < 0) || (auth_id >= auth_size) || (auth[auth_id] == 0))
427 LOG_BEGIN(WARNING_LOG | 4);
428 LOG("AuthPriv: Request to delete non existing auth protocol (id)");
432 return SNMP_CLASS_ERROR;
435 delete auth[auth_id];
438 LOG_BEGIN(INFO_LOG | 6);
439 LOG("AuthPriv: Removed auth protocol (id)");
443 return SNMP_CLASS_SUCCESS;
447 int AuthPriv::add_priv(Priv *new_priv)
451 return SNMP_CLASS_ERROR;
454 int id = new_priv->get_id();
458 return SNMP_CLASS_ERROR;
463 PrivPtr *new_array = new PrivPtr[id + 5];
466 LOG_BEGIN(ERROR_LOG | 1);
467 LOG("AuthPriv: Could not allocate new priv array.");
470 return SNMP_CLASS_ERROR;
472 for (int i=0 ; i<priv_size; i++)
473 new_array[i] = priv[i];
475 for (int j=priv_size ; j<id + 5; j++)
478 PrivPtr *victim = priv;
484 new_priv->set_salt(&salt);
488 LOG_BEGIN(WARNING_LOG | 4);
489 LOG("AuthPriv: deleting old priv object before adding new one (id)");
498 LOG_BEGIN(INFO_LOG | 6);
499 LOG("AuthPriv: Added priv protocol (id)");
503 return SNMP_CLASS_SUCCESS;
506 int AuthPriv::del_priv(const int priv_id)
508 if ((priv_id < 0) || (priv_id >= priv_size) || (priv[priv_id] == 0))
510 LOG_BEGIN(WARNING_LOG | 4);
511 LOG("AuthPriv: Request to delete non existing priv protocol (id)");
515 return SNMP_CLASS_ERROR;
518 delete priv[priv_id];
521 LOG_BEGIN(INFO_LOG | 6);
522 LOG("AuthPriv: Removed priv protocol (id)");
526 return SNMP_CLASS_SUCCESS;
529 Auth *AuthPriv::get_auth(const int auth_prot)
531 if ((auth_prot >= 0) && (auth_prot < auth_size))
532 return auth[auth_prot];
536 Priv *AuthPriv::get_priv(const int priv_prot)
538 if ((priv_prot >= 0) && (priv_prot < priv_size))
539 return priv[priv_prot];
543 // Get the unique id for the given auth protocol.
544 int AuthPriv::get_auth_id(const char *string_id) const
546 for (int i = 0; i < auth_size; ++i)
547 if ((auth[i]) && (strcmp(string_id, auth[i]->get_id_string()) == 0))
552 // Get the unique id for the given priv protocol.
553 int AuthPriv::get_priv_id(const char *string_id) const
555 for (int i = 0; i < priv_size; ++i)
556 if ((priv[i]) && (strcmp(string_id, priv[i]->get_id_string()) == 0))
561 int AuthPriv::get_keychange_value(const int auth_prot,
562 const OctetStr& old_key,
563 const OctetStr& new_key,
564 OctetStr& keychange_value)
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
572 keychange_value.clear();
573 int key_len = old_key.len();
575 Auth *a = get_auth(auth_prot);
578 return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
580 // compute random value
581 OctetStr random = "";
583 for (int i=0; i<key_len; i++) {
585 // do not use random values for testing
586 random += OctetStr((unsigned char*)"\0",1);
588 char tmprand = rand();
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());
600 int iterations = (key_len - 1) / a->get_hash_len();
601 OctetStr tmp = old_key;
604 for (int k = 0; k < iterations; k++)
606 unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
607 memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
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());
620 unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
621 memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
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());
631 keychange_value = random;
632 keychange_value += delta;
633 keychange_value += tmp;
636 debughexcprintf(21, "keychange_value",
637 keychange_value.data(), keychange_value.len());
640 return SNMPv3_USM_OK;
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,
649 unsigned int *key_len)
651 if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
654 return SNMPv3_USM_OK;
657 if (!password || (password_len == 0))
659 LOG_BEGIN(WARNING_LOG | 2);
660 LOG("AuthPriv: Password to key auth needs a non empty password");
663 return SNMPv3_USM_ERROR;
666 Auth *a = get_auth(auth_prot);
669 return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
671 int res = a->password_to_key(password, password_len,
672 engine_id, engine_id_len,
679 int AuthPriv::password_to_key_priv(const int auth_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,
686 unsigned int *key_len)
688 /* check for priv protocol */
689 if (priv_prot == SNMP_PRIVPROTOCOL_NONE)
692 return SNMPv3_USM_OK;
695 if (!password || (password_len == 0))
697 LOG_BEGIN(WARNING_LOG | 2);
698 LOG("AuthPriv: Password to key priv needs a non empty password");
701 return SNMPv3_USM_ERROR;
704 Priv *p = get_priv(priv_prot);
705 Auth *a = get_auth(auth_prot);
707 if (!p) return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
708 if (!a) return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
710 unsigned int max_key_len = *key_len; /* save length of buffer! */
711 unsigned int min_key_len = p->get_min_key_len();
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!
717 int res = password_to_key_auth(auth_prot,
718 password, password_len,
719 engine_id, engine_id_len,
721 if (res != SNMPv3_USM_OK)
724 /* We have a too short key: Call priv protocoll to extend it */
725 if (*key_len < min_key_len)
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)
734 /* make sure key length is valid */
735 p->fix_key_len(*key_len);
737 return SNMPv3_USM_OK;
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)
755 /* check for priv protocol */
756 Priv *p = get_priv(priv_prot);
759 return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
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);
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)
779 /* check for priv protocol */
780 Priv *p = get_priv(priv_prot);
783 return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
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);
792 int AuthPriv::add_default_modules()
794 int ret = SNMP_CLASS_SUCCESS;
796 if (add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
798 LOG_BEGIN(ERROR_LOG | 1);
799 LOG("AuthPriv: Could not add default protocol AuthSHA.");
802 ret = SNMP_CLASS_ERROR;
805 if (add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
807 LOG_BEGIN(ERROR_LOG | 1);
808 LOG("AuthPriv: Could not add default protocol AuthMD5.");
811 ret = SNMP_CLASS_ERROR;
814 if (add_priv(new PrivDES()) != SNMP_ERROR_SUCCESS)
816 LOG_BEGIN(ERROR_LOG | 1);
817 LOG("AuthPriv: Could not add default protocol PrivDES.");
820 ret = SNMP_CLASS_ERROR;
824 if (add_priv(new PrivIDEA()) != SNMP_ERROR_SUCCESS)
826 LOG_BEGIN(ERROR_LOG | 1);
827 LOG("AuthPriv: Could not add default protocol PrivIDEA.");
830 ret = SNMP_CLASS_ERROR;
834 #if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
835 if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES128)) != SNMP_ERROR_SUCCESS)
837 LOG_BEGIN(ERROR_LOG | 1);
838 LOG("AuthPriv: Could not add default protocol PrivAES 128.");
841 ret = SNMP_CLASS_ERROR;
844 if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES192)) != SNMP_ERROR_SUCCESS)
846 LOG_BEGIN(ERROR_LOG | 1);
847 LOG("AuthPriv: Could not add default protocol PrivAES 192.");
850 ret = SNMP_CLASS_ERROR;
853 if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES256)) != SNMP_ERROR_SUCCESS)
855 LOG_BEGIN(ERROR_LOG | 1);
856 LOG("AuthPriv: Could not add default protocol PrivAES 256.");
859 ret = SNMP_CLASS_ERROR;
864 if (add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
866 LOG_BEGIN(ERROR_LOG | 1);
867 LOG("AuthPriv: Could not add default protocol Priv3DES_EDE.");
870 ret = SNMP_CLASS_ERROR;
875 if (ret == SNMP_CLASS_SUCCESS)
877 LOG_BEGIN(INFO_LOG | 3);
878 LOG("AuthPriv: Added default Auth and Priv protocols.");
885 int AuthPriv::get_auth_params_len(const int auth_prot)
887 Auth *a = get_auth(auth_prot);
892 return a->get_auth_params_len();
895 int AuthPriv::get_priv_params_len(const int priv_prot)
897 Priv *p = get_priv(priv_prot);
902 return p->get_priv_params_len();
905 int AuthPriv::auth_out_msg(const int auth_prot,
906 const unsigned char *key,
909 unsigned char *auth_par_ptr)
911 if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
912 return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
914 Auth *a = get_auth(auth_prot);
917 return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
919 return a->auth_out_msg(key, msg, msg_len, auth_par_ptr);
922 int AuthPriv::auth_inc_msg(const int auth_prot,
923 const unsigned char *key,
926 unsigned char *auth_par_ptr,
927 const int auth_par_len)
929 if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
930 return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
932 Auth *a = get_auth(auth_prot);
935 return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
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))
941 LOG_BEGIN(WARNING_LOG | 1);
942 LOG("AuthPriv: Authentication data is not within message (msg start) (len) (auth start) (len)");
949 return SNMPv3_USM_ERROR;
953 return a->auth_inc_msg(key, msg, msg_len, auth_par_ptr, auth_par_len);
956 /* ========================================================== */
958 /* ----------------------- AuthSHA ---------------------------------------*/
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,
965 unsigned int *key_len)
967 *key_len = 20; /* All SHA keys have 20 bytes length */
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());
976 SHAHashStateType sha_hash_state;
977 unsigned char *cp, password_buf[72];
978 unsigned long password_index = 0;
979 unsigned long count = 0, i;
981 SHA1_INIT(&sha_hash_state); /* initialize SHA */
983 /**********************************************/
984 /* Use while loop until we've done 1 Megabyte */
985 /**********************************************/
986 while (count < 1048576) {
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];
996 SHA1_PROCESS(&sha_hash_state, password_buf, 64);
1000 SHA1_DONE(&sha_hash_state, key); /* tell SHA we're done */
1003 debughexcprintf(21, "key", key, *key_len);
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);
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);
1021 debughexcprintf(21, "localized key", key, *key_len);
1024 return SNMPv3_USM_OK;
1027 int AuthSHA::hash(const unsigned char *data,
1028 const unsigned int data_len,
1029 unsigned char *digest) const
1031 SHAHashStateType sha_hash_state;
1033 SHA1_INIT(&sha_hash_state);
1034 SHA1_PROCESS(&sha_hash_state, data, data_len);
1035 SHA1_DONE(&sha_hash_state, digest);
1037 return SNMPv3_USM_OK;
1040 int AuthSHA::auth_out_msg(const unsigned char *key,
1043 unsigned char *auth_par_ptr)
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 */
1051 memset((char*)(auth_par_ptr), 0, 12);
1054 debughexcprintf(21, "key", key, 16);
1058 * the HMAC_SHA transform looks like:
1060 * SHA(K XOR opad, SHA(K XOR ipad, msg))
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
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);
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];
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 */
1090 debughexcprintf(21,"digest", digest, 160 / 8);
1093 memcpy(auth_par_ptr, digest, 12);
1095 return SNMPv3_USM_OK;
1099 int AuthSHA::auth_inc_msg(const unsigned char *key,
1102 unsigned char *auth_par_ptr,
1103 const int auth_par_len)
1105 unsigned char receivedDigest[20];
1107 if (auth_par_len != 12)
1109 debugprintf(4, "SHA illegal digest length (%d), authentication FAILED.",
1111 return SNMPv3_USM_AUTHENTICATION_FAILURE;
1115 debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
1116 debughexcprintf(21, "key", key, 20);
1119 /* Save received digest */
1120 memcpy(receivedDigest, auth_par_ptr, 12);
1122 if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
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;
1130 /* compare digest to received digest */
1131 for (int i=0; i < 12 ; ++i)
1133 if (auth_par_ptr[i] != receivedDigest[i])
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;
1141 debugprintf(4, "SHA authentication OK.");
1142 return SNMPv3_USM_OK;
1146 /* ----------------------- AuthMD5 ---------------------------------------*/
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,
1153 unsigned int *key_len)
1155 *key_len = 16; /* All MD5 keys have 16 bytes length */
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());
1164 MD5HashStateType md5_hash_state;
1165 unsigned char *cp, password_buf[65];
1166 unsigned long password_index = 0;
1167 unsigned long count = 0, i;
1169 MD5_INIT(&md5_hash_state); /* initialize MD5 */
1171 /**********************************************/
1172 /* Use while loop until we've done 1 Megabyte */
1173 /**********************************************/
1174 while (count < 1048576) {
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];
1183 MD5_PROCESS(&md5_hash_state, password_buf, 64);
1186 MD5_DONE(&md5_hash_state, key); /* tell MD5 we're done */
1189 debughexcprintf(21, "key", key, *key_len);
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);
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);
1207 debughexcprintf(21, "localized key", key, *key_len);
1210 return SNMPv3_USM_OK;
1213 int AuthMD5::hash(const unsigned char *data,
1214 const unsigned int data_len,
1215 unsigned char *digest) const
1217 MD5HashStateType md5_hash_state;
1219 MD5_INIT(&md5_hash_state);
1220 MD5_PROCESS(&md5_hash_state, data, data_len);
1221 MD5_DONE(&md5_hash_state, digest);
1223 return SNMPv3_USM_OK;
1226 int AuthMD5::auth_out_msg(const unsigned char *key,
1229 unsigned char *auth_par_ptr)
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 */
1237 memset((char*)(auth_par_ptr), 0, 12);
1240 debughexcprintf(21, "key", key, 16);
1244 * the HMAC_MD5 transform looks like:
1246 * MD5(K XOR opad, MD5(K XOR ipad, msg))
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
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);
1260 /* XOR key with ipad and opad values */
1261 for (int i=0; i<64; i++) {
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 */
1278 debughexcprintf(21, "digest", digest, 128 / 8);
1281 memcpy(auth_par_ptr, digest, 12);
1283 return SNMPv3_USM_OK;
1286 int AuthMD5::auth_inc_msg(const unsigned char *key,
1289 unsigned char *auth_par_ptr,
1290 const int auth_par_len)
1292 unsigned char receivedDigest[16];
1294 if (auth_par_len != 12)
1296 debugprintf(4, "MD5 illegal digest length (%d), authentication FAILED.",
1298 return SNMPv3_USM_AUTHENTICATION_FAILURE;
1302 debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
1303 debughexcprintf(21, "key", key, 16);
1306 memcpy(receivedDigest, auth_par_ptr, 12);
1308 if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
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;
1316 /* compare digest to received digest */
1317 for (int i=0; i < 12 ; ++i)
1319 if (auth_par_ptr[i] != receivedDigest[i])
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;
1327 debugprintf(4, "MD5 authentication OK.");
1328 return SNMPv3_USM_OK;
1331 /* ========================= PRIV ================================*/
1333 /* ----------------------- PrivDES ---------------------------------------*/
1335 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1338 cipher = find_cipher("des");
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*/)
1353 unsigned char initVect[8];
1354 pp_uint64 my_salt = (*salt)++;
1356 #ifdef INVALID_ENCRYPTION
1357 debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1361 /* check space in privacy_params buffer */
1362 if (*privacy_params_len < 8)
1364 debugprintf(4, "Buffer too small: should be 8, is (%i).",
1365 *privacy_params_len);
1366 return SNMPv3_USM_ENCRYPTION_ERROR;
1368 /* Length is always 8 */
1369 *privacy_params_len = 8;
1371 // last 8 bytes of key are used as base for initialization vector
1372 memcpy((char*)initVect, key+8, 8);
1374 // put salt in privacy_params
1375 for (int j=0; j<4; j++)
1377 privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
1378 privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
1381 // xor initVect with salt
1382 for (int i=0; i<8; i++)
1383 initVect[i] ^= privacy_params[i];
1386 debughexcprintf(21, "apDESEncryptData: Data to encrypt",
1387 buffer, buffer_len);
1388 debughexcprintf(21, "apDESEncryptData: used key (only 8 bytes used)",
1390 debughexcprintf(21, "apDESEncryptData: used iv",
1395 DES_CBC_START_ENCRYPT(cipher, initVect, key, 8, 16, symcbc);
1397 for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
1398 DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
1401 /* last part of buffer */
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);
1414 *out_buffer_len = buffer_len;
1416 /* Clear context buffer (paranoia!)*/
1417 DES_MEMSET(symcbc, 0, sizeof(symcbc));
1420 debughexcprintf(21, "apDESEncryptData: created privacy_params",
1422 debughexcprintf(21, "apDESEncryptData: encrypted Data",
1423 out_buffer, *out_buffer_len);
1426 return SNMPv3_USM_OK;
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*/)
1442 unsigned char initVect[8];
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;
1448 for (int i=0; i<8; i++)
1449 initVect[i] = privacy_params[i] ^ key[i+8];
1451 memset((char*)outBuffer, 0, *outBuffer_len);
1454 debughexcprintf(21, "apDESDecryptData: Data to decrypt",
1455 buffer, buffer_len);
1456 debughexcprintf(21, "apDESDecryptData: used key (only 8 bytes used)",
1458 debughexcprintf(21, "apDESDecryptData: used privacy_params",
1460 debughexcprintf(21, "apDESDecryptData: used iv",
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);
1469 /* Clear context (paranoia!) */
1470 DES_MEMSET(symcbc, 0, sizeof(symcbc));
1472 *outBuffer_len = buffer_len;
1475 debughexcprintf(21, "apDESDecryptData: decrypted Data",
1476 outBuffer, *outBuffer_len);
1479 return SNMPv3_USM_OK;
1483 /* ----------------------- PrivIDEA --------------------------------------*/
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*/)
1498 IDEAContext CFB_Context;
1499 pp_uint64 my_salt = (*salt)++;
1501 #ifdef INVALID_ENCRYPTION
1502 debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1506 /* check space in privacy_params buffer */
1507 if (*privacy_params_len < 8)
1509 debugprintf(4, "Buffer too small: should be 8, is (%i).", *privacy_params_len);
1510 return SNMPv3_USM_ENCRYPTION_ERROR;
1512 /* Length is always 8 */
1513 *privacy_params_len = 8;
1515 // last 8 bytes of key are used as base for initialization vector
1516 unsigned char iv[8];
1518 memcpy((char*)iv, key+8, 8);
1520 // put salt in privacy_params
1521 for (int j=0; j<4; j++)
1523 privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
1524 privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
1526 // xor iv with privacy_params
1527 for (int i=0; i<8; i++)
1528 iv[i] ^= privacy_params[i];
1530 idea_set_key(&CFB_Context, key);
1532 idea_cfb_encrypt(&CFB_Context, iv, out_buffer,
1533 buffer, buffer_len);
1535 /* Clear context (paranoia!) */
1536 idea_destroy_context(&CFB_Context);
1538 *out_buffer_len = buffer_len;
1541 debughexcprintf(21, "apIDEAEncryptData: Data to encrypt",
1542 buffer, buffer_len);
1543 debughexcprintf(21, "apIDEAEncryptData: key",
1545 debughexcprintf(21, "apIDEAEncryptData: privacy_params",
1547 debughexcprintf(21, "apIDEAEncryptData: encrypted Data",
1548 out_buffer, *out_buffer_len);
1551 return SNMPv3_USM_OK;
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*/)
1565 unsigned char iv[8];
1566 IDEAContext CFB_Context;
1568 /* privacy params length has to be 8 */
1569 if (privacy_params_len != 8)
1570 return SNMPv3_USM_DECRYPTION_ERROR;
1572 idea_set_key(&CFB_Context, key);
1574 memset((char*)out_buffer, 0, *out_buffer_len);
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];
1581 idea_cfb_decrypt(&CFB_Context, iv, out_buffer,
1582 buffer, buffer_len);
1584 /* Clear context (paranoia!) */
1585 idea_destroy_context(&CFB_Context);
1586 memset((char*)iv, 0, 8);
1588 *out_buffer_len = buffer_len;
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);
1599 return SNMPv3_USM_OK;
1604 #if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
1606 PrivAES::PrivAES(const int aes_type_)
1607 : aes_type(aes_type_)
1609 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1610 cipher = find_cipher("rijndael");
1615 case SNMP_PRIVPROTOCOL_AES128:
1619 case SNMP_PRIVPROTOCOL_AES192:
1623 case SNMP_PRIVPROTOCOL_AES256:
1628 debugprintf(0, "Wrong AES type: %i.", aes_type);
1631 aes_type = -1; // will cause an error in AuthPriv::add_priv()
1634 unsigned int testswap = htonl(0x01020304);
1635 if (testswap == 0x01020304)
1636 need_byteswap = FALSE;
1638 need_byteswap = TRUE;
1641 const char *PrivAES::get_id_string() const
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;
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)
1663 unsigned char initVect[16];
1664 pp_uint64 my_salt = (*salt)++;
1666 #ifdef INVALID_ENCRYPTION
1667 debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1671 /* check space in privacy_params buffer */
1672 if (*privacy_params_len < 8)
1674 debugprintf(4, "Buffer too small: should be 8, is (%i).",
1675 *privacy_params_len);
1676 return SNMPv3_USM_ENCRYPTION_ERROR;
1678 /* Length is always 8 */
1679 *privacy_params_len = 8;
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);
1687 *tmpi++ = htonl(my_salt & 0xFFFFFFFF);
1688 *tmpi = htonl((my_salt >> 32) & 0xFFFFFFFF);
1691 memcpy(tmpi, &my_salt, 8);
1693 /* put byteswapped salt in privacy_params */
1694 memcpy(privacy_params, initVect + 8, 8);
1695 debughexcprintf(21, "aes initVect:", initVect, 16);
1701 if (AES_set_encrypt_key(key, key_len * 8, &symcfb) < 0)
1704 debugprintf(1, "AES_set_encrypt_key(%p, %d, %p) failed.",
1705 key, key_len * 8, &symcfb);
1706 return SNMPv3_USM_ERROR;
1709 AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
1710 &symcfb, initVect, &dummy, AES_ENCRYPT);
1712 symmetric_CFB symcfb;
1714 cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
1715 cfb_encrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
1718 /* Clear context and plaintext buffer (paranoia!)*/
1719 memset(&symcfb, 0, sizeof(symcfb));
1721 *out_buffer_len = buffer_len;
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",
1728 debughexcprintf(21, "aes EncryptData: encrypted Data",
1729 out_buffer, *out_buffer_len);
1732 return SNMPv3_USM_OK;
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)
1746 unsigned char initVect[16];
1748 /* Privacy params length has to be 8 */
1749 if (privacy_params_len != 8)
1750 return SNMPv3_USM_DECRYPTION_ERROR;
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);
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);
1768 symmetric_CFB symcfb;
1770 cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
1771 cfb_decrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
1774 /* Clear context and plaintext buffer (paranoia!)*/
1775 memset(&symcfb, 0, sizeof(symcfb));
1777 *out_buffer_len = buffer_len;
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",
1784 debughexcprintf(21, "aes DecryptData: decrypted Data",
1785 out_buffer, *out_buffer_len);
1788 return SNMPv3_USM_OK;
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,
1796 unsigned int *key_len,
1797 const unsigned int max_key_len,
1800 if (max_key_len < (unsigned)key_bytes)
1801 return SNMPv3_USM_ERROR;
1804 unsigned char *hash_buf = new unsigned char[auth->get_hash_len()];
1808 debugprintf(0, "Out of mem. Did not get %i bytes.", auth->get_hash_len());
1809 return SNMPv3_USM_ERROR;
1812 while (*key_len < (unsigned)key_bytes)
1814 res = auth->hash(key, *key_len, hash_buf);
1815 if (res != SNMPv3_USM_OK)
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;
1827 if (hash_buf) delete [] hash_buf;
1833 #endif // _USE_LIBTOMCRYPT or _USE_OPENSSL
1836 #ifdef _USE_3DES_EDE
1838 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1839 Priv3DES_EDE::Priv3DES_EDE()
1841 cipher = find_cipher("3des");
1842 debugprintf(10, "tomcrypt returned cipher %d", cipher);
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)
1859 unsigned char initVect[8];
1860 pp_uint64 my_salt = (*salt)++;
1862 #ifdef INVALID_ENCRYPTION
1863 debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
1867 /* check space in privacy_params buffer */
1868 if (*privacy_params_len < 8)
1870 debugprintf(4, "Buffer too small: should be 8, is (%i).",
1871 *privacy_params_len);
1872 return SNMPv3_USM_ENCRYPTION_ERROR;
1874 /* Length is always 8 */
1875 *privacy_params_len = 8;
1877 /* check key length */
1878 if (key_len < TRIPLEDES_EDE_KEY_LEN)
1880 debugprintf(4, "Key too small: should be %d, is (%d).",
1881 TRIPLEDES_EDE_KEY_LEN, key_len);
1882 return SNMPv3_USM_ENCRYPTION_ERROR;
1885 /* TODO: check if K1 != K2 != K3 */
1887 // last 8 bytes of key are used as base for initialization vector
1888 memcpy((char*)initVect, key+24, 8);
1890 /* TODO: generate salt as specified in draft */
1892 // put salt in privacy_params
1893 for (int j=0; j<4; j++)
1895 privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
1896 privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
1899 // xor initVect with salt
1900 for (int i=0; i<8; i++)
1901 initVect[i] ^= privacy_params[i];
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);
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
1914 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
1916 DES_CBC_START_ENCRYPT(cipher, initVect, key, 24, 16, symcbc);
1918 for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
1919 DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
1922 /* last part of buffer */
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);
1935 *out_buffer_len = buffer_len;
1937 /* Clear context buffer (paranoia!)*/
1938 DES_MEMSET(symcbc, 0, sizeof(symcbc));
1941 DESCBCType ks1, ks2, ks3;
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))
1947 debugprintf(0, "Starting 3DES-EDE encryption failed.");
1948 return SNMPv3_USM_ERROR;
1951 if (buffer_len >= 8)
1952 for(unsigned int k = 0; k <= (buffer_len - 8); k += 8)
1954 DES_EDE3_CBC_ENCRYPT(buffer+k, out_buffer+k, 8,
1955 ks1, ks2, ks3, initVect);
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);
1970 *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
1973 *out_buffer_len = buffer_len;
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));
1982 debughexcprintf(21, "3DES created privacy_params", privacy_params, 8);
1983 debughexcprintf(21, "3DES encrypted Data", out_buffer, *out_buffer_len);
1986 return SNMPv3_USM_OK;
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)
2002 unsigned char initVect[8];
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;
2008 for (int i=0; i<8; i++)
2009 initVect[i] = privacy_params[i] ^ key[i+24];
2011 memset((char*)out_buffer, 0, *out_buffer_len);
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);
2020 #if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
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);
2026 /* Clear context (paranoia!) */
2027 DES_MEMSET(symcbc, 0, sizeof(symcbc));
2030 DESCBCType ks1, ks2, ks3;
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))
2036 debugprintf(0, "Starting 3DES-EDE decryption failed.");
2037 return SNMPv3_USM_ERROR;
2040 for(unsigned int k=0; k<buffer_len; k+=8 )
2042 DES_EDE3_CBC_DECRYPT(buffer+k, out_buffer+k, 8,
2043 ks1, ks2, ks3, initVect);
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));
2051 *out_buffer_len = buffer_len;
2054 debughexcprintf(21, "3DES decrypted Data", out_buffer, *out_buffer_len);
2057 return SNMPv3_USM_OK;
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,
2067 unsigned int *key_len,
2068 const unsigned int max_key_len,
2071 if (max_key_len < TRIPLEDES_EDE_KEY_LEN)
2072 return SNMPv3_USM_ERROR;
2074 unsigned int p2k_output_len = *key_len;
2075 unsigned char *p2k_buf = new unsigned char[p2k_output_len];
2078 if (!p2k_buf) return SNMPv3_USM_ERROR;
2080 while (*key_len < TRIPLEDES_EDE_KEY_LEN)
2082 unsigned int p2k_buf_len = p2k_output_len;
2084 res = auth->password_to_key(key, *key_len,
2085 engine_id, engine_id_len,
2086 p2k_buf, &p2k_buf_len);
2088 if (res != SNMPv3_USM_OK)
2091 unsigned int copy_bytes = TRIPLEDES_EDE_KEY_LEN - *key_len;
2093 if (copy_bytes > p2k_buf_len)
2094 copy_bytes = p2k_buf_len;
2096 if (*key_len + copy_bytes > max_key_len)
2097 copy_bytes = max_key_len - *key_len;
2099 memcpy(key + *key_len, p2k_buf, copy_bytes);
2101 *key_len += copy_bytes;
2104 if (p2k_buf) delete [] p2k_buf;
2110 bool Priv3DES_EDE::test()
2113 AuthPriv ap(status);
2114 if (status != SNMPv3_USM_OK)
2117 if (ap.add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
2119 debugprintf(0, "Error: could not add AuthSHA.");
2123 if (ap.add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
2125 debugprintf(0, "Error: could not add AuthMD5.");
2129 if (ap.add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
2131 debugprintf(0, "Error: could not add Priv3DES_EDE.");
2135 unsigned char password[11] = "maplesyrup";
2136 unsigned char engine_id[12];
2138 memset(engine_id, 0, 11);
2141 unsigned char key[TRIPLEDES_EDE_KEY_LEN];
2142 unsigned int key_len = TRIPLEDES_EDE_KEY_LEN;
2144 status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
2145 SNMP_PRIVPROTOCOL_3DESEDE,
2150 debughexcprintf(1, "result key 3DES SHA",
2153 key_len = TRIPLEDES_EDE_KEY_LEN;
2154 status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACMD5,
2155 SNMP_PRIVPROTOCOL_3DESEDE,
2160 debughexcprintf(1, "result key 3DES MD5",
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;
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);
2177 debughexcprintf(1, "encrypted text",
2178 enc_buffer, enc_buffer_len);
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);
2185 dec_buffer[dec_buffer_len] = 0;
2186 debugprintf(1, "decrypted text: %s",
2188 // TODO: check keys and return real value
2193 #endif // _USE_3DES_EDE
2196 #ifdef SNMP_PP_NAMESPACE
2197 }; // end of namespace Snmp_pp