public static byte[] decode(String encoded) throws DecodingException {
    // Remove whitespace and separators
    encoded = encoded.trim().replaceAll(SEPARATOR, "").replaceAll(" ", "");

    // Remove padding. Note: the padding is used as hint to determine how many
    // bits to decode from the last incomplete chunk (which is commented out
    // below, so this may have been wrong to start with).
    encoded = encoded.replaceFirst("[=]*$", "");

    // Canonicalize to all upper case
    encoded = encoded.toUpperCase(Locale.US);
    if (encoded.length() == 0) {
      return new byte[0];
    }
    int encodedLength = encoded.length();
    int outLength = encodedLength * SHIFT / 8;
    byte[] result = new byte[outLength];
    int buffer = 0;
    int next = 0;
    int bitsLeft = 0;
    for (char c : encoded.toCharArray()) {
      if (!CHAR_MAP.containsKey(c)) {
        throw new DecodingException("Illegal character: " + c);
      }
      buffer <<= SHIFT;
      buffer |= CHAR_MAP.get(c) & MASK;
      bitsLeft += SHIFT;
      if (bitsLeft >= 8) {
        result[next++] = (byte) (buffer >> (bitsLeft - 8));
        bitsLeft -= 8;
      }
    }
    // We'll ignore leftover bits for now.
    //
    // if (next != outLength || bitsLeft >= SHIFT) {
    //  throw new DecodingException("Bits left: " + bitsLeft);
    // }
    return result;
  }
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