KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > security > AuthGeneric


1 /*_############################################################################
2   _##
3   _## SNMP4J - AuthGeneric.java
4   _##
5   _## Copyright 2003-2007 Frank Fock and Jochen Katz (SNMP4J.org)
6   _##
7   _## Licensed under the Apache License, Version 2.0 (the "License");
8   _## you may not use this file except in compliance with the License.
9   _## You may obtain a copy of the License at
10   _##
11   _## http://www.apache.org/licenses/LICENSE-2.0
12   _##
13   _## Unless required by applicable law or agreed to in writing, software
14   _## distributed under the License is distributed on an "AS IS" BASIS,
15   _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   _## See the License for the specific language governing permissions and
17   _## limitations under the License.
18   _##
19   _##########################################################################*/

20
21
22
23
24
25 package org.snmp4j.security;
26
27 import java.security.MessageDigest JavaDoc;
28 import org.snmp4j.log.*;
29 import org.snmp4j.smi.OctetString;
30
31 /**
32  * The abstract class AuthGeneric implements common operations for
33  * SNMP authentication protocols, such as MD5 and SHA.
34  *
35  * @author Jochen Katz & Frank Fock
36  * @version 1.0
37  */

38
39 public abstract class AuthGeneric
40     implements AuthenticationProtocol {
41
42   private static final LogAdapter logger = LogFactory.getLogger(AuthGeneric.class);
43   private int digestLength;
44   private String JavaDoc protoName;
45
46   public AuthGeneric(String JavaDoc protoName, int digestLength) {
47     this.protoName = protoName;
48     this.digestLength = digestLength;
49   }
50
51   public int getDigestLength() {
52     return digestLength;
53   }
54
55   /**
56    * Get a fresh MessageDigest object of the Algorithm specified in the
57    * constructor.
58    *
59    * @return a new, fresh Message Digest object.
60    */

61   protected MessageDigest JavaDoc getDigestObject() {
62     MessageDigest JavaDoc md;
63     try {
64       md = MessageDigest.getInstance(protoName);
65     }
66     catch (java.security.NoSuchAlgorithmException JavaDoc e) {
67       throw new InternalError JavaDoc(protoName + " not supported in this VM.");
68     }
69     // not needed the first time: md.reset();
70
return md;
71   }
72
73   public boolean authenticate(byte[] authenticationKey,
74                               byte[] message,
75                               int messageOffset,
76                               int messageLength,
77                               ByteArrayWindow digest) {
78     MessageDigest JavaDoc md = getDigestObject();
79
80     byte[] newDigest;
81     byte[] k_ipad = new byte[64]; /* inner padding - key XORd with ipad */
82     byte[] k_opad = new byte[64]; /* outer padding - key XORd with opad */
83
84     // clear the bytes for the digest (12 bytes only!)
85
for (int i = 0; i < MESSAGE_AUTHENTICATION_CODE_LENGTH; ++i) {
86       digest.set(i, (byte)0);
87     }
88
89     /*
90      * the HMAC_MD transform looks like:
91      *
92      * MD(K XOR opad, MD(K XOR ipad, msg))
93      *
94      * where K is an n byte key
95      * ipad is the byte 0x36 repeated 64 times
96      * opad is the byte 0x5c repeated 64 times
97      * and text is the data being protected
98      */

99     /* start out by storing key, ipad and opad in pads */
100     for (int i = 0; i < authenticationKey.length; ++i) {
101       k_ipad[i] = (byte) (authenticationKey[i] ^ 0x36);
102       k_opad[i] = (byte) (authenticationKey[i] ^ 0x5c);
103     }
104     for (int i = authenticationKey.length; i < 64; ++i) {
105       k_ipad[i] = 0x36;
106       k_opad[i] = 0x5c;
107     }
108
109     /* perform inner MD */
110     md.update(k_ipad); /* start with inner pad */
111     md.update(message, messageOffset, messageLength); /* then text of msg */
112     newDigest = md.digest(); /* finish up 1st pass */
113     /* perform outer MD */
114     md.reset(); /* init md5 for 2nd pass */
115     md.update(k_opad); /* start with outer pad */
116     md.update(newDigest); /* then results of 1st hash */
117     newDigest = md.digest(); /* finish up 2nd pass */
118
119     // copy the digest into the message (12 bytes only!)
120
for (int i = 0; i < 12; ++i) {
121       digest.set(i, newDigest[i]);
122     }
123     return true;
124   }
125
126   public boolean isAuthentic(byte[] authenticationKey,
127                              byte[] message,
128                              int messageOffset,
129                              int messageLength,
130                              ByteArrayWindow digest) {
131     // copy digest from message
132
ByteArrayWindow origDigest =
133         new ByteArrayWindow(new byte[MESSAGE_AUTHENTICATION_CODE_LENGTH], 0,
134                             MESSAGE_AUTHENTICATION_CODE_LENGTH);
135     System.arraycopy(digest.getValue(), digest.getOffset(),
136                      origDigest.getValue(), 0,
137                      MESSAGE_AUTHENTICATION_CODE_LENGTH);
138
139     // use the authenticate() method to recalculate the digest
140
if (!authenticate(authenticationKey, message, messageOffset,
141                       messageLength, digest)) {
142       return false;
143     }
144     return digest.equals(origDigest, 12);
145   }
146
147   public byte[] changeDelta(byte[] oldKey,
148                             byte[] newKey,
149                             byte[] random) {
150     // algorithm according to USM-document textual convention KeyChange
151
// simplified for fixed length keys
152

153     MessageDigest JavaDoc md5 = getDigestObject();
154
155     if (logger.isDebugEnabled()) {
156       logger.debug(protoName + "oldKey: " + new OctetString(oldKey).toHexString());
157       logger.debug(protoName + "newKey: " + new OctetString(newKey).toHexString());
158       logger.debug(protoName + "random: " + new OctetString(random).toHexString());
159     }
160
161     // step 1: initialize temporary variable
162
// step 2: nothing to do as we only support fixed length keys ;-)
163
// step 3:
164
md5.update(oldKey);
165     md5.update(random);
166     byte[] digest = md5.digest();
167
168     // step 4:
169
byte[] keyChange = new byte[random.length + newKey.length];
170     for (int i = 0; i < random.length; ++i) {
171       keyChange[i] = random[i];
172     }
173     for (int i = random.length; i < random.length + newKey.length; ++i) {
174       keyChange[i] = newKey[i - random.length];
175     }
176     for (int j = oldKey.length; j < keyChange.length; j++) {
177       keyChange[j] ^= digest[j - oldKey.length];
178     }
179
180     if (logger.isDebugEnabled()) {
181       logger.debug(protoName + "keyChange:" +
182                    new OctetString(keyChange).toHexString());
183     }
184
185     return keyChange;
186   }
187
188   public byte[] passwordToKey(OctetString passwordString, byte[] engineID) {
189
190     MessageDigest JavaDoc md = getDigestObject();
191
192     byte[] digest;
193     byte[] buf = new byte[64];
194     int password_index = 0;
195     int count = 0;
196     byte[] password = passwordString.getValue();
197
198     /* Use while loop until we've done 1 Megabyte */
199     while (count < 1048576) {
200       for (int i = 0; i < 64; ++i) {
201         /* Take the next octet of the password, wrapping */
202         /* to the beginning of the password as necessary.*/
203         buf[i] = password[password_index++ % password.length];
204       }
205       md.update(buf);
206       count += 64;
207     }
208     digest = md.digest();
209     if (logger.isDebugEnabled()) {
210       logger.debug(protoName + "First digest: " +
211                    new OctetString(digest).toHexString());
212     }
213
214     /*****************************************************/
215     /* Now localize the key with the engine_id and pass */
216     /* through MD to produce final key */
217     /*****************************************************/
218     md.reset();
219     md.update(digest);
220     md.update(engineID);
221     md.update(digest);
222     digest = md.digest();
223     if (logger.isDebugEnabled()) {
224       logger.debug(protoName + "localized key: " +
225                    new OctetString(digest).toHexString());
226     }
227
228     return digest;
229   }
230
231   public byte[] hash(byte[] data) {
232     MessageDigest JavaDoc md = getDigestObject();
233     md.update(data);
234     return md.digest();
235   }
236
237   public byte[] hash(byte[] data, int offset, int length) {
238     MessageDigest JavaDoc md = getDigestObject();
239     md.update(data, offset, length);
240     return md.digest();
241   }
242
243 }
244
Popular Tags