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 wim_data;
028:
029: import java.io.*;
030: import java.security.MessageDigest;
031: import java.security.NoSuchAlgorithmException;
032:
033: /**
034: * This class implements miscellaneous utility methods.
035: */
036: public class Utils {
037:
038: /** Hexadecimal digits. */
039: private static char[] hc = { '0', '1', '2', '3', '4', '5', '6',
040: '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
041:
042: /**
043: * Converts a subsequence of bytes in a byte array into a
044: * corresponding string of hexadecimal digits, each separated by a ":".
045: * @param b byte array containing the bytes to be converted
046: * @param off starting offset of the byte subsequence inside b
047: * @param len number of bytes to be converted
048: * @return a string of corresponding hexadecimal digits or
049: * an error string
050: */
051: static String hexEncode(byte[] b, int off, int len) {
052: return new String(hexEncodeToChars(b, off, len));
053: }
054:
055: /**
056: * Converts a subsequence of bytes in a byte array into a
057: * corresponding string of hexadecimal digits, each separated by a ":".
058: * @param b byte array containing the bytes to be converted
059: * @param off starting offset of the byte subsequence inside b
060: * @param len number of bytes to be converted
061: * @return a string of corresponding hexadecimal digits or
062: * an error string
063: */
064: static char[] hexEncodeToChars(byte[] b, int off, int len) {
065: char[] r;
066: int v;
067: int i;
068: int j;
069:
070: if ((b == null) || (len == 0)) {
071: return new char[0];
072: }
073:
074: if ((off < 0) || (len < 0)) {
075: throw new ArrayIndexOutOfBoundsException();
076: }
077:
078: if (len == 1) {
079: r = new char[len * 2];
080: } else {
081: r = new char[(len * 3) - 1];
082: }
083:
084: for (i = 0, j = 0;;) {
085: v = b[off + i] & 0xff;
086: r[j++] = hc[v >>> 4];
087: r[j++] = hc[v & 0x0f];
088:
089: i++;
090: if (i >= len) {
091: break;
092: }
093:
094: r[j++] = ':';
095: }
096:
097: return r;
098: }
099:
100: /**
101: * Converts a byte array into a corresponding string of hexadecimal
102: * digits. This is equivalent to hexEncode(b, 0, b.length).
103: * @param b byte array to be converted
104: * @return corresponding hexadecimal string
105: */
106: static String hexEncode(byte[] b) {
107: if (b == null)
108: return ("");
109: else
110: return hexEncode(b, 0, b.length);
111: }
112:
113: /**
114: * Converts a long value to a cooresponding 8-byte array
115: * starting with the most significant byte.
116: * @param n 64-bit long integer value
117: * @return a corresponding 8-byte array in network byte order
118: */
119: static byte[] longToBytes(long n) {
120: byte[] b = new byte[8];
121:
122: for (int i = 0; i < 64; i += 8) {
123: b[i >> 3] = (byte) ((n >> (56 - i)) & 0xff);
124: }
125: return b;
126: }
127:
128: /**
129: * Checks if two byte arrays match.
130: * @param a first byte array
131: * @param aOff starting offset for comparison within a
132: * @param b second byte array
133: * @param bOff starting offset for comparison within b
134: * @param len number of bytes to be compared
135: * @return true if the sequence of len bytes in a starting at
136: * aOff matches those in b starting at bOff, false otherwise
137: */
138: static boolean byteMatch(byte[] a, int aOff, byte[] b, int bOff,
139: int len) {
140: if ((a.length < aOff + len) || (b.length < bOff + len))
141: return false;
142:
143: for (int i = 0; i < len; i++) {
144: if (a[i + aOff] != b[i + bOff])
145: return false;
146: }
147:
148: return true;
149: }
150:
151: /**
152: * Calculates SHA hash for given data.
153: * @param data byte array containing the bytes to be hashed
154: * @param offset starting offset
155: * @param length number of bytes
156: * @return hash value
157: */
158: public static byte[] getHash(byte[] data, int offset, int length) {
159:
160: MessageDigest SHA = null;
161: try {
162: SHA = MessageDigest.getInstance("SHA-1");
163: } catch (NoSuchAlgorithmException e) {
164: }
165:
166: SHA.reset();
167: SHA.update(data, offset, length);
168: return SHA.digest();
169: }
170:
171: /**
172: * Converts a sequence of bytes into a printable OID,
173: * a string of decimal digits, each separated by a ".".
174: * @param buffer byte array containing the bytes to be converted
175: * @param offset starting offset of the byte subsequence inside b
176: * @param length number of bytes to be converted
177: * @return printable OID
178: */
179: public static String OIDtoString(byte[] buffer, int offset,
180: int length) {
181: StringBuffer result;
182: int end;
183: int t;
184: int x;
185: int y;
186:
187: if (length == 0) {
188: return "";
189: }
190:
191: result = new StringBuffer(40);
192:
193: end = offset + length;
194:
195: /*
196: * first byte (t) always represents the first 2 values (x, y).
197: * t = (x * 40) + y;
198: */
199: t = buffer[offset++] & 0xff;
200: x = t / 40;
201: y = t - (x * 40);
202:
203: result.append(x);
204: result.append('.');
205: result.append(y);
206:
207: x = 0;
208: while (offset < end) {
209: // 7 bit per byte, bit 8 = 0 means the end of a value
210: x = x << 7;
211:
212: t = buffer[offset++];
213: if (t >= 0) {
214: x += t;
215: result.append('.');
216: result.append(x);
217: x = 0;
218: } else {
219: x += t & 0x7f;
220: }
221: }
222:
223: return result.toString();
224: }
225:
226: /**
227: * Converst OID from string representation into byte array.
228: * @param oid string representation of OID
229: * @return byte array containing DER value for this OID.
230: */
231: public static byte[] StringToOID(String oid) {
232:
233: if (oid.indexOf('-') != -1) {
234: throw new IllegalArgumentException(oid);
235: }
236:
237: ByteArrayOutputStream out = new ByteArrayOutputStream();
238:
239: int i = 0;
240: int b1 = 0;
241: int current = 0;
242:
243: while (current < oid.length()) {
244:
245: i++;
246:
247: int k = oid.indexOf('.', current);
248: if (k == -1) {
249: k = oid.length();
250: }
251:
252: int v = Integer.parseInt(oid.substring(current, k));
253: current = k + 1;
254:
255: if (i == 1) {
256: b1 = v;
257: continue;
258: }
259:
260: if (i == 2) {
261: v = b1 * 40 + v;
262: if (v > 255) {
263: throw new IllegalArgumentException(oid);
264: }
265: out.write(v);
266: continue;
267: }
268:
269: int p = 0;
270: k = v;
271:
272: while (true) {
273: p += 1;
274: k = k >> 7;
275: if (k == 0) {
276: break;
277: }
278: }
279:
280: k = v;
281: while (p > 0) {
282:
283: byte x = (byte) (k >> ((p - 1) * 7));
284:
285: if (p == 1) {
286: x &= 0x7f;
287: } else {
288: x |= 0x80;
289: }
290: p--;
291: out.write(x);
292: }
293: }
294:
295: if (i < 2) {
296: throw new IllegalArgumentException(oid);
297: }
298:
299: return out.toByteArray();
300: }
301:
302: /**
303: * Creates java source for static array initialization.
304: * @param writer where to write
305: * @param name array name
306: * @param data initial values
307: */
308: public static void writeDataArray(PrintStream writer, String name,
309: byte[] data) {
310:
311: writer.println();
312:
313: String s = " static byte[] " + name + " = { ";
314:
315: for (int i = 0; i < data.length; i++) {
316:
317: if (i != 0) {
318: s = s + ", ";
319: }
320:
321: String h = "" + data[i];
322:
323: if (s.length() + h.length() > 76) {
324: writer.println(s);
325: s = " ";
326: }
327:
328: s = s + h;
329: }
330:
331: writer.println(s + "};");
332: writer.println();
333: }
334:
335: /**
336: * Writes hex representation of byte array elements.
337: * @param writer where to write
338: * @param data data to be written
339: */
340: public static void writeHex(PrintStream writer, byte[] data) {
341:
342: String s = " ";
343:
344: for (int i = 0; i < data.length; i++) {
345:
346: if (data[i] > -1 && data[i] < 16) {
347: s = s + "0";
348: }
349: s = s + Integer.toHexString(data[i] & 0xff) + " ";
350:
351: if ((i + 1) % 16 == 0) {
352: writer.println(s);
353: s = " ";
354: }
355: }
356:
357: if (s.length() != 4) {
358: writer.println(s);
359: }
360: }
361:
362: /**
363: * Converts short value into 2 byte array.
364: * @param i source value
365: * @return resulting byte array
366: */
367: public static byte[] shortToBytes(int i) {
368:
369: byte[] data = new byte[2];
370: data[0] = (byte) (i >> 8);
371: data[1] = (byte) i;
372: return data;
373: }
374:
375: /**
376: * Converts multiple short values into byte array.
377: * @param v source values
378: * @return resulting byte array
379: */
380: public static byte[] shortToBytes(short[] v) {
381:
382: byte[] data = new byte[v.length * 2];
383: for (int i = 0; i < v.length; i++) {
384: data[i * 2] = (byte) (v[i] >> 8);
385: data[i * 2 + 1] = (byte) v[i];
386: }
387: return data;
388: }
389:
390: /**
391: * Creates TLV structure for given card file path/offset/length.
392: * @param id path
393: * @param offset offset in file
394: * @param len length of data
395: * @return TLV structure for this path
396: */
397: public static TLV createPath(short[] id, int offset, int len) {
398:
399: TLV t = TLV.createSequence();
400:
401: t.setChild(TLV.createOctetString(shortToBytes(id))).setNext(
402: new TLV(TLV.INTEGER_TYPE, shortToBytes(offset)))
403: .setNext(
404: new TLV(TLV.INTEGER_TYPE, shortToBytes(len))
405: .setTag(0x80));
406:
407: return t;
408: }
409:
410: /**
411: * Creates TLV structure for given card file path.
412: * @param id path
413: * @return TLV structure for this path
414: */
415: public static TLV createPath(short[] id) {
416:
417: TLV t = TLV.createSequence();
418: t.setChild(TLV.createOctetString(shortToBytes(id)));
419: return t;
420: }
421:
422: /**
423: * Creates TLV structure for label.
424: * @param label label text
425: * @return TLV structure for this label
426: */
427: public static TLV createLabel(String label) {
428:
429: // Only ASCII symbols should be used
430: while (label.length() < 32) {
431: label = label + " ";
432: }
433: return TLV.createUTF8String(label);
434: }
435: }
|