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