Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4808611

REGRESSION: DSA Signature Verification Fails (1.4.0 -> 1.4.1/1.4.1_01)

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P3 P3
    • None
    • 1.4.1, 1.4.1_01
    • security-libs
    • x86, sparc
    • solaris_8, windows_2000


                          ibufcount = 0;
                          int obufcount = decode0(ibuf, obuf, 0);
                          ostream.write(obuf, 0, obufcount);
                      }
                  }
              }

          }

          public static String encode(byte data[]) {
              return encode(data, 0, data.length);
          }

          public static String encode(byte data[], int off, int len) {
              if (len <= 0)
                  return "";
              char out[] = new char[(len / 3) * 4 + 4];
              int rindex = off;
              int windex = 0;
              int rest;
              for (rest = len; rest >= 3; rest -= 3) {
                  int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff);
                  out[windex++] = S_BASE64CHAR[i >> 18];
                  out[windex++] = S_BASE64CHAR[i >> 12 & 0x3f];
                  out[windex++] = S_BASE64CHAR[i >> 6 & 0x3f];
                  out[windex++] = S_BASE64CHAR[i & 0x3f];
                  rindex += 3;
              }

              if (rest == 1) {
                  int i = data[rindex] & 0xff;
                  out[windex++] = S_BASE64CHAR[i >> 2];
                  out[windex++] = S_BASE64CHAR[i << 4 & 0x3f];
                  out[windex++] = '=';
                  out[windex++] = '=';
              } else if (rest == 2) {
                  int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
                  out[windex++] = S_BASE64CHAR[i >> 10];
                  out[windex++] = S_BASE64CHAR[i >> 4 & 0x3f];
                  out[windex++] = S_BASE64CHAR[i << 2 & 0x3f];
                  out[windex++] = '=';
              }
              return new String(out, 0, windex);
          }

          public static void encode(byte data[], int off, int len, OutputStream ostream) throws IOException {
              if (len <= 0)
                  return;
              byte out[] = new byte[4];
              int rindex = off;
              int rest;
              for (rest = len - off; rest >= 3; rest -= 3) {
                  int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff);
                  out[0] = (byte) S_BASE64CHAR[i >> 18];
                  out[1] = (byte) S_BASE64CHAR[i >> 12 & 0x3f];
                  out[2] = (byte) S_BASE64CHAR[i >> 6 & 0x3f];
                  out[3] = (byte) S_BASE64CHAR[i & 0x3f];
                  ostream.write(out, 0, 4);
                  rindex += 3;
              }

              if (rest == 1) {
                  int i = data[rindex] & 0xff;
                  out[0] = (byte) S_BASE64CHAR[i >> 2];
                  out[1] = (byte) S_BASE64CHAR[i << 4 & 0x3f];
                  out[2] = 61;
                  out[3] = 61;
                  ostream.write(out, 0, 4);
              } else if (rest == 2) {
                  int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
                  out[0] = (byte) S_BASE64CHAR[i >> 10];
                  out[1] = (byte) S_BASE64CHAR[i >> 4 & 0x3f];
                  out[2] = (byte) S_BASE64CHAR[i << 2 & 0x3f];
                  out[3] = 61;
                  ostream.write(out, 0, 4);
              }
          }

          public static void encode(byte data[], int off, int len, Writer writer) throws IOException {
              if (len <= 0)
                  return;
              char out[] = new char[4];
              int rindex = off;
              int rest = len - off;
              int output = 0;
              while (rest >= 3) {
                  int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff);
                  out[0] = S_BASE64CHAR[i >> 18];
                  out[1] = S_BASE64CHAR[i >> 12 & 0x3f];
                  out[2] = S_BASE64CHAR[i >> 6 & 0x3f];
                  out[3] = S_BASE64CHAR[i & 0x3f];
                  writer.write(out, 0, 4);
                  rindex += 3;
                  rest -= 3;
                  if ((output += 4) % 76 == 0)
                      writer.write("\n");
              }
              if (rest == 1) {
                  int i = data[rindex] & 0xff;
                  out[0] = S_BASE64CHAR[i >> 2];
                  out[1] = S_BASE64CHAR[i << 4 & 0x3f];
                  out[2] = '=';
                  out[3] = '=';
                  writer.write(out, 0, 4);
              } else if (rest == 2) {
                  int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
                  out[0] = S_BASE64CHAR[i >> 10];
                  out[1] = S_BASE64CHAR[i >> 4 & 0x3f];
                  out[2] = S_BASE64CHAR[i << 2 & 0x3f];
                  out[3] = '=';
                  writer.write(out, 0, 4);
              }
          }

          public static String format(String src, int indent, String leading, String trailing) {
              if (indent >= 76)
                  throw new RuntimeException("Specified indnet is too large: " + indent);
              int lines = src.length() / (76 - indent) + 1;
              StringBuffer buffer = new StringBuffer(lines * 76 + leading.length() + trailing.length());
              buffer.append(leading);
              for (int index = 0; index < src.length(); buffer.append('\n')) {
                  for (int i = 0; i < indent; i++)
                      buffer.append(' ');

                  int endIndex = Math.min((index + 76) - indent, src.length());
                  buffer.append(src.substring(index, endIndex));
                  index = endIndex;
              }

              buffer.append(trailing);
              return new String(buffer);
          }

          public static String toHexString(byte ab[]) {
              StringBuffer buffer = new StringBuffer(ab.length * 2);
              for (int i = 0; i < ab.length; i++) {
                  buffer.append("0123456789ABCDEF".charAt(ab[i] >> 4 & 0xf));
                  buffer.append("0123456789ABCDEF".charAt(ab[i] & 0xf));
              }

              return new String(buffer);
          }

          private static final char S_BASE64CHAR[] =
              {
                  'A',
                  'B',
                  'C',
                  'D',
                  'E',
                  'F',
                  'G',
                  'H',
                  'I',
                  'J',
                  'K',
                  'L',
                  'M',
                  'N',
                  'O',
                  'P',
                  'Q',
                  'R',
                  'S',
                  'T',
                  'U',
                  'V',
                  'W',
                  'X',
                  'Y',
                  'Z',
                  'a',
                  'b',
                  'c',
                  'd',
                  'e',
                  'f',
                  'g',
                  'h',
                  'i',
                  'j',
                  'k',
                  'l',
                  'm',
                  'n',
                  'o',
                  'p',
                  'q',
                  'r',
                  's',
                  't',
                  'u',
                  'v',
                  'w',
                  'x',
                  'y',
                  'z',
                  '0',
                  '1',
                  '2',
                  '3',
                  '4',
                  '5',
                  '6',
                  '7',
                  '8',
                  '9',
                  '+',
                  '/' };
          private static final char S_BASE64PAD = 61;
          private static final byte S_DECODETABLE[];
          private static final String tab = "0123456789ABCDEF";

          static {
              S_DECODETABLE = new byte[128];
              for (int i = 0; i < S_DECODETABLE.length; i++)
                  S_DECODETABLE[i] = 127;

              for (int i = 0; i < S_BASE64CHAR.length; i++)
                  S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i;

          }
      }


      ---------- END SOURCE ----------

      Release Regression From : 1.4
      The above release value was the last known release where this
      bug was known to work. Since then there has been a regression.

      (Review ID: 178766)
      ======================================================================


      Name: nt126004 Date: 01/27/2003


      FULL PRODUCT VERSION :
      java version "1.4.1_01"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
      Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

      FULL OPERATING SYSTEM VERSION :
      Microsoft Windows 2000 [Version 5.00.2195]

      ADDITIONAL OPERATING SYSTEMS :

      Linux Redhat 7.2

      A DESCRIPTION OF THE PROBLEM :
      I have a digital signature that was produced with a DSA key
      in JDK 1.4.0, I am able to verify the signature using JDK
      1.4.0 as well as .Net but not with JDK 1.4.1 or JDK
      1.4.1_01.

      REGRESSION. Last worked in version 1.4

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Sign with a DSA key in JDK 1.4.0
      2. Try to verify the signature in JDK 1.4.1 or JDK
      1.4.1_01. I several cases the verification fails.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      In about 30% of the signatures produced in Step #1, the
      verification failed in JDK 1.4.1 and JDK 1.4.1_01. The
      verification succeeded in JDK 1.4.0 and .Net.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      DSA Verify Failed: invalid signature: out of range values
      java.security.SignatureException: invalid signature: out of range values
      at sun.security.provider.DSA.engineVerify(DSA.java:228)
      at sun.security.provider.DSA.engineVerify(DSA.java:182)
      at java.security.Signature.verify(Signature.java:464)
      at bug.BugReport.main(BugReport.java:59)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package bug;

      import java.io.ByteArrayInputStream;
      import java.security.PublicKey;
      import java.security.Signature;
      import java.security.SignatureException;
      import java.security.cert.CertificateFactory;
      import java.security.cert.X509Certificate;

      /**
       * This class represents a localized version of a bug that i got while
      verifying an
       * XML Document containing a signature signed using a DSA key.
       *
       * This works with JDK 1.4.0 but fails with JDK 1.4.1 and JDK 1.4.1_01 (failing
      with a
       * java.security.SignatureException: invalid signature: out of range values).
       * In my humble opinion: there is a regression with the DSA verify in JDK 1.4.1
      and above.
       *
       * Base64 is a class that is used to decode the certificate. (I have not
      included the source for that)
       * @author Maneesh Sahu (###@###.###)
       *
       */
      public class BugReport {
          public static void main(String[] args) throws Exception {
              try {
                  byte[] signature = {48, 44, 2, 20, 82, 19, -68, 93, -11, -109, -
      51, -33, -15, 3, -109, 107, -58, -96, 71, 22, 47, 74, -31, 24, 2, 20, -127, -
      97, 49, -24, 99, 111, 40, -27, 25, 106, -24, -17, -66, -7, -59, -53, -12, 36, -
      125, 68};
                          
                  byte[] hash = {60, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111,
      32, 120, 109, 108, 110, 115, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119,
      119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120,
      109, 108, 100, 115, 105, 103, 35, 34, 32, 120, 109, 108, 110, 115, 58, 83, 79,
      65, 80, 45, 69, 78, 67, 61, 34, 104, 116, 116, 112, 58, 47, 47, 115, 99, 104,
      101, 109, 97, 115, 46, 120, 109, 108, 115, 111, 97, 112, 46, 111, 114, 103, 47,
      115, 111, 97, 112, 47, 101, 110, 99, 111, 100, 105, 110, 103, 47, 34, 32, 120,
      109, 108, 110, 115, 58, 83, 79, 65, 80, 45, 69, 78, 86, 61, 34, 104, 116, 116,
      112, 58, 47, 47, 115, 99, 104, 101, 109, 97, 115, 46, 120, 109, 108, 115, 111,
      97, 112, 46, 111, 114, 103, 47, 115, 111, 97, 112, 47, 101, 110, 118, 101, 108,
      111, 112, 101, 47, 34, 32, 120, 109, 108, 110, 115, 58, 105, 109, 112, 108, 61,
      34, 104, 116, 116, 112, 58, 47, 47, 120, 109, 115, 45, 100, 101, 109, 111, 46,
      119, 101, 115, 116, 98, 114, 105, 100, 103, 101, 116, 101, 99, 104, 46, 99,
      111, 109, 47, 97, 120, 105, 115, 47, 99, 111, 114, 112, 45, 100, 101, 109, 111,
      47, 84, 114, 97, 100, 101, 83, 101, 99, 117, 114, 105, 116, 121, 46, 106, 119,
      115, 45, 105, 109, 112, 108, 34, 32, 120, 109, 108, 110, 115, 58, 105, 110,
      116, 102, 61, 34, 104, 116, 116, 112, 58, 47, 47, 120, 109, 115, 45, 100, 101,
      109, 111, 46, 119, 101, 115, 116, 98, 114, 105, 100, 103, 101, 116, 101, 99,
      104, 46, 99, 111, 109, 47, 97, 120, 105, 115, 47, 99, 111, 114, 112, 45, 100,
      101, 109, 111, 47, 84, 114, 97, 100, 101, 83, 101, 99, 117, 114, 105, 116, 121,
      46, 106, 119, 115, 34, 32, 120, 109, 108, 110, 115, 58, 119, 115, 100, 108, 61,
      34, 104, 116, 116, 112, 58, 47, 47, 115, 99, 104, 101, 109, 97, 115, 46, 120,
      109, 108, 115, 111, 97, 112, 46, 111, 114, 103, 47, 119, 115, 100, 108, 47, 34,
      32, 120, 109, 108, 110, 115, 58, 119, 115, 100, 108, 115, 111, 97, 112, 61, 34,
      104, 116, 116, 112, 58, 47, 47, 115, 99, 104, 101, 109, 97, 115, 46, 120, 109,
      108, 115, 111, 97, 112, 46, 111, 114, 103, 47, 119, 115, 100, 108, 47, 115,
      111, 97, 112, 47, 34, 32, 120, 109, 108, 110, 115, 58, 120, 115, 100, 61, 34,
      104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103,
      47, 50, 48, 48, 49, 47, 88, 77, 76, 83, 99, 104, 101, 109, 97, 34, 32, 120,
      109, 108, 110, 115, 58, 120, 115, 105, 61, 34, 104, 116, 116, 112, 58, 47, 47,
      119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 88, 77,
      76, 83, 99, 104, 101, 109, 97, 45, 105, 110, 115, 116, 97, 110, 99, 101, 34,
      62, 10, 60, 67, 97, 110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105,
      111, 110, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116,
      104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51,
      46, 111, 114, 103, 47, 84, 82, 47, 50, 48, 48, 49, 47, 82, 69, 67, 45, 120,
      109, 108, 45, 99, 49, 52, 110, 45, 50, 48, 48, 49, 48, 51, 49, 53, 34, 62, 60,
      47, 67, 97, 110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105, 111, 110,
      77, 101, 116, 104, 111, 100, 62, 10, 60, 83, 105, 103, 110, 97, 116, 117, 114,
      101, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104,
      109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46,
      111, 114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115,
      105, 103, 35, 100, 115, 97, 45, 115, 104, 97, 49, 34, 62, 60, 47, 83, 105, 103,
      110, 97, 116, 117, 114, 101, 77, 101, 116, 104, 111, 100, 62, 10, 60, 82, 101,
      102, 101, 114, 101, 110, 99, 101, 32, 85, 82, 73, 61, 34, 34, 62, 10, 60, 84,
      114, 97, 110, 115, 102, 111, 114, 109, 115, 62, 10, 60, 84, 114, 97, 110, 115,
      102, 111, 114, 109, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34,
      104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103,
      47, 84, 82, 47, 49, 57, 57, 57, 47, 82, 69, 67, 45, 120, 112, 97, 116, 104, 45,
      49, 57, 57, 57, 49, 49, 49, 54, 34, 62, 10, 60, 88, 80, 97, 116, 104, 32, 120,
      109, 108, 110, 115, 58, 100, 115, 105, 103, 61, 34, 104, 116, 116, 112, 58, 47,
      47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48, 47, 48,
      57, 47, 120, 109, 108, 100, 115, 105, 103, 35, 34, 62, 10, 97, 110, 99, 101,
      115, 116, 111, 114, 45, 111, 114, 45, 115, 101, 108, 102, 58, 58, 116, 105, 99,
      107, 101, 114, 83, 121, 109, 98, 111, 108, 10, 60, 47, 88, 80, 97, 116, 104,
      62, 10, 60, 47, 84, 114, 97, 110, 115, 102, 111, 114, 109, 62, 10, 60, 47, 84,
      114, 97, 110, 115, 102, 111, 114, 109, 115, 62, 10, 60, 68, 105, 103, 101, 115,
      116, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104,
      109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46,
      111, 114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115,
      105, 103, 35, 115, 104, 97, 49, 34, 62, 60, 47, 68, 105, 103, 101, 115, 116,
      77, 101, 116, 104, 111, 100, 62, 10, 60, 68, 105, 103, 101, 115, 116, 86, 97,
      108, 117, 101, 62, 55, 66, 71, 83, 51, 67, 116, 81, 69, 50, 52, 80, 121, 87,
      88, 53, 50, 80, 55, 109, 50, 68, 107, 100, 86, 116, 99, 61, 60, 47, 68, 105,
      103, 101, 115, 116, 86, 97, 108, 117, 101, 62, 10, 60, 47, 82, 101, 102, 101,
      114, 101, 110, 99, 101, 62, 10, 60, 47, 83, 105, 103, 110, 101, 100, 73, 110,
      102, 111, 62};

                  String cert =
                      "MIIDPzCCAv0CBD3ddWowCwYHKoZIzjgEAwUAMIGEMQswCQYDVQQGEwJVUzELMAk
      GA1UECBMCQ0Ex\n"
                          
      + "FjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHjAcBgNVBAoTFVdlc3RicmlkZ2UgVGVjaG5vbG9neTEUn"
                          
      + "MBIGA1UECxMLRW5naW5lZXJpbmcxGjAYBgNVBAMTEUFuZHJlYXMgRGhhcm1hd2FuMB4XDTAyMTEyn"
                          
      + "MjAwMDgxMFoXDTAzMTExNzAwMDgxMFowgYQxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGn"
                          
      + "A1UEBxMNTW91bnRhaW4gVmlldzEeMBwGA1UEChMVV2VzdGJyaWRnZSBUZWNobm9sb2d5MRQwEgYDn"
                          
      + "VQQLEwtFbmdpbmVlcmluZzEaMBgGA1UEAxMRQW5kcmVhcyBEaGFybWF3YW4wggG4MIIBLAYHKoZIn"
                          
      + "zjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/Fn"
                          
      + "9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7Dn"
                          
      + "AjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCFn"
                          
      + "1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMn"
                          
      + "yKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7
      \n"
                          
      + "VSVkAUw7/s9JKgOBhQACgYEAlhscM0K3IBsqPDRl9ZFH601bqznfpM1bRfDkS3tzM46wYc2HytcYn"
                          
      + "lIx1PkbtMTUPBbi8vKqq6LwdDNyYbi9exJQHoLfnhkM/2xetDdlLmDh1wojqbQVFRxLlGIb3flv/
      \n"
                          
      + "5P6ZQkD52ui5c32ZIPtrYJt9BX3BAU7nBgJKGrcnkZgwCwYHKoZIzjgEAwUAAy8AMCwCFElyBSFin"
                          + "MIXQiNn1u+CBuqhY2PUAAhR/o1fMmtsLTUw3Aq/eiymM+oM0cg==";

                  CertificateFactory certFactory = CertificateFactory.getInstance
      ("X.509");
                  byte certbytes[] = Base64.decode(cert);
                  ByteArrayInputStream bais = new ByteArrayInputStream(certbytes);
                  X509Certificate certificate = (X509Certificate)
      certFactory.generateCertificate(bais);
                  PublicKey pKey = certificate.getPublicKey();

                  Signature sig = Signature.getInstance("SHA1withDSA");
                  sig.initVerify(pKey);
                  sig.update(hash);
                  sig.verify(signature);
                  System.out.println("DSA Verify Succeeded");
              } catch (SignatureException sexc) {
                  System.err.println("DSA Verify Failed: " + sexc.getMessage());
                  sexc.printStackTrace();
              }
          }
      }

      // Base64.java
      import java.io.IOException;
      import java.io.OutputStream;
      import java.io.Writer;

      public class Base64 {

          public Base64() {
          }

          private static int decode0(char ibuf[], byte obuf[], int wp) {
              int outlen = 3;
              if (ibuf[3] == '=')
                  outlen = 2;
              if (ibuf[2] == '=')
                  outlen = 1;
              int b0 = S_DECODETABLE[ibuf[0]];
              int b1 = S_DECODETABLE[ibuf[1]];
              int b2 = S_DECODETABLE[ibuf[2]];
              int b3 = S_DECODETABLE[ibuf[3]];
              switch (outlen) {
                  case 1 : // '\001'
                      obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 3);
                      return 1;

                  case 2 : // '\002'
                      obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 3);
                      obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
                      return 2;

                  case 3 : // '\003'
                      obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 3);
                      obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
                      obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);
                      return 3;
              }
              throw new RuntimeException("Internal Errror");
          }

          public static byte[] decode(char data[], int off, int len) {
              char ibuf[] = new char[4];
              int ibufcount = 0;
              byte obuf[] = new byte[(len / 4) * 3 + 3];
              int obufcount = 0;
              for (int i = off; i < off + len; i++) {
                  char ch = data[i];
                  if (ch == '=' || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != 127) {
                      ibuf[ibufcount++] = ch;
                      if (ibufcount == ibuf.length) {
                          ibufcount = 0;
                          obufcount += decode0(ibuf, obuf, obufcount);
                      }
                  }
              }

              if (obufcount == obuf.length) {
                  return obuf;
              } else {
                  byte ret[] = new byte[obufcount];
                  System.arraycopy(obuf, 0, ret, 0, obufcount);
                  return ret;
              }
          }

          public static byte[] decode(String data) {
              char ibuf[] = new char[4];
              int ibufcount = 0;
              byte obuf[] = new byte[(data.length() / 4) * 3 + 3];
              int obufcount = 0;
              for (int i = 0; i < data.length(); i++) {
                  char ch = data.charAt(i);
                  if (ch == '=' || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != 127) {
                      ibuf[ibufcount++] = ch;
                      if (ibufcount == ibuf.length) {
                          ibufcount = 0;
                          obufcount += decode0(ibuf, obuf, obufcount);
                      }
                  }
              }

              if (obufcount == obuf.length) {
                  return obuf;
              } else {
                  byte ret[] = new byte[obufcount];
                  System.arraycopy(obuf, 0, ret, 0, obufcount);
                  return ret;
              }
          }

          public static byte[] decode(byte data[]) {
              return decode(data, 0, data.length);
          }

          public static byte[] decode(byte data[], int off, int len) {
              char ibuf[] = new char[4];
              int ibufcount = 0;
              byte obuf[] = new byte[(len / 4) * 3 + 3];
              int obufcount = 0;
              for (int i = off; i < off + len; i++) {
                  char ch = (char) data[i];
                  if (ch == '=' || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != 127) {
                      ibuf[ibufcount++] = ch;
                      if (ibufcount == ibuf.length) {
                          ibufcount = 0;
                          obufcount += decode0(ibuf, obuf, obufcount);
                      }
                  }
              }

              if (obufcount == obuf.length) {
                  return obuf;
              } else {
                  byte ret[] = new byte[obufcount];
                  System.arraycopy(obuf, 0, ret, 0, obufcount);
                  return ret;
              }
          }

          public static void decode(char data[], int off, int len, OutputStream ostream) throws IOException {
              char ibuf[] = new char[4];
              int ibufcount = 0;
              byte obuf[] = new byte[3];
              for (int i = off; i < off + len; i++) {
                  char ch = data[i];
                  if (ch == '=' || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != 127) {
                      ibuf[ibufcount++] = ch;
                      if (ibufcount == ibuf.length) {
                          ibufcount = 0;
                          int obufcount = decode0(ibuf, obuf, 0);
                          ostream.write(obuf, 0, obufcount);
                      }
                  }
              }

          }

          public static void decode(String data, OutputStream ostream) throws IOException {
              char ibuf[] = new char[4];
              int ibufcount = 0;
              byte obuf[] = new byte[3];
              for (int i = 0; i < data.length(); i++) {
                  char ch = data.charAt(i);
                  if (ch == '=' || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != 127) {
                      ibuf[ibufcount++] = ch;
                      if (ibufcount == ibuf.length) {

            andreas Andreas Sterbenz
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: