1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  package uk.co.westhawk.snmp.util;
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  import java.security.MessageDigest;
53  import java.security.NoSuchAlgorithmException;
54  import java.util.*;
55  
56  import uk.co.westhawk.snmp.stack.*;
57  
58  import org.bouncycastle.crypto.digests.*;
59  import org.bouncycastle.crypto.params.*;
60  import org.bouncycastle.crypto.engines.*;
61  
62  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.MD5_PROTOCOL;
63  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.SHA1_PROTOCOL;
64  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.SHA224_PROTOCOL;
65  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.SHA256_PROTOCOL;
66  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.SHA384_PROTOCOL;
67  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.SHA512_PROTOCOL;
68  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.AES_ENCRYPT;
69  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.AES192_ENCRYPT;
70  import static uk.co.westhawk.snmp.stack.SnmpContextv3Face.AES256_ENCRYPT;
71  import static uk.co.westhawk.snmp.stack.SnmpContextv3Basis.AES128_KEY_LENGTH;
72  import static uk.co.westhawk.snmp.stack.SnmpContextv3Basis.AES192_KEY_LENGTH;
73  import static uk.co.westhawk.snmp.stack.SnmpContextv3Basis.AES256_KEY_LENGTH;
74  
75  
76  
77  
78  
79  
80  
81  
82  public class SnmpUtilities extends Object {
83      
84  
85  
86      private static final String SHA256_ALGORITHM = "SHA-256";
87      
88  
89  
90      private static final String SHA512_ALGORITHM = "SHA-512";
91      
92  
93  
94      private static final String SHA224_ALGORITHM = "SHA-224";
95      
96  
97  
98      private static final String SHA384_ALGORITHM = "SHA-384";
99  
100     private static final String version_id = "@(#)$Id: SnmpUtilities.java,v 1.27 2009/03/05 12:57:57 birgita Exp $ Copyright Westhawk Ltd";
101 
102     final static int ONEMEG = 1048576;
103     final static int SALT_LENGTH = 8; 
104 
105     private static int salt_count = -1;
106     private static long asalt;
107 
108     
109     static byte[] dummySha1FingerPrint = new byte[12];
110 
111     
112     static byte[] dummySHA256FingerPrint = new byte[24];
113 
114     
115     static byte[] dummySHA512FingerPrint = new byte[48];
116 
117     
118     static byte[] dummySHA224FingerPrint = new byte[16];
119 
120     
121     static byte[] dummySHA384FingerPrint = new byte[32];
122 
123     private static final Map<Integer, byte[]> DUMMY_FINGERPRINT_MAP = new HashMap<>();
124     static {
125         DUMMY_FINGERPRINT_MAP.put(SnmpContextv3Basis.SHA256_PROTOCOL, dummySHA256FingerPrint);
126         DUMMY_FINGERPRINT_MAP.put(SnmpContextv3Basis.SHA1_PROTOCOL, dummySha1FingerPrint);
127         DUMMY_FINGERPRINT_MAP.put(SnmpContextv3Basis.MD5_PROTOCOL, dummySha1FingerPrint);
128         DUMMY_FINGERPRINT_MAP.put(SnmpContextv3Basis.SHA512_PROTOCOL, dummySHA512FingerPrint);
129         DUMMY_FINGERPRINT_MAP.put(SnmpContextv3Basis.SHA224_PROTOCOL, dummySHA224FingerPrint);
130         DUMMY_FINGERPRINT_MAP.put(SnmpContextv3Basis.SHA384_PROTOCOL, dummySHA384FingerPrint);
131     }
132 
133     
134 
135 
136 
137 
138 
139     public static String getSnmpVersionString(int version) {
140         String versionString;
141 
142         switch (version) {
143             case SnmpConstants.SNMP_VERSION_1:
144                 versionString = "SNMPv1";
145                 break;
146             case SnmpConstants.SNMP_VERSION_2c:
147                 versionString = "SNMPv2c";
148                 break;
149             case SnmpConstants.SNMP_VERSION_3:
150                 versionString = "SNMPv3";
151                 break;
152             default:
153                 versionString = "Unsupported version no " + version;
154         }
155         return versionString;
156     }
157 
158     
159 
160 
161 
162 
163 
164 
165 
166 
167 
168     public static byte[] toBytes(String hexStr) {
169         byte mask = (byte) 0x7F;
170         byte[] bytes = new byte[0];
171 
172         if (hexStr != null) {
173             hexStr = hexStr.toUpperCase();
174             int len = hexStr.length();
175             bytes = new byte[(len / 2)];
176             int sPos = 0; 
177             int bPos = 0; 
178             while (sPos < len) {
179                 char a = hexStr.charAt(sPos);
180                 char b = hexStr.charAt(sPos + 1);
181 
182                 int v1 = Character.digit(a, 16);
183                 int v2 = Character.digit(b, 16);
184                 int v3 = (int) (v1 * 16 + v2);
185                 bytes[bPos] = (byte) v3;
186 
187                 sPos += 2;
188                 bPos++;
189             }
190         }
191         return bytes;
192     }
193 
194     
195 
196 
197 
198 
199 
200 
201 
202 
203 
204     public static byte longToByte(long l) throws IllegalArgumentException {
205         byte ret = 0;
206         if ((l < 0) || (l > 255)) {
207             throw new IllegalArgumentException("Valid byte values are between 0 and 255."
208                     + "Got " + l);
209         }
210         ret = (byte) (l);
211         return ret;
212     }
213 
214     
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225     public static byte[] longToByte(long[] l) throws IllegalArgumentException {
226         int len = l.length;
227         byte[] ret = new byte[len];
228         for (int i = 0; i < len; i++) {
229             ret[i] = longToByte(l[i]);
230         }
231         return ret;
232     }
233 
234     
235 
236 
237 
238 
239 
240     public static void dumpBytes(String headerStr, byte[] bytes) {
241         StringBuffer buf = new StringBuffer(bytes.length);
242         buf.append("\n");
243         buf.append(headerStr).append("\n");
244         buf.append("bytes.length: ").append(bytes.length).append("\n");
245         int len = bytes.length;
246         int i = 0;
247         for (i = 0; i < len; i++) {
248             buf.append(toHex(bytes[i]) + " ");
249             if (0 == ((i + 1) % 8)) {
250                 buf.append("\n");
251             }
252         }
253         buf.append("\n");
254         System.out.println(buf.toString());
255     }
256 
257     
258 
259 
260 
261 
262 
263 
264 
265 
266     public static String toHexString(byte[] bytes) {
267         String str = "";
268         if (bytes != null) {
269             int len = bytes.length;
270             for (int i = 0; i < len; i++) {
271                 str += toHex(bytes[i]);
272             }
273         }
274         return str;
275     }
276 
277     
278 
279 
280 
281 
282 
283     public static String toHex(int val) {
284         int val1, val2;
285 
286         val1 = (val >> 4) & 0x0F;
287         val2 = (val & 0x0F);
288 
289         return ("" + HEX_DIGIT[val1] + HEX_DIGIT[val2]);
290     }
291 
292     final static char[] HEX_DIGIT = { '0', '1', '2', '3', '4', '5', '6', '7',
293             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
294 
295     
296 
297 
298 
299 
300 
301 
302     public static boolean areBytesEqual(byte[] array1, byte[] array2) {
303         boolean same = true;
304         int len1 = array1.length;
305         if (len1 == array2.length) {
306             int i = 0;
307             while (i < len1 && same) {
308                 same = (array1[i] == array2[i]);
309                 i++;
310             }
311         } else {
312             same = false;
313         }
314         return same;
315     }
316 
317     
318 
319 
320 
321 
322 
323 
324 
325 
326 
327 
328     public static byte[] getLocalizedKeyMD5(byte[] passwKey, String engineId) {
329         byte[] ret = null;
330         MD5Digest mdc = new MD5Digest();
331         mdc.reset();
332 
333         byte[] beid = toBytes(engineId);
334         if ((beid != null) && (passwKey != null)) {
335             
336             mdc.update(passwKey, 0, passwKey.length);
337             mdc.update(beid, 0, beid.length);
338             mdc.update(passwKey, 0, passwKey.length);
339             ret = new byte[mdc.getDigestSize()];
340             mdc.doFinal(ret, 0);
341         }
342         return ret;
343     }
344 
345     
346 
347 
348 
349 
350 
351 
352 
353     public static byte[] getLocalizedKeySHA1(byte[] passwKey, String engineId) {
354         byte[] ret = null;
355         SHA1Digest mdc = new SHA1Digest();
356         mdc.reset();
357 
358         byte[] beid = toBytes(engineId);
359         if ((beid != null) && (passwKey != null)) {
360             
361             mdc.update(passwKey, 0, passwKey.length);
362             mdc.update(beid, 0, beid.length);
363             mdc.update(passwKey, 0, passwKey.length);
364             ret = new byte[mdc.getDigestSize()];
365             mdc.doFinal(ret, 0);
366         }
367         return ret;
368     }
369 
370     
371 
372 
373 
374 
375 
376 
377 
378 
379 
380 
381     public static byte[] passwordToKeySHA1(String password) {
382         SHA1Digest sha;
383         byte[] ret = null;
384         sha = new SHA1Digest();
385         byte[] passwordBuf = new byte[64];
386         int pl = password.length();
387         byte[] pass = new byte[pl];
388 
389         
390         for (int i = 0; i < pl; i++) {
391             pass[i] = (byte) (0xFF & password.charAt(i));
392         }
393 
394         int count = 0;
395         int passwordIndex = 0;
396         Date then = (AsnObject.debug > 1) ? new Date() : null;
397 
398         synchronized (sha) {
399             while (count < ONEMEG) {
400                 int cp = 0;
401                 int i = 0;
402                 while (i < 64) {
403                     int pim = passwordIndex % pl;
404                     int len = 64 - cp;
405                     int pr = pl - pim;
406                     if (len > pr) {
407                         len = pr;
408                     }
409                     System.arraycopy(pass, pim, passwordBuf, cp, len);
410                     i += len;
411                     cp += len;
412                     passwordIndex += len;
413                 }
414 
415                 
416                 sha.update(passwordBuf, 0, passwordBuf.length);
417                 count += 64;
418             }
419             
420             ret = new byte[sha.getDigestSize()];
421             sha.doFinal(ret, 0);
422         }
423 
424         if (AsnObject.debug > 1) {
425             Date now = new Date();
426             long diff = now.getTime() - then.getTime();
427             System.out.println("(Complex) pass to key takes " + diff / 1000.0);
428         }
429 
430         return ret;
431     }
432 
433     
434 
435 
436 
437 
438 
439 
440 
441 
442 
443 
444     public static byte[] passwordToKeyMD5(String password) {
445         MD5Digest mdc;
446         byte[] ret = null;
447         mdc = new MD5Digest();
448         byte[] passwordBuf = new byte[64];
449         int pl = password.length();
450         byte[] pass = new byte[pl];
451 
452         
453         for (int i = 0; i < pl; i++) {
454             pass[i] = (byte) (0xFF & password.charAt(i));
455         }
456 
457         int count = 0;
458         int passwordIndex = 0;
459         Date then = (AsnObject.debug > 1) ? new Date() : null;
460         synchronized (mdc) {
461             while (count < ONEMEG) {
462                 int cp = 0;
463                 int i = 0;
464                 while (i < 64) {
465                     int pim = passwordIndex % pl;
466                     int len = 64 - cp;
467                     int pr = pl - pim;
468                     if (len > pr) {
469                         len = pr;
470                     }
471                     System.arraycopy(pass, pim, passwordBuf, cp, len);
472                     i += len;
473                     cp += len;
474                     passwordIndex += len;
475                 }
476                 mdc.update(passwordBuf, 0, passwordBuf.length);
477                 count += 64;
478             }
479             
480             ret = new byte[mdc.getDigestSize()];
481             mdc.doFinal(ret, 0);
482         }
483 
484         if (AsnObject.debug > 1) {
485             Date now = new Date();
486             long diff = now.getTime() - then.getTime();
487             System.out.println("(Complex) pass to key takes " + diff / 1000.0);
488         }
489 
490         return ret;
491     }
492 
493     
494 
495 
496 
497 
498 
499 
500     public final static byte[] getFingerPrintMD5(byte[] key, byte[] message) {
501         if ((AsnObject.debug > 5) && (key.length != 16)) {
502             System.out.println("MD5 key length wrong");
503         }
504         return getFingerPrint(key, message, false);
505     }
506 
507     
508 
509 
510 
511 
512 
513 
514     public final static byte[] getFingerPrintSHA1(byte[] key, byte[] message) {
515         if ((AsnObject.debug > 5) && (key.length != 20)) {
516             System.out.println("SHA1 key length wrong");
517         }
518         return getFingerPrint(key, message, true);
519     }
520 
521     
522 
523 
524 
525 
526 
527 
528 
529 
530 
531 
532 
533 
534 
535 
536     public final static byte[] getSaltDES(int snmpEngineBoots) {
537         if (salt_count == -1) {
538             
539             Random rand = new Random();
540             salt_count = rand.nextInt();
541         }
542         byte[] salt = new byte[SALT_LENGTH];
543         setBytesFromInt(salt, snmpEngineBoots, 0);
544         setBytesFromInt(salt, salt_count, SALT_LENGTH / 2);
545         salt_count++;
546         return salt;
547     }
548 
549     
550 
551 
552 
553 
554 
555 
556 
557 
558 
559 
560 
561 
562 
563 
564     
565 
566 
567 
568 
569     public static byte[] getSaltAES() {
570         if (asalt == 0) {
571             java.security.SecureRandom rand = new java.security.SecureRandom();
572             asalt = rand.nextLong();
573         } else {
574             asalt++;
575         }
576         byte[] tsalt = new byte[8];
577         setBytesFromLong(tsalt, asalt, 0);
578         return tsalt;
579     }
580 
581     
582 
583 
584 
585 
586 
587 
588 
589 
590     public final static byte[] getDESKey(byte[] secretPrivacyKey)
591             throws PduException {
592         byte[] desKey = new byte[8];
593         if (secretPrivacyKey.length < 16) {
594             throw new PduException("SnmpUtilities.getDESKey():"
595                     + " secretPrivacyKey is < 16");
596         }
597         System.arraycopy(secretPrivacyKey, 0, desKey, 0, 8);
598         return desKey;
599     }
600 
601     
602 
603 
604 
605 
606 
607 
608 
609     public static final byte[] getAESKey(byte[] secretPrivacyKey, int protocolVersion)
610         throws PduException {
611             int len = secretPrivacyKey.length;
612 
613             final  byte[] aesKey;
614             if (protocolVersion == AES_ENCRYPT) {
615             	if (len < AES128_KEY_LENGTH) {
616 					throw new PduException("SnmpUtilities.getAESKey():" + " secretPrivacyKey is < 16 for AES_ENCRYPT");
617             	}
618             	aesKey = new byte[AES128_KEY_LENGTH];
619             } else if (protocolVersion == AES192_ENCRYPT) {
620                 if (len < AES192_KEY_LENGTH) {
621                 	                    throw new PduException("SnmpUtilities.getAESKey():" + " secretPrivacyKey is < 24 for AES192_ENCRYPT");
622                 }
623                 aesKey = new byte[AES192_KEY_LENGTH];
624             } else if (protocolVersion == AES256_ENCRYPT) {
625 				if (len < AES256_KEY_LENGTH) {
626 					throw new PduException(
627 							"SnmpUtilities.getAESKey():" + " secretPrivacyKey is < 32 for AES256_ENCRYPT");
628 				}
629                 aesKey = new byte[AES256_KEY_LENGTH];
630             } else {
631                 throw new PduException("Unsupported AES protocol version: " + protocolVersion);
632             }
633 
634             System.arraycopy(secretPrivacyKey, 0, aesKey, 0, aesKey.length);
635             return aesKey;
636         }
637 
638     
639 
640 
641 
642 
643 
644 
645 
646 
647 
648 
649 
650 
651     public final static byte[] getDESInitialValue(byte[] secretPrivacyKey,
652             byte[] salt) throws PduException {
653         byte[] initV = new byte[8];
654         if (secretPrivacyKey.length < 16) {
655             throw new PduException("SnmpUtilities.getInitialValue():"
656                     + " secretPrivacyKey is < 16");
657         }
658 
659         int spk = 8;
660         for (int i = 0; i < initV.length; i++) {
661             initV[i] = (byte) (secretPrivacyKey[spk] ^ salt[i]);
662             spk++;
663         }
664         return initV;
665     }
666 
667     
668 
669 
670 
671 
672 
673 
674 
675 
676 
677     public static byte[] getAESInitialValue(int engineBoots, int engineTime, byte[] salt) {
678         byte ret[] = new byte[16];
679 
680         
681         
682         setBytesFromInt(ret, engineBoots, 0);
683 
684         
685         
686         setBytesFromInt(ret, engineTime, 4);
687 
688         
689         
690         ret[8] = salt[0];
691         ret[9] = salt[1];
692         ret[10] = salt[2];
693         ret[11] = salt[3];
694         ret[12] = salt[4];
695         ret[13] = salt[5];
696         ret[14] = salt[6];
697         ret[15] = salt[7];
698         return ret;
699     }
700 
701     
702 
703 
704 
705 
706 
707 
708 
709 
710 
711 
712 
713 
714 
715 
716 
717 
718 
719 
720 
721 
722 
723 
724 
725 
726 
727 
728 
729 
730 
731 
732 
733 
734 
735 
736 
737 
738 
739 
740     
741 
742 
743 
744 
745 
746 
747 
748 
749 
750 
751 
752     public static byte[] AESencrypt(byte[] plaintext,
753             byte[] secretPrivacyKey,
754             int engineBoots,
755             int engineTime,
756             byte[] salt,
757             int protocolVersion)
758             throws EncodingException {
759         byte[] aesKey = null;
760         byte[] iv = null;
761         try {
762             aesKey = getAESKey(secretPrivacyKey, protocolVersion);
763             iv = getAESInitialValue(engineBoots, engineTime, salt);
764         } catch (PduException exc) {
765             throw new EncodingException(exc.getMessage());
766         }
767         
768         AESEngine aes = new AESEngine();
769         KeyParameter param = new KeyParameter(aesKey);
770         aes.init(true, param);
771 
772         
773         int newL = plaintext.length;
774         int bcount = newL / 16;
775         byte[] result = new byte[newL];
776         byte[] in = new byte[16];
777         byte[] out = new byte[16];
778         int posIn = 0;
779         int posResult = 0;
780         
781         System.arraycopy(iv, 0, in, 0, 16);
782         for (int b = 0; b < bcount; b++) {
783             aes.processBlock(in, 0, out, 0);
784             for (int i = 0; i < 16; i++) {
785                 in[i] = result[posResult] = (byte) (out[i] ^ plaintext[posIn]);
786                 posResult++;
787                 posIn++;
788             }
789         }
790         
791         if (posIn < newL) {
792             aes.processBlock(in, 0, out, 0);
793             for (int i = 0; posIn < newL; i++) {
794                 result[posResult] = (byte) (out[i] ^ plaintext[posIn]);
795                 posResult++;
796                 posIn++;
797             }
798         }
799         return result;
800     }
801 
802     
803 
804 
805 
806 
807 
808 
809 
810 
811 
812 
813 
814 
815 
816 
817     public final static byte[] DESencrypt(byte[] plain, byte[] secretPrivacyKey,
818             byte[] salt) throws EncodingException {
819         byte[] desKey = null;
820         byte[] iv = null;
821         try {
822             desKey = getDESKey(secretPrivacyKey);
823             iv = getDESInitialValue(secretPrivacyKey, salt);
824         } catch (PduException exc) {
825             throw new EncodingException(exc.getMessage());
826         }
827 
828         
829         int l = plain.length;
830         int div = l / 8;
831         int mod = l % 8;
832         if (mod > 0) {
833             div++;
834         }
835         int newL = div * 8;
836         byte[] paddedOrig = new byte[newL];
837         System.arraycopy(plain, 0, paddedOrig, 0, l);
838         for (int i = l; i < newL; i++) {
839             paddedOrig[i] = (byte) 0x0;
840         }
841 
842         DESEngine des = new DESEngine();
843         DESParameters param = new DESParameters(desKey);
844         des.init(true, param);
845 
846         byte[] result = new byte[newL];
847         byte[] in = new byte[8];
848         byte[] cipherText = iv;
849         int posIn = 0;
850         int posResult = 0;
851         for (int b = 0; b < div; b++) {
852             for (int i = 0; i < 8; i++) {
853                 in[i] = (byte) (paddedOrig[posIn] ^ cipherText[i]);
854                 posIn++;
855             }
856             des.processBlock(in, 0, cipherText, 0);
857             System.arraycopy(cipherText, 0, result, posResult, cipherText.length);
858             posResult += cipherText.length;
859         }
860         return result;
861     }
862 
863     
864 
865 
866 
867 
868 
869 
870 
871 
872 
873 
874 
875 
876 
877 
878 
879 
880 
881 
882 
883 
884 
885 
886 
887     public final static byte[] DESdecrypt(byte[] encryptedText, byte[] salt,
888             byte[] secretPrivacyKey) throws DecodingException {
889         int l = encryptedText.length;
890         int div = l / 8;
891         int mod = l % 8;
892         if (mod != 0) {
893             throw new DecodingException("SnmpUtilities.decrypt():"
894                     + " The encrypted scoped PDU should be a multiple of 8 bytes");
895         }
896 
897         byte[] desKey = null;
898         byte[] iv = null;
899         try {
900             desKey = getDESKey(secretPrivacyKey);
901             iv = getDESInitialValue(secretPrivacyKey, salt);
902         } catch (PduException exc) {
903             throw new DecodingException(exc.getMessage());
904         }
905 
906         DESEngine des = new DESEngine();
907         DESParameters param = new DESParameters(desKey);
908         des.init(false, param);
909 
910         byte[] plain = new byte[l];
911         byte[] in = new byte[8];
912         byte[] out = new byte[8];
913         byte[] cipherText = iv;
914         int posPlain = 0;
915         int posEncr = 0;
916         for (int b = 0; b < div; b++) {
917             System.arraycopy(encryptedText, posEncr, in, 0, in.length);
918             posEncr += in.length;
919             des.processBlock(in, 0, out, 0);
920             for (int i = 0; i < 8; i++) {
921                 plain[posPlain] = (byte) (out[i] ^ cipherText[i]);
922                 posPlain++;
923             }
924             System.arraycopy(in, 0, cipherText, 0, in.length);
925         }
926         return plain;
927     }
928 
929     
930 
931 
932 
933 
934 
935 
936 
937 
938 
939 
940 
941 
942 
943 
944     
945 
946 
947 
948 
949 
950 
951 
952 
953 
954 
955 
956     public final static byte[] AESdecrypt(byte[] ciphertext,
957             byte[] secretPrivacyKey,
958             int engineBoots,
959             int engineTime,
960             byte[] salt,
961             int protocolVersion)
962             throws DecodingException {
963         byte[] aesKey = null;
964         byte[] iv = null;
965         try {
966             aesKey = getAESKey(secretPrivacyKey, protocolVersion);
967             iv = getAESInitialValue(engineBoots, engineTime, salt);
968         } catch (PduException exc) {
969             throw new DecodingException(exc.getMessage());
970         }
971         
972         AESEngine aes = new AESEngine();
973         KeyParameter param = new KeyParameter(aesKey);
974         aes.init(true, param);
975 
976         
977         int newL = ciphertext.length;
978         int bcount = newL / 16;
979         byte[] result = new byte[newL];
980         byte[] in = new byte[16];
981         byte[] out = new byte[16];
982         int posIn = 0;
983         int posResult = 0;
984         
985         System.arraycopy(iv, 0, in, 0, 16);
986         for (int b = 0; b < bcount; b++) {
987             aes.processBlock(in, 0, out, 0);
988             for (int i = 0; i < 16; i++) {
989                 result[posResult] = (byte) (out[i] ^ ciphertext[posIn]);
990                 in[i] = ciphertext[posIn];
991                 posResult++;
992                 posIn++;
993             }
994         }
995         
996         if (posIn < newL) {
997             aes.processBlock(in, 0, out, 0);
998             for (int i = 0; posIn < newL; i++) {
999                 result[posResult] = (byte) (out[i] ^ ciphertext[posIn]);
1000                 posResult++;
1001                 posIn++;
1002             }
1003         }
1004         return result;
1005     }
1006 
1007     
1008     static byte[] getFingerPrint(byte[] key, byte[] message, boolean doSha) {
1009         
1010         byte[] k1 = new byte[64];
1011         byte[] k2 = new byte[64];
1012         
1013         byte z1 = (byte) (0 ^ 0x36);
1014         byte z2 = (byte) (0 ^ 0x5c);
1015         int kl = key.length;
1016         int i = 0;
1017         while (i < kl) {
1018             k1[i] = (byte) (ifb(key[i]) ^ 0x36);
1019             k2[i] = (byte) (ifb(key[i]) ^ 0x5c);
1020             i++;
1021         }
1022         while (i < 64) {
1023             k1[i] = z1;
1024             k2[i] = z2;
1025             i++;
1026         }
1027         
1028         byte[] interm = null;
1029         GeneralDigest mdc = doSha ? ((GeneralDigest) new SHA1Digest()) : ((GeneralDigest) new MD5Digest());
1030         mdc.reset();
1031         mdc.update(k1, 0, k1.length);
1032         mdc.update(message, 0, message.length);
1033         interm = new byte[mdc.getDigestSize()];
1034         mdc.doFinal(interm, 0);
1035 
1036         
1037         byte[] rettmp = null;
1038         GeneralDigest mdc2 = doSha ? ((GeneralDigest) new SHA1Digest()) : ((GeneralDigest) new MD5Digest());
1039         mdc2.reset();
1040         mdc2.update(k2, 0, k2.length);
1041         mdc2.update(interm, 0, interm.length);
1042         rettmp = new byte[mdc2.getDigestSize()];
1043         mdc2.doFinal(rettmp, 0);
1044 
1045         
1046         byte[] ret = null;
1047         if (rettmp != null) {
1048             ret = new byte[12];
1049             System.arraycopy(rettmp, 0, ret, 0, 12);
1050         }
1051         return ret;
1052     }
1053 
1054     final static int ifb(byte b) {
1055         return intFromByteWithoutStupidJavaSignExtension(b);
1056     }
1057 
1058     final static int intFromByteWithoutStupidJavaSignExtension(byte val) {
1059         int ret = (0x7F) & val;
1060         if (val < 0) {
1061             ret += 128;
1062         }
1063         return ret;
1064     }
1065 
1066     final static void setBytesFromInt(byte[] ret, int value, int offs) {
1067         int v = value;
1068         int j = offs;
1069         ret[j++] = (byte) ((v >>> 24) & 0xFF);
1070         ret[j++] = (byte) ((v >>> 16) & 0xFF);
1071         ret[j++] = (byte) ((v >>> 8) & 0xFF);
1072         ret[j++] = (byte) ((v >>> 0) & 0xFF);
1073     }
1074 
1075     final static void setBytesFromLong(byte[] ret, long value, int offs) {
1076         long v = value;
1077         int j = offs;
1078         ret[j++] = (byte) ((v >>> 56) & 0xFF);
1079         ret[j++] = (byte) ((v >>> 48) & 0xFF);
1080         ret[j++] = (byte) ((v >>> 40) & 0xFF);
1081         ret[j++] = (byte) ((v >>> 32) & 0xFF);
1082         ret[j++] = (byte) ((v >>> 24) & 0xFF);
1083         ret[j++] = (byte) ((v >>> 16) & 0xFF);
1084         ret[j++] = (byte) ((v >>> 8) & 0xFF);
1085         ret[j++] = (byte) ((v >>> 0) & 0xFF);
1086     }
1087 
1088     
1089 
1090 
1091 
1092 
1093 
1094 
1095     public static byte[] passwordToKeySHA256(String userPrivacyPassword) {
1096         byte[] ret;
1097         byte[] passwordBuf = new byte[64];
1098         int pl = userPrivacyPassword.length();
1099         byte[] pass = new byte[pl];
1100 
1101         
1102         for (int i = 0; i < pl; i++) {
1103             pass[i] = (byte) (0xFF & userPrivacyPassword.charAt(i));
1104         }
1105 
1106         int count = 0;
1107         int passwordIndex = 0;
1108 
1109         try {
1110             MessageDigest sha = MessageDigest.getInstance(SHA256_ALGORITHM);
1111 
1112             
1113             while (count < ONEMEG) {
1114                 int cp = 0;
1115                 int i = 0;
1116                 while (i < 64) {
1117                     int pim = passwordIndex % pl;
1118                     int len = 64 - cp;
1119                     int pr = pl - pim;
1120                     if (len > pr) {
1121                         len = pr;
1122                     }
1123                     System.arraycopy(pass, pim, passwordBuf, cp, len);
1124                     i += len;
1125                     cp += len;
1126                     passwordIndex += len;
1127                 }
1128                 sha.update(passwordBuf, 0, passwordBuf.length);
1129                 count += 64;
1130             }
1131 
1132             
1133             ret = sha.digest();
1134         } catch (NoSuchAlgorithmException e) {
1135             throw new IllegalStateException("SHA-256 not supported, failed to generate key", e);
1136         }
1137 
1138         return ret;
1139     }
1140 
1141     
1142 
1143 
1144 
1145 
1146 
1147 
1148     public static byte[] passwordToKeySHA384(String userPrivacyPassword) {
1149         byte[] ret;
1150         byte[] passwordBuf = new byte[128]; 
1151         int pl = userPrivacyPassword.length();
1152         byte[] pass = new byte[pl];
1153 
1154         
1155         for (int i = 0; i < pl; i++) {
1156             pass[i] = (byte) (0xFF & userPrivacyPassword.charAt(i));
1157         }
1158 
1159         int count = 0;
1160         int passwordIndex = 0;
1161 
1162         try {
1163             MessageDigest sha = MessageDigest.getInstance(SHA384_ALGORITHM);
1164 
1165             
1166             while (count < ONEMEG) {
1167                 int cp = 0;
1168                 int i = 0;
1169                 while (i < 128) {
1170                     int pim = passwordIndex % pl;
1171                     int len = 128 - cp;
1172                     int pr = pl - pim;
1173                     if (len > pr) {
1174                         len = pr;
1175                     }
1176                     System.arraycopy(pass, pim, passwordBuf, cp, len);
1177                     i += len;
1178                     cp += len;
1179                     passwordIndex += len;
1180                 }
1181                 sha.update(passwordBuf, 0, passwordBuf.length);
1182                 count += 128;
1183             }
1184 
1185             
1186             ret = sha.digest();
1187         } catch (NoSuchAlgorithmException e) {
1188             throw new IllegalStateException("SHA-384 not supported, failed to generate key", e);
1189         }
1190 
1191         return ret;
1192     }
1193 
1194     
1195 
1196 
1197 
1198 
1199 
1200 
1201     public static byte[] passwordToKeySHA224(String userPrivacyPassword) {
1202         byte[] ret; 
1203         byte[] passwordBuf = new byte[64]; 
1204         int pl = userPrivacyPassword.length();
1205         byte[] pass = new byte[pl];
1206 
1207         
1208         for (int i = 0; i < pl; i++) {
1209             pass[i] = (byte) (0xFF & userPrivacyPassword.charAt(i));
1210         }
1211 
1212         int count = 0;
1213         int passwordIndex = 0;
1214 
1215         try {
1216             MessageDigest sha = MessageDigest.getInstance(SHA224_ALGORITHM);
1217 
1218             
1219             while (count < ONEMEG) {
1220                 int cp = 0;
1221                 int i = 0;
1222                 while (i < 64) { 
1223                     int pim = passwordIndex % pl;
1224                     int len = 64 - cp;
1225                     int pr = pl - pim;
1226                     if (len > pr) {
1227                         len = pr;
1228                     }
1229                     System.arraycopy(pass, pim, passwordBuf, cp, len);
1230                     i += len;
1231                     cp += len;
1232                     passwordIndex += len;
1233                 }
1234                 sha.update(passwordBuf, 0, passwordBuf.length); 
1235                 count += 64; 
1236             }
1237 
1238             
1239             ret = sha.digest();
1240         } catch (NoSuchAlgorithmException e) {
1241             throw new IllegalStateException("SHA-224 not supported, failed to generate key", e);
1242         }
1243 
1244         return ret;
1245     }
1246 
1247     
1248 
1249 
1250 
1251 
1252 
1253 
1254 
1255     public static byte[] passwordToKeySHA512(String userPrivacyPassword) {
1256         byte[] ret;
1257         byte[] passwordBuf = new byte[64];
1258         int pl = userPrivacyPassword.length();
1259         byte[] pass = new byte[pl];
1260 
1261         
1262         for (int i = 0; i < pl; i++) {
1263             pass[i] = (byte) (0xFF & userPrivacyPassword.charAt(i));
1264         }
1265 
1266         int count = 0;
1267         int passwordIndex = 0;
1268 
1269         try {
1270             MessageDigest sha = MessageDigest.getInstance(SHA512_ALGORITHM);
1271 
1272             
1273             while (count < 1024 * 1024) { 
1274                 int cp = 0;
1275                 int i = 0;
1276                 while (i < 64) {
1277                     int pim = passwordIndex % pl;
1278                     int len = 64 - cp;
1279                     int pr = pl - pim;
1280                     if (len > pr) {
1281                         len = pr;
1282                     }
1283                     System.arraycopy(pass, pim, passwordBuf, cp, len);
1284                     i += len;
1285                     cp += len;
1286                     passwordIndex += len;
1287                 }
1288                 sha.update(passwordBuf, 0, passwordBuf.length);
1289                 count += 64;
1290             }
1291 
1292             
1293             ret = sha.digest();
1294         } catch (NoSuchAlgorithmException e) {
1295             throw new IllegalStateException("SHA-512 not supported, failed to generate key", e);
1296         }
1297 
1298         return ret;
1299     }
1300 
1301     
1302 
1303 
1304 
1305 
1306 
1307 
1308     public static byte[] getLocalizedKeySHA256(final byte[] passwKey, final String snmpEngineId) {
1309         byte[] ret = null;
1310         byte[] beid = toBytes(snmpEngineId); 
1311 
1312         if (passwKey == null) {
1313             return null;
1314         }
1315 
1316         try {
1317             final MessageDigest sha = MessageDigest.getInstance(SHA256_ALGORITHM);
1318             sha.update(passwKey, 0, passwKey.length);
1319             sha.update(beid, 0, beid.length);
1320             sha.update(passwKey, 0, passwKey.length);
1321             ret = sha.digest(); 
1322         } catch (NoSuchAlgorithmException e) {
1323             throw new IllegalStateException("SHA-256 not supported, failed to generate localized key", e);
1324         }
1325 
1326         return ret;
1327     }
1328 
1329     
1330 
1331 
1332 
1333 
1334 
1335 
1336     public static byte[] getLocalizedKeySHA384(final byte[] passwKey, final String snmpEngineId) {
1337         byte[] ret = null;
1338         byte[] beid = toBytes(snmpEngineId); 
1339 
1340         if (passwKey == null) {
1341             return null;
1342         }
1343 
1344         try {
1345             final MessageDigest sha = MessageDigest.getInstance(SHA384_ALGORITHM);
1346             sha.update(passwKey, 0, passwKey.length);
1347             sha.update(beid, 0, beid.length);
1348             sha.update(passwKey, 0, passwKey.length);
1349             ret = sha.digest(); 
1350         } catch (NoSuchAlgorithmException e) {
1351             throw new IllegalStateException("SHA-384 not supported, failed to generate localized key", e);
1352         }
1353 
1354         return ret;
1355     }
1356 
1357     
1358 
1359 
1360 
1361 
1362 
1363 
1364     public static byte[] getLocalizedKeySHA224(final byte[] passwKey, final String snmpEngineId) {
1365         byte[] ret = null;
1366         byte[] beid = toBytes(snmpEngineId); 
1367 
1368         if (passwKey == null) {
1369             return null;
1370         }
1371 
1372         try {
1373             final MessageDigest sha = MessageDigest.getInstance(SHA224_ALGORITHM);
1374             sha.update(passwKey, 0, passwKey.length);
1375             sha.update(beid, 0, beid.length);
1376             sha.update(passwKey, 0, passwKey.length);
1377             ret = sha.digest(); 
1378         } catch (NoSuchAlgorithmException e) {
1379             throw new IllegalStateException("SHA-224 not supported, failed to generate localized key", e);
1380         }
1381 
1382         return ret;
1383     }
1384 
1385     
1386 
1387 
1388 
1389 
1390 
1391 
1392     public static byte[] getFingerPrintSHA256(final byte[] key, final byte[] message) {
1393         if ((AsnObject.debug > 5) && (key.length != 32)) {
1394             System.out.println("SHA256 key length wrong");
1395         }
1396         try {
1397             return doFingerPrintSHA256(key, message);
1398         } catch (NoSuchAlgorithmException e) {
1399             throw new IllegalStateException("SHA-256 not supported, failed to generate fingerprint", e);
1400         }
1401     }
1402 
1403     
1404 
1405 
1406 
1407 
1408 
1409 
1410 
1411     public static byte[] getLocalizedKeySHA512(final byte[] passwKey, final String snmpEngineId) {
1412         byte[] ret = null;
1413         byte[] beid = toBytes(snmpEngineId); 
1414 
1415         if (passwKey == null) {
1416             return null;
1417         }
1418 
1419         try {
1420             final MessageDigest sha = MessageDigest.getInstance(SHA512_ALGORITHM);
1421             sha.update(passwKey, 0, passwKey.length);
1422             sha.update(beid, 0, beid.length);
1423             sha.update(passwKey, 0, passwKey.length);
1424             ret = sha.digest(); 
1425         } catch (NoSuchAlgorithmException e) {
1426             throw new IllegalStateException("SHA-512 not supported, failed to generate localized key", e);
1427         }
1428 
1429         return ret;
1430     }
1431 
1432     
1433 
1434 
1435 
1436 
1437 
1438 
1439     public static byte[] getFingerPrintSHA512(final byte[] key, final byte[] message) {
1440         if ((AsnObject.debug > 5) && (key.length != 64)) {
1441             System.out.println("SHA-512 key length wrong");
1442         }
1443         try {
1444             return doFingerPrintSHA512(key, message);
1445         } catch (NoSuchAlgorithmException e) {
1446             throw new IllegalStateException("SHA-512 not supported, failed to generate fingerprint", e);
1447         }
1448     }
1449 
1450     
1451 
1452 
1453 
1454 
1455 
1456 
1457 
1458     public static byte[] getFingerPrintSHA224(final byte[] key, final byte[] message) {
1459         if ((AsnObject.debug > 5) && (key.length != 28)) {
1460             System.out.println("SHA-224 key length wrong");
1461         }
1462         try {
1463             return doFingerPrintSHA224(key, message);
1464         } catch (NoSuchAlgorithmException e) {
1465             throw new IllegalStateException("SHA-224 not supported, failed to generate fingerprint", e);
1466         }
1467     }
1468 
1469     
1470 
1471 
1472 
1473 
1474 
1475 
1476 
1477 
1478     private static byte[] doFingerPrintSHA224(final byte[] key, final byte[] message) throws NoSuchAlgorithmException {
1479         
1480         byte[] k1 = new byte[64];
1481         byte[] k2 = new byte[64];
1482 
1483         
1484         for (int i = 0; i < 64; i++) {
1485             byte theByte = (i < key.length) ? key[i] : 0;
1486             k1[i] = (byte) ((theByte & 0xFF) ^ 0x36); 
1487             k2[i] = (byte) ((theByte & 0xFF) ^ 0x5C); 
1488         }
1489 
1490         
1491         MessageDigest digest1 = MessageDigest.getInstance(SHA224_ALGORITHM);
1492         digest1.update(k1);
1493         digest1.update(message);
1494         byte[] innerHash = digest1.digest();
1495 
1496         
1497         MessageDigest digest2 = MessageDigest.getInstance(SHA224_ALGORITHM);
1498         digest2.update(k2);
1499         digest2.update(innerHash);
1500         byte[] fullHmac = digest2.digest();
1501 
1502         
1503         byte[] ret = new byte[16];
1504         System.arraycopy(fullHmac, 0, ret, 0, 16);
1505         return ret;
1506     }
1507 
1508     
1509 
1510 
1511 
1512 
1513 
1514 
1515 
1516     private static byte[] doFingerPrintSHA256(final byte[] key, final byte[] message) throws NoSuchAlgorithmException {
1517         
1518         byte[] k1 = new byte[64];
1519         byte[] k2 = new byte[64];
1520 
1521         
1522         for (int i = 0; i < 64; i++) {
1523             byte theByte = (i < key.length) ? key[i] : 0;
1524             k1[i] = (byte) ((theByte & 0xFF) ^ 0x36);
1525             k2[i] = (byte) ((theByte & 0xFF) ^ 0x5C);
1526         }
1527 
1528         
1529         MessageDigest digest1 = MessageDigest.getInstance(SHA256_ALGORITHM);
1530         digest1.update(k1);
1531         digest1.update(message);
1532         byte[] innerHash = digest1.digest();
1533 
1534         
1535         MessageDigest digest2 = MessageDigest.getInstance(SHA256_ALGORITHM);
1536         digest2.update(k2);
1537         digest2.update(innerHash);
1538         byte[] fullHmac = digest2.digest();
1539 
1540         
1541         byte[] ret = new byte[24];
1542         System.arraycopy(fullHmac, 0, ret, 0, 24);
1543         return ret;
1544     }
1545 
1546     
1547 
1548 
1549 
1550 
1551 
1552 
1553     public static byte[] getFingerPrintSHA384(final byte[] key, final byte[] message) {
1554         if ((AsnObject.debug > 5) && (key.length != 48)) {
1555             System.out.println("SHA384 key length wrong");
1556         }
1557         try {
1558             return doFingerPrintSHA384(key, message);
1559         } catch (NoSuchAlgorithmException e) {
1560             throw new IllegalStateException("SHA-384 not supported, failed to generate fingerprint", e);
1561         }
1562     }
1563 
1564     
1565 
1566 
1567 
1568 
1569 
1570 
1571 
1572     private static byte[] doFingerPrintSHA384(final byte[] key, final byte[] message) throws NoSuchAlgorithmException {
1573         
1574         byte[] k1 = new byte[128];
1575         byte[] k2 = new byte[128];
1576 
1577         
1578         for (int i = 0; i < 128; i++) {
1579             byte theByte = (i < key.length) ? key[i] : 0;
1580             k1[i] = (byte) ((theByte & 0xFF) ^ 0x36);
1581             k2[i] = (byte) ((theByte & 0xFF) ^ 0x5C);
1582         }
1583 
1584         
1585         MessageDigest digest1 = MessageDigest.getInstance(SHA384_ALGORITHM);
1586         digest1.update(k1);
1587         digest1.update(message);
1588         byte[] innerHash = digest1.digest();
1589 
1590         
1591         MessageDigest digest2 = MessageDigest.getInstance(SHA384_ALGORITHM);
1592         digest2.update(k2);
1593         digest2.update(innerHash);
1594         byte[] fullHmac = digest2.digest();
1595 
1596         
1597         byte[] ret = new byte[32];
1598         System.arraycopy(fullHmac, 0, ret, 0, 32);
1599         return ret;
1600     }
1601 
1602     
1603 
1604 
1605 
1606 
1607 
1608 
1609 
1610     private static byte[] doFingerPrintSHA512(final byte[] key, final byte[] message) throws NoSuchAlgorithmException {
1611         
1612         byte[] k1 = new byte[128];
1613         byte[] k2 = new byte[128];
1614 
1615         
1616         for (int i = 0; i < 128; i++) {
1617             byte theByte = (i < key.length) ? key[i] : 0;
1618             k1[i] = (byte) ((theByte & 0xFF) ^ 0x36);
1619             k2[i] = (byte) ((theByte & 0xFF) ^ 0x5C);
1620         }
1621 
1622         
1623         MessageDigest digest1 = MessageDigest.getInstance(SHA512_ALGORITHM);
1624         digest1.update(k1);
1625         digest1.update(message);
1626         byte[] innerHash = digest1.digest();
1627 
1628         
1629         MessageDigest digest2 = MessageDigest.getInstance(SHA512_ALGORITHM);
1630         digest2.update(k2);
1631         digest2.update(innerHash);
1632         byte[] fullHmac = digest2.digest();
1633 
1634         
1635         byte[] ret = new byte[48];
1636         System.arraycopy(fullHmac, 0, ret, 0, 48);
1637         return ret;
1638     }
1639 
1640     
1641 
1642 
1643 
1644 
1645 
1646 
1647 
1648 
1649     public static byte[] initFingerprint(final int authenticationProtocol) {
1650         
1651         return DUMMY_FINGERPRINT_MAP.getOrDefault(authenticationProtocol, new byte[0]);
1652     }
1653 
1654     
1655 
1656 
1657 
1658 
1659 
1660 
1661 
1662 
1663 
1664 
1665     public static void copyFingerprintToSnmpMessage(
1666             int authenticationProtocol,
1667             byte[] computedFingerprint,
1668             byte[] message,
1669             int fpPos) {
1670         int lengthToCopy = 0;
1671         switch (authenticationProtocol) {
1672             case SHA256_PROTOCOL:
1673                 lengthToCopy = dummySHA256FingerPrint.length;
1674                 break;
1675             case SHA1_PROTOCOL:
1676             case MD5_PROTOCOL:
1677                 lengthToCopy = dummySha1FingerPrint.length;
1678                 break;
1679             case SHA512_PROTOCOL:
1680                 lengthToCopy = dummySHA512FingerPrint.length;
1681                 break;
1682             case SHA224_PROTOCOL:
1683                 lengthToCopy = dummySHA224FingerPrint.length;
1684                 break;
1685             case SHA384_PROTOCOL:
1686                 lengthToCopy = dummySHA384FingerPrint.length;
1687                 break;
1688             default:
1689                 
1690                 break;
1691         }
1692         if (lengthToCopy > 0) {
1693             System.arraycopy(computedFingerprint, 0, message, fpPos, lengthToCopy);
1694         }
1695     }
1696 }