Source for gnu.java.security.util.Util

   1: /* Util.java -- various utility routines.
   2:    Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2 of the License, or (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.java.security.util;
  40: 
  41: import java.math.BigInteger;
  42: 
  43: /**
  44:  * A collection of utility methods used throughout this project.
  45:  */
  46: public class Util
  47: {
  48:   // Hex charset
  49:   private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
  50: 
  51:   // Base-64 charset
  52:   private static final String BASE64_CHARS =
  53:       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
  54: 
  55:   private static final char[] BASE64_CHARSET = BASE64_CHARS.toCharArray();
  56: 
  57:   /** Trivial constructor to enforce Singleton pattern. */
  58:   private Util()
  59:   {
  60:     super();
  61:   }
  62: 
  63:   /**
  64:    * Returns a string of hexadecimal digits from a byte array. Each byte is
  65:    * converted to 2 hex symbols; zero(es) included.
  66:    * <p>
  67:    * This method calls the method with same name and three arguments as:
  68:    * <pre>
  69:    * toString(ba, 0, ba.length);
  70:    * </pre>
  71:    * 
  72:    * @param ba the byte array to convert.
  73:    * @return a string of hexadecimal characters (two for each byte) representing
  74:    *         the designated input byte array.
  75:    */
  76:   public static String toString(byte[] ba)
  77:   {
  78:     return toString(ba, 0, ba.length);
  79:   }
  80: 
  81:   /**
  82:    * Returns a string of hexadecimal digits from a byte array, starting at
  83:    * <code>offset</code> and consisting of <code>length</code> bytes. Each
  84:    * byte is converted to 2 hex symbols; zero(es) included.
  85:    * 
  86:    * @param ba the byte array to convert.
  87:    * @param offset the index from which to start considering the bytes to
  88:    *          convert.
  89:    * @param length the count of bytes, starting from the designated offset to
  90:    *          convert.
  91:    * @return a string of hexadecimal characters (two for each byte) representing
  92:    *         the designated input byte sub-array.
  93:    */
  94:   public static final String toString(byte[] ba, int offset, int length)
  95:   {
  96:     char[] buf = new char[length * 2];
  97:     for (int i = 0, j = 0, k; i < length;)
  98:       {
  99:         k = ba[offset + i++];
 100:         buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F];
 101:         buf[j++] = HEX_DIGITS[ k        & 0x0F];
 102:       }
 103:     return new String(buf);
 104:   }
 105: 
 106:   /**
 107:    * Returns a string of hexadecimal digits from a byte array. Each byte is
 108:    * converted to 2 hex symbols; zero(es) included. The argument is treated as a
 109:    * large little-endian integer and is returned as a large big-endian integer.
 110:    * <p>
 111:    * This method calls the method with same name and three arguments as:
 112:    * <pre>
 113:    * toReversedString(ba, 0, ba.length);
 114:    * </pre>
 115:    * 
 116:    * @param ba the byte array to convert.
 117:    * @return a string of hexadecimal characters (two for each byte) representing
 118:    *         the designated input byte array.
 119:    */
 120:   public static String toReversedString(byte[] ba)
 121:   {
 122:     return toReversedString(ba, 0, ba.length);
 123:   }
 124: 
 125:   /**
 126:    * Returns a string of hexadecimal digits from a byte array, starting at
 127:    * <code>offset</code> and consisting of <code>length</code> bytes. Each
 128:    * byte is converted to 2 hex symbols; zero(es) included.
 129:    * <p>
 130:    * The byte array is treated as a large little-endian integer, and is returned
 131:    * as a large big-endian integer.
 132:    * 
 133:    * @param ba the byte array to convert.
 134:    * @param offset the index from which to start considering the bytes to
 135:    *          convert.
 136:    * @param length the count of bytes, starting from the designated offset to
 137:    *          convert.
 138:    * @return a string of hexadecimal characters (two for each byte) representing
 139:    *         the designated input byte sub-array.
 140:    */
 141:   public static final String toReversedString(byte[] ba, int offset, int length)
 142:   {
 143:     char[] buf = new char[length * 2];
 144:     for (int i = offset + length - 1, j = 0, k; i >= offset;)
 145:       {
 146:         k = ba[offset + i--];
 147:         buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F];
 148:         buf[j++] = HEX_DIGITS[ k        & 0x0F];
 149:       }
 150:     return new String(buf);
 151:   }
 152: 
 153:   /**
 154:    * <p>
 155:    * Returns a byte array from a string of hexadecimal digits.
 156:    * </p>
 157:    * 
 158:    * @param s a string of hexadecimal ASCII characters
 159:    * @return the decoded byte array from the input hexadecimal string.
 160:    */
 161:   public static byte[] toBytesFromString(String s)
 162:   {
 163:     int limit = s.length();
 164:     byte[] result = new byte[((limit + 1) / 2)];
 165:     int i = 0, j = 0;
 166:     if ((limit % 2) == 1)
 167:       result[j++] = (byte) fromDigit(s.charAt(i++));
 168:     while (i < limit)
 169:       {
 170:         result[j  ] = (byte) (fromDigit(s.charAt(i++)) << 4);
 171:         result[j++] |= (byte) fromDigit(s.charAt(i++));
 172:       }
 173:     return result;
 174:   }
 175: 
 176:   /**
 177:    * Returns a byte array from a string of hexadecimal digits, interpreting them
 178:    * as a large big-endian integer and returning it as a large little-endian
 179:    * integer.
 180:    * 
 181:    * @param s a string of hexadecimal ASCII characters
 182:    * @return the decoded byte array from the input hexadecimal string.
 183:    */
 184:   public static byte[] toReversedBytesFromString(String s)
 185:   {
 186:     int limit = s.length();
 187:     byte[] result = new byte[((limit + 1) / 2)];
 188:     int i = 0;
 189:     if ((limit % 2) == 1)
 190:       result[i++] = (byte) fromDigit(s.charAt(--limit));
 191:     while (limit > 0)
 192:       {
 193:         result[i  ] = (byte) fromDigit(s.charAt(--limit));
 194:         result[i++] |= (byte) (fromDigit(s.charAt(--limit)) << 4);
 195:       }
 196:     return result;
 197:   }
 198: 
 199:   /**
 200:    * Returns a number from <code>0</code> to <code>15</code> corresponding
 201:    * to the designated hexadecimal digit.
 202:    * 
 203:    * @param c a hexadecimal ASCII symbol.
 204:    */
 205:   public static int fromDigit(char c)
 206:   {
 207:     if (c >= '0' && c <= '9')
 208:       return c - '0';
 209:     else if (c >= 'A' && c <= 'F')
 210:       return c - 'A' + 10;
 211:     else if (c >= 'a' && c <= 'f')
 212:       return c - 'a' + 10;
 213:     else
 214:       throw new IllegalArgumentException("Invalid hexadecimal digit: " + c);
 215:   }
 216: 
 217:   /**
 218:    * Returns a string of 8 hexadecimal digits (most significant digit first)
 219:    * corresponding to the unsigned integer <code>n</code>.
 220:    * 
 221:    * @param n the unsigned integer to convert.
 222:    * @return a hexadecimal string 8-character long.
 223:    */
 224:   public static String toString(int n)
 225:   {
 226:     char[] buf = new char[8];
 227:     for (int i = 7; i >= 0; i--)
 228:       {
 229:         buf[i] = HEX_DIGITS[n & 0x0F];
 230:         n >>>= 4;
 231:       }
 232:     return new String(buf);
 233:   }
 234: 
 235:   /**
 236:    * Returns a string of hexadecimal digits from an integer array. Each int is
 237:    * converted to 4 hex symbols.
 238:    */
 239:   public static String toString(int[] ia)
 240:   {
 241:     int length = ia.length;
 242:     char[] buf = new char[length * 8];
 243:     for (int i = 0, j = 0, k; i < length; i++)
 244:       {
 245:         k = ia[i];
 246:         buf[j++] = HEX_DIGITS[(k >>> 28) & 0x0F];
 247:         buf[j++] = HEX_DIGITS[(k >>> 24) & 0x0F];
 248:         buf[j++] = HEX_DIGITS[(k >>> 20) & 0x0F];
 249:         buf[j++] = HEX_DIGITS[(k >>> 16) & 0x0F];
 250:         buf[j++] = HEX_DIGITS[(k >>> 12) & 0x0F];
 251:         buf[j++] = HEX_DIGITS[(k >>>  8) & 0x0F];
 252:         buf[j++] = HEX_DIGITS[(k >>>  4) & 0x0F];
 253:         buf[j++] = HEX_DIGITS[ k         & 0x0F];
 254:       }
 255:     return new String(buf);
 256:   }
 257: 
 258:   /**
 259:    * Returns a string of 16 hexadecimal digits (most significant digit first)
 260:    * corresponding to the unsigned long <code>n</code>.
 261:    * 
 262:    * @param n the unsigned long to convert.
 263:    * @return a hexadecimal string 16-character long.
 264:    */
 265:   public static String toString(long n)
 266:   {
 267:     char[] b = new char[16];
 268:     for (int i = 15; i >= 0; i--)
 269:       {
 270:         b[i] = HEX_DIGITS[(int)(n & 0x0FL)];
 271:         n >>>= 4;
 272:       }
 273:     return new String(b);
 274:   }
 275: 
 276:   /**
 277:    * Similar to the <code>toString()</code> method except that the Unicode
 278:    * escape character is inserted before every pair of bytes. Useful to
 279:    * externalise byte arrays that will be constructed later from such strings;
 280:    * eg. s-box values.
 281:    * 
 282:    * @throws ArrayIndexOutOfBoundsException if the length is odd.
 283:    */
 284:   public static String toUnicodeString(byte[] ba)
 285:   {
 286:     return toUnicodeString(ba, 0, ba.length);
 287:   }
 288: 
 289:   /**
 290:    * Similar to the <code>toString()</code> method except that the Unicode
 291:    * escape character is inserted before every pair of bytes. Useful to
 292:    * externalise byte arrays that will be constructed later from such strings;
 293:    * eg. s-box values.
 294:    * 
 295:    * @throws ArrayIndexOutOfBoundsException if the length is odd.
 296:    */
 297:   public static final String toUnicodeString(byte[] ba, int offset, int length)
 298:   {
 299:     StringBuffer sb = new StringBuffer();
 300:     int i = 0;
 301:     int j = 0;
 302:     int k;
 303:     sb.append('\n').append("\"");
 304:     while (i < length)
 305:       {
 306:         sb.append("\\u");
 307:         k = ba[offset + i++];
 308:         sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]);
 309:         sb.append(HEX_DIGITS[ k        & 0x0F]);
 310:         k = ba[offset + i++];
 311:         sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]);
 312:         sb.append(HEX_DIGITS[ k        & 0x0F]);
 313:         if ((++j % 8) == 0)
 314:           sb.append("\"+").append('\n').append("\"");
 315:       }
 316:     sb.append("\"").append('\n');
 317:     return sb.toString();
 318:   }
 319: 
 320:   /**
 321:    * Similar to the <code>toString()</code> method except that the Unicode
 322:    * escape character is inserted before every pair of bytes. Useful to
 323:    * externalise integer arrays that will be constructed later from such
 324:    * strings; eg. s-box values.
 325:    * 
 326:    * @throws ArrayIndexOutOfBoundsException if the length is not a multiple of
 327:    *           4.
 328:    */
 329:   public static String toUnicodeString(int[] ia)
 330:   {
 331:     StringBuffer sb = new StringBuffer();
 332:     int i = 0;
 333:     int j = 0;
 334:     int k;
 335:     sb.append('\n').append("\"");
 336:     while (i < ia.length)
 337:       {
 338:         k = ia[i++];
 339:         sb.append("\\u");
 340:         sb.append(HEX_DIGITS[(k >>> 28) & 0x0F]);
 341:         sb.append(HEX_DIGITS[(k >>> 24) & 0x0F]);
 342:         sb.append(HEX_DIGITS[(k >>> 20) & 0x0F]);
 343:         sb.append(HEX_DIGITS[(k >>> 16) & 0x0F]);
 344:         sb.append("\\u");
 345:         sb.append(HEX_DIGITS[(k >>> 12) & 0x0F]);
 346:         sb.append(HEX_DIGITS[(k >>>  8) & 0x0F]);
 347:         sb.append(HEX_DIGITS[(k >>>  4) & 0x0F]);
 348:         sb.append(HEX_DIGITS[ k         & 0x0F]);
 349:         if ((++j % 4) == 0)
 350:           sb.append("\"+").append('\n').append("\"");
 351:       }
 352:     sb.append("\"").append('\n');
 353:     return sb.toString();
 354:   }
 355: 
 356:   public static byte[] toBytesFromUnicode(String s)
 357:   {
 358:     int limit = s.length() * 2;
 359:     byte[] result = new byte[limit];
 360:     char c;
 361:     for (int i = 0; i < limit; i++)
 362:       {
 363:         c = s.charAt(i >>> 1);
 364:         result[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c);
 365:       }
 366:     return result;
 367:   }
 368: 
 369:   /**
 370:    * Dumps a byte array as a string, in a format that is easy to read for
 371:    * debugging. The string <code>m</code> is prepended to the start of each
 372:    * line.
 373:    * <p>
 374:    * If <code>offset</code> and <code>length</code> are omitted, the whole
 375:    * array is used. If <code>m</code> is omitted, nothing is prepended to each
 376:    * line.
 377:    * 
 378:    * @param data the byte array to be dumped.
 379:    * @param offset the offset within <i>data</i> to start from.
 380:    * @param length the number of bytes to dump.
 381:    * @param m a string to be prepended to each line.
 382:    * @return a string containing the result.
 383:    */
 384:   public static String dumpString(byte[] data, int offset, int length, String m)
 385:   {
 386:     if (data == null)
 387:       return m + "null\n";
 388:     StringBuffer sb = new StringBuffer(length * 3);
 389:     if (length > 32)
 390:       sb.append(m).append("Hexadecimal dump of ")
 391:           .append(length).append(" bytes...\n");
 392:     // each line will list 32 bytes in 4 groups of 8 each
 393:     int end = offset + length;
 394:     String s;
 395:     int l = Integer.toString(length).length();
 396:     if (l < 4)
 397:       l = 4;
 398:     for (; offset < end; offset += 32)
 399:       {
 400:         if (length > 32)
 401:           {
 402:             s = "         " + offset;
 403:             sb.append(m).append(s.substring(s.length() - l)).append(": ");
 404:           }
 405:         int i = 0;
 406:         for (; i < 32 && offset + i + 7 < end; i += 8)
 407:           sb.append(toString(data, offset + i, 8)).append(' ');
 408:         if (i < 32)
 409:           for (; i < 32 && offset + i < end; i++)
 410:             sb.append(byteToString(data[offset + i]));
 411:         sb.append('\n');
 412:       }
 413:     return sb.toString();
 414:   }
 415: 
 416:   public static String dumpString(byte[] data)
 417:   {
 418:     return (data == null) ? "null\n" : dumpString(data, 0, data.length, "");
 419:   }
 420: 
 421:   public static String dumpString(byte[] data, String m)
 422:   {
 423:     return (data == null) ? "null\n" : dumpString(data, 0, data.length, m);
 424:   }
 425: 
 426:   public static String dumpString(byte[] data, int offset, int length)
 427:   {
 428:     return dumpString(data, offset, length, "");
 429:   }
 430: 
 431:   /**
 432:    * Returns a string of 2 hexadecimal digits (most significant digit first)
 433:    * corresponding to the lowest 8 bits of <code>n</code>.
 434:    * 
 435:    * @param n the byte value to convert.
 436:    * @return a string of 2 hex characters representing the input.
 437:    */
 438:   public static String byteToString(int n)
 439:   {
 440:     char[] buf = { HEX_DIGITS[(n >>> 4) & 0x0F], HEX_DIGITS[n & 0x0F] };
 441:     return new String(buf);
 442:   }
 443: 
 444:   /**
 445:    * Converts a designated byte array to a Base-64 representation, with the
 446:    * exceptions that (a) leading 0-byte(s) are ignored, and (b) the character
 447:    * '.' (dot) shall be used instead of "+' (plus).
 448:    * <p>
 449:    * Used by SASL password file manipulation primitives.
 450:    * 
 451:    * @param buffer an arbitrary sequence of bytes to represent in Base-64.
 452:    * @return unpadded (without the '=' character(s)) Base-64 representation of
 453:    *         the input.
 454:    */
 455:   public static final String toBase64(byte[] buffer)
 456:   {
 457:     int len = buffer.length, pos = len % 3;
 458:     byte b0 = 0, b1 = 0, b2 = 0;
 459:     switch (pos)
 460:       {
 461:       case 1:
 462:         b2 = buffer[0];
 463:         break;
 464:       case 2:
 465:         b1 = buffer[0];
 466:         b2 = buffer[1];
 467:         break;
 468:       }
 469:     StringBuffer sb = new StringBuffer();
 470:     int c;
 471:     boolean notleading = false;
 472:     do
 473:       {
 474:         c = (b0 & 0xFC) >>> 2;
 475:         if (notleading || c != 0)
 476:           {
 477:             sb.append(BASE64_CHARSET[c]);
 478:             notleading = true;
 479:           }
 480:         c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >>> 4);
 481:         if (notleading || c != 0)
 482:           {
 483:             sb.append(BASE64_CHARSET[c]);
 484:             notleading = true;
 485:           }
 486:         c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >>> 6);
 487:         if (notleading || c != 0)
 488:           {
 489:             sb.append(BASE64_CHARSET[c]);
 490:             notleading = true;
 491:           }
 492:         c = b2 & 0x3F;
 493:         if (notleading || c != 0)
 494:           {
 495:             sb.append(BASE64_CHARSET[c]);
 496:             notleading = true;
 497:           }
 498:         if (pos >= len)
 499:           break;
 500:         else
 501:           {
 502:             try
 503:               {
 504:                 b0 = buffer[pos++];
 505:                 b1 = buffer[pos++];
 506:                 b2 = buffer[pos++];
 507:               }
 508:             catch (ArrayIndexOutOfBoundsException x)
 509:               {
 510:                 break;
 511:               }
 512:           }
 513:       }
 514:     while (true);
 515: 
 516:     if (notleading)
 517:       return sb.toString();
 518:     return "0";
 519:   }
 520: 
 521:   /**
 522:    * The inverse function of the above.
 523:    * <p>
 524:    * Converts a string representing the encoding of some bytes in Base-64 to
 525:    * their original form.
 526:    * 
 527:    * @param str the Base-64 encoded representation of some byte(s).
 528:    * @return the bytes represented by the <code>str</code>.
 529:    * @throws NumberFormatException if <code>str</code> is <code>null</code>,
 530:    *           or <code>str</code> contains an illegal Base-64 character.
 531:    * @see #toBase64(byte[])
 532:    */
 533:   public static final byte[] fromBase64(String str)
 534:   {
 535:     int len = str.length();
 536:     if (len == 0)
 537:       throw new NumberFormatException("Empty string");
 538:     byte[] a = new byte[len + 1];
 539:     int i, j;
 540:     for (i = 0; i < len; i++)
 541:       try
 542:         {
 543:           a[i] = (byte) BASE64_CHARS.indexOf(str.charAt(i));
 544:         }
 545:       catch (ArrayIndexOutOfBoundsException x)
 546:         {
 547:           throw new NumberFormatException("Illegal character at #" + i);
 548:         }
 549:     i = len - 1;
 550:     j = len;
 551:     try
 552:       {
 553:         while (true)
 554:           {
 555:             a[j] = a[i];
 556:             if (--i < 0)
 557:               break;
 558:             a[j] |= (a[i] & 0x03) << 6;
 559:             j--;
 560:             a[j] = (byte)((a[i] & 0x3C) >>> 2);
 561:             if (--i < 0)
 562:               break;
 563:             a[j] |= (a[i] & 0x0F) << 4;
 564:             j--;
 565:             a[j] = (byte)((a[i] & 0x30) >>> 4);
 566:             if (--i < 0)
 567:               break;
 568:             a[j] |= (a[i] << 2);
 569:             j--;
 570:             a[j] = 0;
 571:             if (--i < 0)
 572:               break;
 573:           }
 574:       }
 575:     catch (Exception ignored)
 576:       {
 577:       }
 578:     try
 579:       { // ignore leading 0-bytes
 580:         while (a[j] == 0)
 581:           j++;
 582:       }
 583:     catch (Exception x)
 584:       {
 585:         return new byte[1]; // one 0-byte
 586:       }
 587:     byte[] result = new byte[len - j + 1];
 588:     System.arraycopy(a, j, result, 0, len - j + 1);
 589:     return result;
 590:   }
 591: 
 592:   // BigInteger utilities ----------------------------------------------------
 593: 
 594:   /**
 595:    * Treats the input as the MSB representation of a number, and discards
 596:    * leading zero elements. For efficiency, the input is simply returned if no
 597:    * leading zeroes are found.
 598:    * 
 599:    * @param n the {@link BigInteger} to trim.
 600:    * @return the byte array representation of the designated {@link BigInteger}
 601:    *         with no leading 0-bytes.
 602:    */
 603:   public static final byte[] trim(BigInteger n)
 604:   {
 605:     byte[] in = n.toByteArray();
 606:     if (in.length == 0 || in[0] != 0)
 607:       return in;
 608:     int len = in.length;
 609:     int i = 1;
 610:     while (in[i] == 0 && i < len)
 611:       ++i;
 612:     byte[] result = new byte[len - i];
 613:     System.arraycopy(in, i, result, 0, len - i);
 614:     return result;
 615:   }
 616: 
 617:   /**
 618:    * Returns a hexadecimal dump of the trimmed bytes of a {@link BigInteger}.
 619:    * 
 620:    * @param x the {@link BigInteger} to display.
 621:    * @return the string representation of the designated {@link BigInteger}.
 622:    */
 623:   public static final String dump(BigInteger x)
 624:   {
 625:     return dumpString(trim(x));
 626:   }
 627: }