fix outgoing QOS prios
[tomato.git] / release / src / router / snmp / snmplib / scapi.c
blobf8df6d31cc3ab53acfe81debc9ed62b9b2d91799
1 /*
2 * scapi.c
4 */
6 #include <net-snmp/net-snmp-config.h>
8 #include <sys/types.h>
9 #if HAVE_WINSOCK_H
10 #include <winsock.h>
11 #endif
12 #ifdef HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif
15 #if HAVE_STRING_H
16 #include <string.h>
17 #else
18 #include <strings.h>
19 #endif
20 #if TIME_WITH_SYS_TIME
21 # ifdef WIN32
22 # include <sys/timeb.h>
23 # else
24 # include <sys/time.h>
25 # endif
26 # include <time.h>
27 #else
28 # if HAVE_SYS_TIME_H
29 # include <sys/time.h>
30 # else
31 # include <time.h>
32 # endif
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
38 #if HAVE_DMALLOC_H
39 #include <dmalloc.h>
40 #endif
42 #include <net-snmp/types.h>
43 #include <net-snmp/output_api.h>
44 #include <net-snmp/utilities.h>
46 #ifdef USE_INTERNAL_MD5
47 #include <net-snmp/library/md5.h>
48 #endif
49 #include <net-snmp/library/snmp_api.h>
50 #include <net-snmp/library/callback.h>
51 #include <net-snmp/library/snmp_secmod.h>
52 #include <net-snmp/library/snmpusm.h>
53 #include <net-snmp/library/keytools.h>
54 #include <net-snmp/library/scapi.h>
55 #include <net-snmp/library/mib.h>
56 #include <net-snmp/library/transform_oids.h>
58 #ifdef USE_OPENSSL
59 #include <openssl/hmac.h>
60 #include <openssl/evp.h>
61 #include <openssl/rand.h>
62 #include <openssl/des.h>
63 #ifdef HAVE_AES
64 #include <openssl/aes.h>
65 #endif
67 #ifdef STRUCT_DES_KS_STRUCT_HAS_WEAK_KEY
68 /* these are older names for newer structures that exist in openssl .9.7 */
69 #define DES_key_schedule des_key_schedule
70 #define DES_cblock des_cblock
71 #define DES_key_sched des_key_sched
72 #define DES_ncbc_encrypt des_ncbc_encrypt
73 #define DES_cbc_encrypt des_cbc_encrypt
74 #define OLD_DES
75 #endif
77 #endif /* HAVE_OPENSSL */
79 #ifdef QUITFUN
80 #undef QUITFUN
81 #define QUITFUN(e, l) \
82 if (e != SNMPERR_SUCCESS) { \
83 rval = SNMPERR_SC_GENERAL_FAILURE; \
84 goto l ; \
86 #endif
90 * sc_get_properlength(oid *hashtype, u_int hashtype_len):
92 * Given a hashing type ("hashtype" and its length hashtype_len), return
93 * the length of the hash result.
95 * Returns either the length or SNMPERR_GENERR for an unknown hashing type.
97 int
98 sc_get_properlength(const oid * hashtype, u_int hashtype_len)
100 DEBUGTRACE;
102 * Determine transform type hash length.
104 if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
105 return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
106 } else if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
107 return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
109 return SNMPERR_GENERR;
113 /*******************************************************************-o-******
114 * sc_init
116 * Returns:
117 * SNMPERR_SUCCESS Success.
120 sc_init(void)
122 int rval = SNMPERR_SUCCESS;
124 #ifndef USE_OPENSSL
125 #ifdef USE_INTERNAL_MD5
126 struct timeval tv;
128 DEBUGTRACE;
130 gettimeofday(&tv, (struct timezone *) 0);
132 srandom(tv.tv_sec ^ tv.tv_usec);
133 #else
134 rval = SNMPERR_SC_NOT_CONFIGURED;
135 #endif
137 * XXX ogud: The only reason to do anything here with openssl is to
138 * * XXX ogud: seed random number generator
140 #endif /* ifndef USE_OPENSSL */
141 return rval;
142 } /* end sc_init() */
144 /*******************************************************************-o-******
145 * sc_random
147 * Parameters:
148 * *buf Pre-allocated buffer.
149 * *buflen Size of buffer.
151 * Returns:
152 * SNMPERR_SUCCESS Success.
155 sc_random(u_char * buf, size_t * buflen)
156 #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
158 int rval = SNMPERR_SUCCESS;
159 #ifdef USE_INTERNAL_MD5
160 int i;
161 int rndval;
162 u_char *ucp = buf;
163 #endif
165 DEBUGTRACE;
167 #ifdef USE_OPENSSL
168 RAND_bytes(buf, *buflen); /* will never fail */
169 #else /* USE_INTERNAL_MD5 */
171 * fill the buffer with random integers. Note that random()
172 * is defined in config.h and may not be truly the random()
173 * system call if something better existed
175 rval = *buflen - *buflen % sizeof(rndval);
176 for (i = 0; i < rval; i += sizeof(rndval)) {
177 rndval = random();
178 memcpy(ucp, &rndval, sizeof(rndval));
179 ucp += sizeof(rndval);
182 rndval = random();
183 memcpy(ucp, &rndval, *buflen % sizeof(rndval));
185 rval = SNMPERR_SUCCESS;
186 #endif /* USE_OPENSSL */
187 return rval;
189 } /* end sc_random() */
191 #else
192 _SCAPI_NOT_CONFIGURED
193 #endif /* */
194 /*******************************************************************-o-******
195 * sc_generate_keyed_hash
197 * Parameters:
198 * authtype Type of authentication transform.
199 * authtypelen
200 * *key Pointer to key (Kul) to use in keyed hash.
201 * keylen Length of key in bytes.
202 * *message Pointer to the message to hash.
203 * msglen Length of the message.
204 * *MAC Will be returned with allocated bytes containg hash.
205 * *maclen Length of the hash buffer in bytes; also indicates
206 * whether the MAC should be truncated.
208 * Returns:
209 * SNMPERR_SUCCESS Success.
210 * SNMPERR_GENERR All errs
213 * A hash of the first msglen bytes of message using a keyed hash defined
214 * by authtype is created and stored in MAC. MAC is ASSUMED to be a buffer
215 * of at least maclen bytes. If the length of the hash is greater than
216 * maclen, it is truncated to fit the buffer. If the length of the hash is
217 * less than maclen, maclen set to the number of hash bytes generated.
219 * ASSUMED that the number of hash bits is a multiple of 8.
222 sc_generate_keyed_hash(const oid * authtype, size_t authtypelen,
223 u_char * key, u_int keylen,
224 u_char * message, u_int msglen,
225 u_char * MAC, size_t * maclen)
226 #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
228 int rval = SNMPERR_SUCCESS;
229 int properlength;
231 u_char buf[SNMP_MAXBUF_SMALL];
232 #if defined(USE_OPENSSL)
233 int buf_len = sizeof(buf);
234 #endif
236 DEBUGTRACE;
238 #ifdef SNMP_TESTING_CODE
240 int i;
241 DEBUGMSG(("sc_generate_keyed_hash",
242 "sc_generate_keyed_hash(): key=0x"));
243 for (i = 0; i < keylen; i++)
244 DEBUGMSG(("sc_generate_keyed_hash", "%02x", key[i] & 0xff));
245 DEBUGMSG(("sc_generate_keyed_hash", " (%d)\n", keylen));
247 #endif /* SNMP_TESTING_CODE */
250 * Sanity check.
252 if (!authtype || !key || !message || !MAC || !maclen
253 || (keylen <= 0) || (msglen <= 0) || (*maclen <= 0)
254 || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
255 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
258 properlength = sc_get_properlength(authtype, authtypelen);
259 if (properlength == SNMPERR_GENERR)
260 return properlength;
262 if (((int) keylen < properlength)) {
263 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
265 #ifdef USE_OPENSSL
267 * Determine transform type.
269 if (ISTRANSFORM(authtype, HMACMD5Auth))
270 HMAC(EVP_md5(), key, keylen, message, msglen, buf, &buf_len);
271 else if (ISTRANSFORM(authtype, HMACSHA1Auth))
272 HMAC(EVP_sha1(), key, keylen, message, msglen, buf, &buf_len);
273 else {
274 QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
276 if (buf_len != properlength) {
277 QUITFUN(rval, sc_generate_keyed_hash_quit);
279 if (*maclen > buf_len)
280 *maclen = buf_len;
281 memcpy(MAC, buf, *maclen);
282 #else
283 if ((int) *maclen > properlength)
284 *maclen = properlength;
285 if (MDsign(message, msglen, MAC, *maclen, key, keylen)) {
286 rval = SNMPERR_GENERR;
287 goto sc_generate_keyed_hash_quit;
289 #endif /* USE_OPENSSL */
291 #ifdef SNMP_TESTING_CODE
293 char *s;
294 int len = binary_to_hex(MAC, *maclen, &s);
296 DEBUGMSGTL(("scapi", "Full v3 message hash: %s\n", s));
297 SNMP_ZERO(s, len);
298 SNMP_FREE(s);
300 #endif
302 sc_generate_keyed_hash_quit:
303 SNMP_ZERO(buf, SNMP_MAXBUF_SMALL);
304 return rval;
305 } /* end sc_generate_keyed_hash() */
307 #else
308 _SCAPI_NOT_CONFIGURED
309 #endif /* */
311 * sc_hash(): a generic wrapper around whatever hashing package we are using.
313 * IN:
314 * hashtype - oid pointer to a hash type
315 * hashtypelen - length of oid pointer
316 * buf - u_char buffer to be hashed
317 * buf_len - integer length of buf data
318 * MAC_len - length of the passed MAC buffer size.
320 * OUT:
321 * MAC - pre-malloced space to store hash output.
322 * MAC_len - length of MAC output to the MAC buffer.
324 * Returns:
325 * SNMPERR_SUCCESS Success.
326 * SNMP_SC_GENERAL_FAILURE Any error.
329 sc_hash(const oid * hashtype, size_t hashtypelen, u_char * buf,
330 size_t buf_len, u_char * MAC, size_t * MAC_len)
331 #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
333 #ifdef USE_OPENSSL
334 int rval = SNMPERR_SUCCESS;
335 const EVP_MD *hashfn;
336 EVP_MD_CTX ctx, *cptr;
337 #endif
339 DEBUGTRACE;
341 if (hashtype == NULL || hashtypelen < 0 || buf == NULL ||
342 buf_len < 0 || MAC == NULL || MAC_len == NULL ||
343 (int) (*MAC_len) < sc_get_properlength(hashtype, hashtypelen))
344 return (SNMPERR_GENERR);
346 #ifdef USE_OPENSSL
348 * Determine transform type.
350 if (ISTRANSFORM(hashtype, HMACMD5Auth)) {
351 hashfn = (const EVP_MD *) EVP_md5();
352 } else if (ISTRANSFORM(hashtype, HMACSHA1Auth)) {
353 hashfn = (const EVP_MD *) EVP_sha1();
354 } else {
355 return (SNMPERR_GENERR);
358 /** initialize the pointer */
359 memset(&ctx, 0, sizeof(ctx));
360 cptr = &ctx;
361 #if defined(OLD_DES)
362 EVP_DigestInit(cptr, hashfn);
363 #else /* !OLD_DES */
364 /* this is needed if the runtime library is different than the compiled
365 library since the openssl versions are very different. */
366 if (SSLeay() < 0x907000) {
367 /* the old version of the struct was bigger and thus more
368 memory is needed. should be 152, but we use 256 for safety. */
369 cptr = malloc(256);
370 EVP_DigestInit(cptr, hashfn);
371 } else {
372 EVP_MD_CTX_init(cptr);
373 EVP_DigestInit(cptr, hashfn);
375 #endif
377 /** pass the data */
378 EVP_DigestUpdate(cptr, buf, buf_len);
380 /** do the final pass */
381 #if defined(OLD_DES)
382 EVP_DigestFinal(cptr, MAC, MAC_len);
383 #else /* !OLD_DES */
384 if (SSLeay() < 0x907000) {
385 EVP_DigestFinal(cptr, MAC, MAC_len);
386 free(cptr);
387 } else {
388 EVP_DigestFinal_ex(cptr, MAC, MAC_len);
389 EVP_MD_CTX_cleanup(cptr);
391 #endif
392 return (rval);
393 #else /* USE_INTERNAL_MD5 */
395 if (MDchecksum(buf, buf_len, MAC, *MAC_len)) {
396 return SNMPERR_GENERR;
398 if (*MAC_len > 16)
399 *MAC_len = 16;
400 return SNMPERR_SUCCESS;
402 #endif /* USE_OPENSSL */
404 #else /* !defined(USE_OPENSSL) && !defined(USE_INTERNAL_MD5) */
405 _SCAPI_NOT_CONFIGURED
406 #endif /* !defined(USE_OPENSSL) && !defined(USE_INTERNAL_MD5) */
407 /*******************************************************************-o-******
408 * sc_check_keyed_hash
410 * Parameters:
411 * authtype Transform type of authentication hash.
412 * *key Key bits in a string of bytes.
413 * keylen Length of key in bytes.
414 * *message Message for which to check the hash.
415 * msglen Length of message.
416 * *MAC Given hash.
417 * maclen Length of given hash; indicates truncation if it is
418 * shorter than the normal size of output for
419 * given hash transform.
420 * Returns:
421 * SNMPERR_SUCCESS Success.
422 * SNMP_SC_GENERAL_FAILURE Any error
425 * Check the hash given in MAC against the hash of message. If the length
426 * of MAC is less than the length of the transform hash output, only maclen
427 * bytes are compared. The length of MAC cannot be greater than the
428 * length of the hash transform output.
431 sc_check_keyed_hash(const oid * authtype, size_t authtypelen,
432 u_char * key, u_int keylen,
433 u_char * message, u_int msglen,
434 u_char * MAC, u_int maclen)
435 #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL)
437 int rval = SNMPERR_SUCCESS;
438 size_t buf_len = SNMP_MAXBUF_SMALL;
440 u_char buf[SNMP_MAXBUF_SMALL];
442 DEBUGTRACE;
444 #ifdef SNMP_TESTING_CODE
446 int i;
447 DEBUGMSG(("scapi", "sc_check_keyed_hash(): key=0x"));
448 for (i = 0; i < keylen; i++)
449 DEBUGMSG(("scapi", "%02x", key[i] & 0xff));
450 DEBUGMSG(("scapi", " (%d)\n", keylen));
452 #endif /* SNMP_TESTING_CODE */
455 * Sanity check.
457 if (!authtype || !key || !message || !MAC
458 || (keylen <= 0) || (msglen <= 0) || (maclen <= 0)
459 || (authtypelen != USM_LENGTH_OID_TRANSFORM)) {
460 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
465 * Generate a full hash of the message, then compare
466 * the result with the given MAC which may shorter than
467 * the full hash length.
469 rval = sc_generate_keyed_hash(authtype, authtypelen,
470 key, keylen,
471 message, msglen, buf, &buf_len);
472 QUITFUN(rval, sc_check_keyed_hash_quit);
474 if (maclen > msglen) {
475 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
477 } else if (memcmp(buf, MAC, maclen) != 0) {
478 QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
482 sc_check_keyed_hash_quit:
483 SNMP_ZERO(buf, SNMP_MAXBUF_SMALL);
485 return rval;
487 } /* end sc_check_keyed_hash() */
489 #else
490 _SCAPI_NOT_CONFIGURED
491 #endif /* USE_INTERNAL_MD5 */
492 /*******************************************************************-o-******
493 * sc_encrypt
495 * Parameters:
496 * privtype Type of privacy cryptographic transform.
497 * *key Key bits for crypting.
498 * keylen Length of key (buffer) in bytes.
499 * *iv IV bits for crypting.
500 * ivlen Length of iv (buffer) in bytes.
501 * *plaintext Plaintext to crypt.
502 * ptlen Length of plaintext.
503 * *ciphertext Ciphertext to crypt.
504 * *ctlen Length of ciphertext.
506 * Returns:
507 * SNMPERR_SUCCESS Success.
508 * SNMPERR_SC_NOT_CONFIGURED Encryption is not supported.
509 * SNMPERR_SC_GENERAL_FAILURE Any other error
512 * Encrypt plaintext into ciphertext using key and iv.
514 * ctlen contains actual number of crypted bytes in ciphertext upon
515 * successful return.
518 sc_encrypt(const oid * privtype, size_t privtypelen,
519 u_char * key, u_int keylen,
520 u_char * iv, u_int ivlen,
521 u_char * plaintext, u_int ptlen,
522 u_char * ciphertext, size_t * ctlen)
523 #if defined(USE_OPENSSL)
525 int rval = SNMPERR_SUCCESS;
526 u_int properlength, properlength_iv;
527 u_char pad_block[128]; /* bigger than anything I need */
528 u_char my_iv[128]; /* ditto */
529 int pad, plast, pad_size;
530 #ifdef OLD_DES
531 DES_key_schedule key_sch;
532 #else
533 DES_key_schedule key_sched_store;
534 DES_key_schedule *key_sch = &key_sched_store;
535 #endif
536 DES_cblock key_struct;
537 #ifdef HAVE_AES
538 AES_KEY aes_key;
539 int new_ivlen = 0;
540 #endif
542 DEBUGTRACE;
545 * Sanity check.
547 #if !defined(SCAPI_AUTHPRIV)
548 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
549 return SNMPERR_SC_NOT_CONFIGURED;
550 #endif
552 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
553 || (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)
554 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
555 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
556 } else if (ptlen > *ctlen) {
557 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
559 #ifdef SNMP_TESTING_CODE
561 size_t buf_len = 128, out_len = 0;
562 u_char *buf = (u_char *) malloc(buf_len);
564 if (buf != NULL) {
565 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
566 iv, ivlen)) {
567 DEBUGMSGTL(("scapi", "encrypt: IV: %s/", buf));
568 } else {
569 DEBUGMSGTL(("scapi", "encrypt: IV: %s [TRUNCATED]/", buf));
571 out_len = 0;
572 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
573 key, keylen)) {
574 DEBUGMSG(("scapi", "%s\n", buf));
575 } else {
576 DEBUGMSG(("scapi", "%s [TRUNCATED]\n", buf));
578 out_len = 0;
579 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
580 plaintext, 16)) {
581 DEBUGMSGTL(("scapi", "encrypt: string: %s\n", buf));
582 } else {
583 DEBUGMSGTL(("scapi", "encrypt: string: %s [TRUNCATED]\n",
584 buf));
586 free(buf);
587 } else {
588 DEBUGMSGTL(("scapi",
589 "encrypt: malloc fail for debug output\n"));
592 #endif /* SNMP_TESTING_CODE */
596 * Determine privacy transform.
598 if (ISTRANSFORM(privtype, DESPriv)) {
599 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
600 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
601 pad_size = properlength;
602 #ifdef HAVE_AES
603 } else if (ISTRANSFORM(privtype, AES128Priv)) {
604 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES128);
605 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES128_IV);
606 } else if (ISTRANSFORM(privtype, AES192Priv)) {
607 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES192);
608 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES192_IV);
609 } else if (ISTRANSFORM(privtype, AES256Priv)) {
610 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES256);
611 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES256_IV);
612 #endif
613 } else {
614 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
617 if ((keylen < properlength) || (ivlen < properlength_iv)) {
618 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
621 memset(my_iv, 0, sizeof(my_iv));
623 if (ISTRANSFORM(privtype, DESPriv)) {
626 * now calculate the padding needed
628 pad = pad_size - (ptlen % pad_size);
629 plast = (int) ptlen - (pad_size - pad);
630 if (pad == pad_size)
631 pad = 0;
632 if (ptlen + pad > *ctlen) {
633 QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); /* not enough space */
635 if (pad > 0) { /* copy data into pad block if needed */
636 memcpy(pad_block, plaintext + plast, pad_size - pad);
637 memset(&pad_block[pad_size - pad], pad, pad); /* filling in padblock */
640 memcpy(key_struct, key, sizeof(key_struct));
641 (void) DES_key_sched(&key_struct, key_sch);
643 memcpy(my_iv, iv, ivlen);
645 * encrypt the data
647 DES_ncbc_encrypt(plaintext, ciphertext, plast, key_sch,
648 (DES_cblock *) my_iv, DES_ENCRYPT);
649 if (pad > 0) {
651 * then encrypt the pad block
653 DES_ncbc_encrypt(pad_block, ciphertext + plast, pad_size,
654 key_sch, (DES_cblock *) my_iv, DES_ENCRYPT);
655 *ctlen = plast + pad_size;
656 } else {
657 *ctlen = plast;
660 #ifdef HAVE_AES
661 else if (ISTRANSFORM(privtype, AES128Priv) ||
662 ISTRANSFORM(privtype, AES192Priv) ||
663 ISTRANSFORM(privtype, AES256Priv)) {
664 (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
666 memcpy(my_iv, iv, ivlen);
668 * encrypt the data
670 AES_cfb128_encrypt(plaintext, ciphertext, ptlen,
671 &aes_key, my_iv, &new_ivlen, AES_ENCRYPT);
672 *ctlen = ptlen;
674 #endif
675 sc_encrypt_quit:
677 * clear memory just in case
679 memset(my_iv, 0, sizeof(my_iv));
680 memset(pad_block, 0, sizeof(pad_block));
681 memset(key_struct, 0, sizeof(key_struct));
682 #ifdef OLD_DES
683 memset(&key_sch, 0, sizeof(key_sch));
684 #else
685 memset(&key_sched_store, 0, sizeof(key_sched_store));
686 #endif
687 #ifdef HAVE_AES
688 memset(&aes_key,0,sizeof(aes_key));
689 #endif
690 return rval;
692 } /* end sc_encrypt() */
694 #else
696 # if USE_INTERNAL_MD5
698 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
699 DEBUGMSGTL(("scapi", "Encrypt function not defined.\n"));
700 return SNMPERR_SC_GENERAL_FAILURE;
703 # else
704 _SCAPI_NOT_CONFIGURED
705 # endif /* USE_INTERNAL_MD5 */
707 #endif /* */
711 /*******************************************************************-o-******
712 * sc_decrypt
714 * Parameters:
715 * privtype
716 * *key
717 * keylen
718 * *iv
719 * ivlen
720 * *ciphertext
721 * ctlen
722 * *plaintext
723 * *ptlen
725 * Returns:
726 * SNMPERR_SUCCESS Success.
727 * SNMPERR_SC_NOT_CONFIGURED Encryption is not supported.
728 * SNMPERR_SC_GENERAL_FAILURE Any other error
731 * Decrypt ciphertext into plaintext using key and iv.
733 * ptlen contains actual number of plaintext bytes in plaintext upon
734 * successful return.
737 sc_decrypt(const oid * privtype, size_t privtypelen,
738 u_char * key, u_int keylen,
739 u_char * iv, u_int ivlen,
740 u_char * ciphertext, u_int ctlen,
741 u_char * plaintext, size_t * ptlen)
742 #ifdef USE_OPENSSL
745 int rval = SNMPERR_SUCCESS;
746 u_char my_iv[128];
747 #ifdef OLD_DES
748 DES_key_schedule key_sch;
749 #else
750 DES_key_schedule key_sched_store;
751 DES_key_schedule *key_sch = &key_sched_store;
752 #endif
753 DES_cblock key_struct;
754 u_int properlength, properlength_iv;
755 #ifdef HAVE_AES
756 int new_ivlen = 0;
757 AES_KEY aes_key;
758 #endif
760 DEBUGTRACE;
762 if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
763 || (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)
764 || (privtypelen != USM_LENGTH_OID_TRANSFORM)) {
765 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
767 #ifdef SNMP_TESTING_CODE
769 size_t buf_len = 128, out_len = 0;
770 u_char *buf = (u_char *) malloc(buf_len);
772 if (buf != NULL) {
773 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
774 iv, ivlen)) {
775 DEBUGMSGTL(("scapi", "decrypt: IV: %s/", buf));
776 } else {
777 DEBUGMSGTL(("scapi", "decrypt: IV: %s [TRUNCATED]/", buf));
779 out_len = 0;
780 if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
781 key, keylen)) {
782 DEBUGMSG(("scapi", "%s\n", buf));
783 } else {
784 DEBUGMSG(("scapi", "%s\n", buf));
786 free(buf);
787 } else {
788 DEBUGMSGTL(("scapi",
789 "decrypt: malloc fail for debug output\n"));
792 #endif /* SNMP_TESTING_CODE */
795 * Determine privacy transform.
797 if (ISTRANSFORM(privtype, DESPriv)) {
798 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
799 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
800 #ifdef HAVE_AES
801 } else if (ISTRANSFORM(privtype, AES128Priv)) {
802 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES128);
803 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES128_IV);
804 } else if (ISTRANSFORM(privtype, AES192Priv)) {
805 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES192);
806 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES192_IV);
807 } else if (ISTRANSFORM(privtype, AES256Priv)) {
808 properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_AES256);
809 properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_AES256_IV);
810 #endif
811 } else {
812 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
815 if ((keylen < properlength) || (ivlen < properlength_iv)) {
816 QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
819 memset(my_iv, 0, sizeof(my_iv));
820 if (ISTRANSFORM(privtype, DESPriv)) {
821 memcpy(key_struct, key, sizeof(key_struct));
822 (void) DES_key_sched(&key_struct, key_sch);
824 memcpy(my_iv, iv, ivlen);
825 DES_cbc_encrypt(ciphertext, plaintext, ctlen, key_sch,
826 (DES_cblock *) my_iv, DES_DECRYPT);
827 *ptlen = ctlen;
829 #ifdef HAVE_AES
830 else if (ISTRANSFORM(privtype, AES128Priv) ||
831 ISTRANSFORM(privtype, AES192Priv) ||
832 ISTRANSFORM(privtype, AES256Priv)) {
833 (void) AES_set_encrypt_key(key, properlength*8, &aes_key);
835 memcpy(my_iv, iv, ivlen);
837 * encrypt the data
839 AES_cfb128_encrypt(ciphertext, plaintext, ctlen,
840 &aes_key, my_iv, &new_ivlen, AES_DECRYPT);
841 *ptlen = ctlen;
843 #endif
846 * exit cond
848 sc_decrypt_quit:
849 #ifdef OLD_DES
850 memset(&key_sch, 0, sizeof(key_sch));
851 #else
852 memset(&key_sched_store, 0, sizeof(key_sched_store));
853 #endif
854 memset(key_struct, 0, sizeof(key_struct));
855 memset(my_iv, 0, sizeof(my_iv));
856 return rval;
858 #else /* USE OPEN_SSL */
860 #if !defined(SCAPI_AUTHPRIV)
861 snmp_log(LOG_ERR, "Encryption support not enabled.\n");
862 return SNMPERR_SC_NOT_CONFIGURED;
863 #else
864 # if USE_INTERNAL_MD5
866 DEBUGMSGTL(("scapi", "Decryption function not defined.\n"));
867 return SNMPERR_SC_GENERAL_FAILURE;
870 # else
871 _SCAPI_NOT_CONFIGURED
872 # endif /* USE_INTERNAL_MD5 */
873 #endif /* */
875 #endif /* USE_OPENSSL */