001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package acl_data;
028:
029: import java.security.MessageDigest;
030:
031: import java.io.ByteArrayOutputStream;
032: import java.io.UnsupportedEncodingException;
033:
034: import java.util.*;
035: import java.io.PrintStream;
036:
037: /**
038: * This class implements miscellaneous utility methods including
039: * those used for conversion of BigIntegers to
040: * byte arrays, hexadecimal printing of byte arrays etc.
041: */
042: public class Utils {
043:
044: /** UTF-8 encoding name. */
045: public static final String utf8 = "UTF-8";
046:
047: /** Hexadecimal digits. */
048: private static char[] hc = { '0', '1', '2', '3', '4', '5', '6',
049: '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
050:
051: /**
052: * Returns hex value for given sequence of bytes.
053: * @param b source data
054: * @param off offset of the first byte
055: * @param len length of the value
056: * @return hex value for given sequence of bytes.
057: */
058: public static String hexNumber(byte[] b, int off, int len) {
059:
060: char[] r;
061: int v;
062: int i;
063: int j;
064:
065: if ((b == null) || (len == 0)) {
066: return "";
067: }
068:
069: if ((off < 0) || (len < 0)) {
070: throw new ArrayIndexOutOfBoundsException();
071: }
072:
073: r = new char[len * 2];
074:
075: for (i = 0, j = 0;;) {
076: v = b[off + i] & 0xff;
077: r[j++] = hc[v >>> 4];
078: r[j++] = hc[v & 0x0f];
079:
080: i++;
081: if (i >= len) {
082: break;
083: }
084: }
085:
086: return (new String(r, 0, j));
087: }
088:
089: /**
090: * Returns hex value for given byte.
091: * @param b source data
092: * @return hex value.
093: */
094: public static String hexByte(int b) {
095: b = b & 0xff;
096: return new String(new char[] { hc[b >>> 4], hc[b & 0x0f] });
097: }
098:
099: /**
100: * Checks if two byte arrays match.
101: * @param a the first byte array
102: * @param aOff starting offset for comparison within a
103: * @param aLen length of data in the first array
104: * @param b the second byte array
105: * @param bOff starting offset for comparison within b
106: * @param bLen length of data in the second array
107: * @return true if the sequence of len bytes in a starting at
108: * aOff matches those in b starting at bOff, false otherwise
109: */
110: public static boolean byteMatch(byte[] a, int aOff, int aLen,
111: byte[] b, int bOff, int bLen) {
112: if ((aLen != bLen) || (a.length < aOff + aLen)
113: || (b.length < bOff + bLen)) {
114: return false;
115: }
116:
117: for (int i = 0; i < aLen; i++) {
118: if (a[i + aOff] != b[i + bOff])
119: return false;
120: }
121:
122: return true;
123: }
124:
125: /**
126: * Checks if two byte arrays match.
127: * @param a the first byte array
128: * @param b the second byte array
129: * @return true if both arrays has the same length and contents
130: */
131: public static boolean byteMatch(byte[] a, byte[] b) {
132: return byteMatch(a, 0, a.length, b, 0, b.length);
133: }
134:
135: /**
136: * Converts a sequence of bytes into a printable OID,
137: * a string of decimal digits, each separated by a ".".
138: * @param buffer byte array containing the bytes to be converted
139: * @param offset starting offset of the byte subsequence inside b
140: * @param length number of bytes to be converted
141: * @return printable OID
142: */
143: public static String OIDtoString(byte[] buffer, int offset,
144: int length) {
145:
146: StringBuffer result;
147: int end;
148: int t;
149: int x;
150: int y;
151:
152: if (length == 0) {
153: return "";
154: }
155:
156: result = new StringBuffer(40);
157:
158: end = offset + length;
159:
160: // first byte (t) always represents the first 2 values (x, y).
161: // t = (x * 40) + y;
162:
163: t = buffer[offset++] & 0xff;
164: x = t / 40;
165: y = t - (x * 40);
166:
167: result.append(x);
168: result.append('.');
169: result.append(y);
170:
171: x = 0;
172: while (offset < end) {
173: // 7 bit per byte, bit 8 = 0 means the end of a value
174: x = x << 7;
175:
176: t = buffer[offset++];
177: if (t >= 0) {
178: x += t;
179: result.append('.');
180: result.append(x);
181: x = 0;
182: } else {
183: x += t & 0x7f;
184: }
185: }
186:
187: return result.toString();
188: }
189:
190: /**
191: * Converst OID from string representation into byte array.
192: * @param oid string representation of OID
193: * @return byte array containing DER value for this OID.
194: */
195: public static byte[] StringToOID(String oid) {
196:
197: if (oid.indexOf('-') != -1) {
198: throw new IllegalArgumentException(oid);
199: }
200:
201: ByteArrayOutputStream out = new ByteArrayOutputStream();
202:
203: int i = 0;
204: int b1 = 0;
205: int current = 0;
206:
207: while (current < oid.length()) {
208:
209: i++;
210:
211: int k = oid.indexOf('.', current);
212: if (k == -1) {
213: k = oid.length();
214: }
215:
216: int v = Integer.parseInt(oid.substring(current, k));
217: current = k + 1;
218:
219: if (i == 1) {
220: b1 = v;
221: continue;
222: }
223:
224: if (i == 2) {
225: v = b1 * 40 + v;
226: if (v > 255) {
227: throw new IllegalArgumentException(oid);
228: }
229: out.write(v);
230: continue;
231: }
232:
233: int p = 0;
234: k = v;
235:
236: while (true) {
237: p += 1;
238: k = k >> 7;
239: if (k == 0) {
240: break;
241: }
242: }
243:
244: k = v;
245: while (p > 0) {
246:
247: byte x = (byte) (k >> ((p - 1) * 7));
248:
249: if (p == 1) {
250: x &= 0x7f;
251: } else {
252: x |= 0x80;
253: }
254: p--;
255: out.write(x);
256: }
257: }
258:
259: if (i < 2) {
260: throw new IllegalArgumentException(oid);
261: }
262:
263: return out.toByteArray();
264: }
265:
266: /**
267: * Retrieves short value from byte array.
268: * @param data byte array
269: * @param offset value offset
270: * @return the short value
271: */
272: public static short getShort(byte[] data, int offset) {
273: return (short) getU2(data, offset);
274: }
275:
276: /**
277: * Retrieves unsigned 2-byte value from byte array.
278: * @param data byte array
279: * @param offset value offset
280: * @return the value
281: */
282: public static int getU2(byte[] data, int offset) {
283: return ((data[offset] & 0xff) << 8) | (data[offset + 1] & 0xff);
284: }
285:
286: /**
287: * Constructs integer value from byte array data.
288: * @param data the byte array.
289: * @param offset offset of the data.
290: * @return the integer value.
291: */
292: public static int getInt(byte[] data, int offset) {
293:
294: int l = 0;
295: for (int k = 0; k < 4; k++) {
296: l = (l << 8) | (data[offset++] & 0xFF);
297: }
298: return l;
299: }
300:
301: /**
302: * Calculates SHA-1 hash for given data.
303: * @param inBuf array containing the data
304: * @param inOff data offset
305: * @param inLen data length
306: * @return SHA-1 hash
307: */
308: public static byte[] getHash(byte[] inBuf, int inOff, int inLen) {
309:
310: try {
311: MessageDigest sha = MessageDigest.getInstance("SHA");
312: sha.reset();
313: byte[] hash = new byte[20];
314: hash = sha.digest(inBuf);
315: return hash;
316: } catch (Exception e) {
317: e.printStackTrace();
318: return null;
319: }
320: }
321:
322: /**
323: * Returns byte array which contains encoded short value.
324: * @param i the value
325: * @return byte array
326: */
327: public static byte[] shortToBytes(int i) {
328:
329: byte[] data = new byte[2];
330: data[0] = (byte) (i >> 8);
331: data[1] = (byte) i;
332: return data;
333: }
334:
335: /**
336: * Returns byte array that contains sequence of encoded short values.
337: * @param data the short values
338: * @return byte array
339: */
340:
341: public static byte[] shortsToBytes(short[] data) {
342:
343: byte[] d = new byte[2 * data.length];
344: for (int i = 0; i < data.length; i++) {
345: d[i * 2] = (byte) (data[i] >> 8);
346: d[i * 2 + 1] = (byte) data[i];
347: }
348: return d;
349: }
350:
351: /**
352: * Returns UTF 8 encoding for this string.
353: * @param s the string
354: * @return UTF 8 encoding
355: */
356: public static byte[] stringToBytes(String s) {
357: try {
358: return s.getBytes(utf8);
359: } catch (UnsupportedEncodingException e) {
360: e.printStackTrace();
361: }
362:
363: System.out.println("Internal error: unsupported encoding");
364: return null;
365: }
366:
367: /**
368: * Converts the calender to a string.
369: * @param calendar input date information
370: * @return formatted calendar string
371: */
372: public static String calendarToString(Calendar calendar) {
373: String[] months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
374: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
375:
376: String[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
377: "Sat" };
378:
379: if (calendar == null) {
380: return "Thu Jan 01 00:00:00 UTC 1970";
381: }
382:
383: int dow = calendar.get(Calendar.DAY_OF_WEEK);
384: int month = calendar.get(Calendar.MONTH);
385: int day = calendar.get(Calendar.DAY_OF_MONTH);
386: int hour_of_day = calendar.get(Calendar.HOUR_OF_DAY);
387: int minute = calendar.get(Calendar.MINUTE);
388: int seconds = calendar.get(Calendar.SECOND);
389: int year = calendar.get(Calendar.YEAR);
390:
391: String yr = Integer.toString(year);
392:
393: // TimeZone zone = calendar.getTimeZone();
394: // String zoneID = zone.getID();
395: // if (zoneID == null) zoneID = "";
396: String zoneID = "GMT";
397:
398: // The total size of the string buffer
399: // 3+1+3+1+2+1+2+1+2+1+2+1+zoneID.length+1+yr.length
400: // = 21 + zoneID.length + yr.length
401: StringBuffer sb = new StringBuffer(25 + zoneID.length()
402: + yr.length());
403:
404: sb.append(days[dow - 1]).append(' ');
405: sb.append(months[month]).append(' ');
406: appendTwoDigits(sb, day).append(' ');
407: appendTwoDigits(sb, hour_of_day).append(':');
408: appendTwoDigits(sb, minute).append(':');
409: appendTwoDigits(sb, seconds).append(' ');
410: if (zoneID.length() > 0)
411: sb.append(zoneID).append(' ');
412: appendFourDigits(sb, year);
413:
414: return sb.toString();
415: }
416:
417: /**
418: * Appends zero filled numeric string for two digit numbers.
419: * @param sb current formatted buffer
420: * @param number the digit to format
421: * @return updated formatted string buffer
422: */
423: private static final StringBuffer appendTwoDigits(StringBuffer sb,
424: int number) {
425: if (number < 10) {
426: sb.append('0');
427: }
428: return sb.append(number);
429: }
430:
431: /**
432: * Appends zero filled numeric string for four digit numbers.
433: * @param sb current formatted buffer
434: * @param number the digit to format
435: * @return updated formatted string buffer
436: */
437: private static final StringBuffer appendFourDigits(StringBuffer sb,
438: int number) {
439: if (number >= 0 && number < 1000) {
440: sb.append('0');
441: if (number < 100) {
442: sb.append('0');
443: }
444: if (number < 10) {
445: sb.append('0');
446: }
447: }
448: return sb.append(number);
449: }
450:
451: /**
452: * Writes hex representation of byte array elements.
453: * @param writer where to write
454: * @param data data to be written
455: */
456: public static void writeHex(PrintStream writer, byte[] data) {
457:
458: String s = " ";
459:
460: for (int i = 0; i < data.length; i++) {
461:
462: if (data[i] > -1 && data[i] < 16) {
463: s = s + "0";
464: }
465: s = s + Integer.toHexString(data[i] & 0xff) + " ";
466:
467: if ((i + 1) % 16 == 0) {
468: writer.println(s);
469: s = " ";
470: }
471: }
472:
473: if (s.length() != 4) {
474: writer.println(s);
475: }
476: }
477:
478: /**
479: * Converts string to array of shorts
480: * @param str input string
481: * @return output array of shorts
482: */
483: public static short[] stringToShorts(String str) {
484: byte[] b = str.getBytes();
485: short[] res = new short[1 + (b.length / 4)];
486: for (int i = 0; i < b.length; i++) {
487: if ((b[i] >= 0x30) & (b[i] <= 0x39)) {
488: b[i] = (byte) (b[i] - 0x30);
489: } else {
490: if ((b[i] >= 0x41) & (b[i] <= 0x46)) {
491: b[i] = (byte) (b[i] - 0x41 + 0xa);
492: } else {
493: if ((b[i] >= 0x61) & (b[i] <= 0x66)) {
494: b[i] = (byte) (b[i] - 0x61 + 0xa);
495: }
496: }
497:
498: }
499: }
500: res[0] = 0x3fff;
501: for (int i = 0; i < res.length - 1; i++) {
502: res[i + 1] = (short) ((b[4 * i] << 12)
503: | (b[4 * i + 1] << 8) | (b[4 * i + 2] << 4) | b[4 * i + 3]);
504: }
505: return res;
506: }
507:
508: /**
509: * Creates java source for static array initialization.
510: * @param writer where to write
511: * @param name array name
512: * @param data initial values
513: */
514: public static void writeDataArray(PrintStream writer, String name,
515: byte[] data) {
516:
517: writer.println();
518:
519: String s = " static byte[] " + name + " = { ";
520:
521: for (int i = 0; i < data.length; i++) {
522:
523: if (i != 0) {
524: s = s + ", ";
525: }
526:
527: String h = "" + data[i];
528:
529: if (s.length() + h.length() > 76) {
530: writer.println(s);
531: s = " ";
532: }
533:
534: s = s + h;
535: }
536:
537: writer.println(s + "};");
538: writer.println();
539: }
540: }
|