public static String encode(byte[] data) {
    int dataLength = data.length;
    if (dataLength == 0) {
      return "";
    }

    // SHIFT is the number of bits per output character, so the length of the
    // output is the length of the input multiplied by 8/SHIFT, rounded up.
    if (dataLength >= (1 << 28)) {
      // The computation below will fail, so don't do it.
      throw new IllegalArgumentException();
    }

    int outputLength = (dataLength * 8 + SHIFT - 1) / SHIFT;
    StringBuilder result = new StringBuilder(outputLength);

    int buffer = data[0];
    int next = 1;
    int bitsLeft = 8;
    while (bitsLeft > 0 || next < dataLength) {
      if (bitsLeft < SHIFT) {
        if (next < dataLength) {
          buffer <<= 8;
          buffer |= (data[next++] & 0xff);
          bitsLeft += 8;
        } else {
          int pad = SHIFT - bitsLeft;
          buffer <<= pad;
          bitsLeft += pad;
        }
      }
      int index = MASK & (buffer >> (bitsLeft - SHIFT));
      bitsLeft -= SHIFT;
      result.append(DIGITS[index]);
    }
    return result.toString();
  }
Encodes arbitrary byte arrays as case-insensitive base-32 strings.

<p> The implementation is slightly different than in RFC 4648. During encoding, padding is not
added, and during decoding the last incomplete chunk is not taken into account. The result is
that multiple strings decode to the same byte array, for example, string of sixteen 7s ("7...7")
and seventeen 7s both decode to the same byte array.

<p>TODO: Revisit this encoding and whether this ambiguity needs fixing.
java/com/google/android/apps/authenticator/util/Base32String.java