6

I have a base64 encoded string that was encoded in Java:

string s = "x8QeoAdVOAwpKHAeXIxEticayZLMx7RP_baVdSpDSLLea5TZMxRT-IX93lA05MEUzmwtOvd6WLRBluLchZz2EJSHsFfxxtPQF1VEFv4rA5w="

I'm trying to decode it in C# using the following statement.

string s = "x8QeoAdVOAwpKHAeXIxEticayZLMx7RP_baVdSpDSLLea5TZMxRT-IX93lA05MEUzmwtOvd6WLRBluLchZz2EJSHsFfxxtPQF1VEFv4rA5w="

var decodedBytes = System.Convert.FromBase64String(s);

But I get the error:

The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

What am I doing wrong? I can clearly see there are no illegal characters. Can anyone point me in the right direction?

Update : Here is the java code that generated that string.

 private static String encrypt(byte[] iv, String salt, String password, String clearText) throws Exception {
byte[] encryptedBytes = encryptDecrypt(true, iv, salt, password, clearText.getBytes("UTF-8"));
return Base64.encodeBytes(encryptedBytes, 16);

}

  private static byte[] encryptDecrypt(boolean encrypt, byte[] iv, String salt, String password, byte[] bytesToEncryptDecrypt) throws Exception {
SecretKeySpec secretKeySpec = null;
MessageDigest digester = MessageDigest.getInstance("SHA-1");
digester.update((salt + password).getBytes("UTF-8"));
byte[] key = digester.digest();
secretKeySpec = new SecretKeySpec(key, 2, 16, "AES");
IvParameterSpec ivps = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(encrypt ? 1 : 2, secretKeySpec, ivps);
return cipher.doFinal(bytesToEncryptDecrypt, 0, bytesToEncryptDecrypt.length);

}

Here is the Base64.class file (decompiled). It has both encode and decode methods from Java.

public class Base64
{
  public static final int NO_OPTIONS = 0;
  public static final int ENCODE = 1;
  public static final int DECODE = 0;
  public static final int GZIP = 2;
  public static final int DONT_GUNZIP = 4;
  public static final int DO_BREAK_LINES = 8;
  public static final int URL_SAFE = 16;
  public static final int ORDERED = 32;
  private static final int MAX_LINE_LENGTH = 76;
  private static final byte EQUALS_SIGN = 61;
  private static final byte NEW_LINE = 10;
  private static final String PREFERRED_ENCODING = "US-ASCII";
  private static final byte WHITE_SPACE_ENC = -5;
  private static final byte EQUALS_SIGN_ENC = -1;
  private static final byte[] _STANDARD_ALPHABET = { 
    65, 66, 67, 68, 69, 70, 71, 
    72, 73, 74, 75, 76, 77, 78, 
    79, 80, 81, 82, 83, 84, 85, 
    86, 87, 88, 89, 90, 
    97, 98, 99, 100, 101, 102, 103, 
    104, 105, 106, 107, 108, 109, 110, 
    111, 112, 113, 114, 115, 116, 117, 
    118, 119, 120, 121, 122, 
    48, 49, 50, 51, 52, 53, 
    54, 55, 56, 57, 43, 47 };

  private static final byte[] _STANDARD_DECODABET = { 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -5, -5, 
    -9, -9, 
    -5, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, 
    -5, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    62, 
    -9, -9, -9, 
    63, 
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 
    -9, -9, -9, 
    -1, 
    -9, -9, -9, 
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 
    14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 
    -9, -9, -9, -9, -9, -9, 
    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 
    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
    -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 };

  private static final byte[] _URL_SAFE_ALPHABET = { 
    65, 66, 67, 68, 69, 70, 71, 
    72, 73, 74, 75, 76, 77, 78, 
    79, 80, 81, 82, 83, 84, 85, 
    86, 87, 88, 89, 90, 
    97, 98, 99, 100, 101, 102, 103, 
    104, 105, 106, 107, 108, 109, 110, 
    111, 112, 113, 114, 115, 116, 117, 
    118, 119, 120, 121, 122, 
    48, 49, 50, 51, 52, 53, 
    54, 55, 56, 57, 45, 95 };

  private static final byte[] _URL_SAFE_DECODABET = { 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -5, -5, 
    -9, -9, 
    -5, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, 
    -5, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, 
    -9, 
    62, 
    -9, 
    -9, 
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 
    -9, -9, -9, 
    -1, 
    -9, -9, -9, 
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 
    14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 
    -9, -9, -9, -9, 
    63, 
    -9, 
    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 
    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
    -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 };

  private static final byte[] _ORDERED_ALPHABET = { 
    45, 
    48, 49, 50, 51, 52, 
    53, 54, 55, 56, 57, 
    65, 66, 67, 68, 69, 70, 71, 
    72, 73, 74, 75, 76, 77, 78, 
    79, 80, 81, 82, 83, 84, 85, 
    86, 87, 88, 89, 90, 
    95, 
    97, 98, 99, 100, 101, 102, 103, 
    104, 105, 106, 107, 108, 109, 110, 
    111, 112, 113, 114, 115, 116, 117, 
    118, 119, 120, 121, 122 };

  private static final byte[] _ORDERED_DECODABET = { 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -5, -5, 
    -9, -9, 
    -5, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, 
    -5, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, 
    -9, 
    0, -9, 
    -9, 
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
    -9, -9, -9, 
    -1, 
    -9, -9, -9, 
    11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 
    24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 
    -9, -9, -9, -9, 
    37, 
    -9, 
    38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 
    51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 
    -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
    -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 };

  private static final byte[] getAlphabet(int options)
  {
    if ((options & 0x10) == 16)
      return _URL_SAFE_ALPHABET;
    if ((options & 0x20) == 32) {
      return _ORDERED_ALPHABET;
    }
    return _STANDARD_ALPHABET;
  }

  private static final byte[] getDecodabet(int options)
  {
    if ((options & 0x10) == 16)
      return _URL_SAFE_DECODABET;
    if ((options & 0x20) == 32) {
      return _ORDERED_DECODABET;
    }
    return _STANDARD_DECODABET;
  }

  private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes, int options)
  {
    encode3to4(threeBytes, 0, numSigBytes, b4, 0, options);
    return b4;
  }

  private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset, int options)
  {
    byte[] ALPHABET = getAlphabet(options);

    int inBuff = (numSigBytes > 0 ? source[srcOffset] << 24 >>> 8 : 0) | (
      numSigBytes > 1 ? source[(srcOffset + 1)] << 24 >>> 16 : 0) | (
      numSigBytes > 2 ? source[(srcOffset + 2)] << 24 >>> 24 : 0);

    switch (numSigBytes)
    {
    case 3:
      destination[destOffset] = ALPHABET[(inBuff >>> 18)];
      destination[(destOffset + 1)] = ALPHABET[(inBuff >>> 12 & 0x3F)];
      destination[(destOffset + 2)] = ALPHABET[(inBuff >>> 6 & 0x3F)];
      destination[(destOffset + 3)] = ALPHABET[(inBuff & 0x3F)];
      return destination;
    case 2:
      destination[destOffset] = ALPHABET[(inBuff >>> 18)];
      destination[(destOffset + 1)] = ALPHABET[(inBuff >>> 12 & 0x3F)];
      destination[(destOffset + 2)] = ALPHABET[(inBuff >>> 6 & 0x3F)];
      destination[(destOffset + 3)] = 61;
      return destination;
    case 1:
      destination[destOffset] = ALPHABET[(inBuff >>> 18)];
      destination[(destOffset + 1)] = ALPHABET[(inBuff >>> 12 & 0x3F)];
      destination[(destOffset + 2)] = 61;
      destination[(destOffset + 3)] = 61;
      return destination;
    }

    return destination;
  }

  public static void encode(ByteBuffer raw, ByteBuffer encoded)
  {
    byte[] raw3 = new byte[3];
    byte[] enc4 = new byte[4];

    while (raw.hasRemaining()) {
      int rem = Math.min(3, raw.remaining());
      raw.get(raw3, 0, rem);
      encode3to4(enc4, raw3, rem, 0);
      encoded.put(enc4);
    }
  }

  public static void encode(ByteBuffer raw, CharBuffer encoded)
  {
    byte[] raw3 = new byte[3];
    byte[] enc4 = new byte[4];
    int i;
    for (; raw.hasRemaining(); 
      i < 4)
    {
      int rem = Math.min(3, raw.remaining());
      raw.get(raw3, 0, rem);
      encode3to4(enc4, raw3, rem, 0);
      i = 0; continue;
      encoded.put((char)(enc4[i] & 0xFF));

      i++;
    }
  }

  public static String encodeObject(Serializable serializableObject)
    throws IOException
  {
    return encodeObject(serializableObject, 0);
  }

  public static String encodeObject(Serializable serializableObject, int options)
    throws IOException
  {
    if (serializableObject == null) {
      throw new NullPointerException("Cannot serialize a null object.");
    }

    ByteArrayOutputStream baos = null;
    OutputStream b64os = null;
    GZIPOutputStream gzos = null;
    ObjectOutputStream oos = null;
    try
    {
      baos = new ByteArrayOutputStream();
      b64os = new OutputStream(baos, 0x1 | options);
      if ((options & 0x2) != 0)
      {
        gzos = new GZIPOutputStream(b64os);
        oos = new ObjectOutputStream(gzos);
      }
      else {
        oos = new ObjectOutputStream(b64os);
      }
      oos.writeObject(serializableObject);
    }
    catch (IOException e)
    {
      throw e;
    } finally {
      try {
        oos.close(); } catch (Exception localException) {
      }try { gzos.close(); } catch (Exception localException1) {
      }try { b64os.close(); } catch (Exception localException2) {
      }try { baos.close();
      } catch (Exception localException3) {
      }
    }
    try {
      return new String(baos.toByteArray(), "US-ASCII");
    }
    catch (UnsupportedEncodingException uue) {
    }
    return new String(baos.toByteArray());
  }

  public static String encodeBytes(byte[] source)
  {
    String encoded = null;
    try {
      encoded = encodeBytes(source, 0, source.length, 0);
    } catch (IOException ex) {
      if (!$assertionsDisabled) throw new AssertionError(ex.getMessage());
    }
    assert (encoded != null);
    return encoded;
  }

  public static String encodeBytes(byte[] source, int options)
    throws IOException
  {
    return encodeBytes(source, 0, source.length, options);
  }

  public static String encodeBytes(byte[] source, int off, int len)
  {
    String encoded = null;
    try {
      encoded = encodeBytes(source, off, len, 0);
    } catch (IOException ex) {
      if (!$assertionsDisabled) throw new AssertionError(ex.getMessage());
    }
    assert (encoded != null);
    return encoded;
  }

  public static String encodeBytes(byte[] source, int off, int len, int options)
    throws IOException
  {
    byte[] encoded = encodeBytesToBytes(source, off, len, options);
    try
    {
      return new String(encoded, "US-ASCII");
    } catch (UnsupportedEncodingException uue) {
    }
    return new String(encoded);
  }

  public static byte[] encodeBytesToBytes(byte[] source)
  {
    byte[] encoded = (byte[])null;
    try {
      encoded = encodeBytesToBytes(source, 0, source.length, 0);
    } catch (IOException ex) {
      if (!$assertionsDisabled) throw new AssertionError("IOExceptions only come from GZipping, which is turned off: " + ex.getMessage());
    }
    return encoded;
  }

  public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options)
    throws IOException
  {
    if (source == null) {
      throw new NullPointerException("Cannot serialize a null array.");
    }

    if (off < 0) {
      throw new IllegalArgumentException("Cannot have negative offset: " + off);
    }

    if (len < 0) {
      throw new IllegalArgumentException("Cannot have length offset: " + len);
    }

    if (off + len > source.length) {
      throw new IllegalArgumentException(
        String.format("Cannot have offset of %d and length of %d with array of length %d", new Object[] { Integer.valueOf(off), Integer.valueOf(len), Integer.valueOf(source.length) }));
    }

    if ((options & 0x2) != 0) {
      ByteArrayOutputStream baos = null;
      GZIPOutputStream gzos = null;
      OutputStream b64os = null;
      try
      {
        baos = new ByteArrayOutputStream();
        b64os = new OutputStream(baos, 0x1 | options);
        gzos = new GZIPOutputStream(b64os);

        gzos.write(source, off, len);
        gzos.close();
      }
      catch (IOException e)
      {
        throw e;
      } finally {
        try {
          gzos.close(); } catch (Exception localException) {
        }try { b64os.close(); } catch (Exception localException1) {
        }try { baos.close(); } catch (Exception localException2) {
        }
      }
      return baos.toByteArray();
    }

    boolean breakLines = (options & 0x8) != 0;

    int encLen = len / 3 * 4 + (len % 3 > 0 ? 4 : 0);
    if (breakLines) {
      encLen += encLen / 76;
    }
    byte[] outBuff = new byte[encLen];

    int d = 0;
    int e = 0;
    int len2 = len - 2;
    int lineLength = 0;
    for (; d < len2; e += 4) {
      encode3to4(source, d + off, 3, outBuff, e, options);

      lineLength += 4;
      if ((breakLines) && (lineLength >= 76))
      {
        outBuff[(e + 4)] = 10;
        e++;
        lineLength = 0;
      }
      d += 3;
    }

    if (d < len) {
      encode3to4(source, d + off, len - d, outBuff, e, options);
      e += 4;
    }

    if (e <= outBuff.length - 1)
    {
      byte[] finalOut = new byte[e];
      System.arraycopy(outBuff, 0, finalOut, 0, e);

      return finalOut;
    }

    return outBuff;
  }

  private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset, int options)
  {
    if (source == null) {
      throw new NullPointerException("Source array was null.");
    }
    if (destination == null) {
      throw new NullPointerException("Destination array was null.");
    }
    if ((srcOffset < 0) || (srcOffset + 3 >= source.length)) {
      throw new IllegalArgumentException(String.format(
        "Source array with length %d cannot have offset of %d and still process four bytes.", new Object[] { Integer.valueOf(source.length), Integer.valueOf(srcOffset) }));
    }
    if ((destOffset < 0) || (destOffset + 2 >= destination.length)) {
      throw new IllegalArgumentException(String.format(
        "Destination array with length %d cannot have offset of %d and still store three bytes.", new Object[] { Integer.valueOf(destination.length), Integer.valueOf(destOffset) }));
    }

    byte[] DECODABET = getDecodabet(options);

    if (source[(srcOffset + 2)] == 61)
    {
      int outBuff = (DECODABET[source[srcOffset]] & 0xFF) << 18 | 
        (DECODABET[source[(srcOffset + 1)]] & 0xFF) << 12;

      destination[destOffset] = ((byte)(outBuff >>> 16));
      return 1;
    }

    if (source[(srcOffset + 3)] == 61)
    {
      int outBuff = (DECODABET[source[srcOffset]] & 0xFF) << 18 | 
        (DECODABET[source[(srcOffset + 1)]] & 0xFF) << 12 | 
        (DECODABET[source[(srcOffset + 2)]] & 0xFF) << 6;

      destination[destOffset] = ((byte)(outBuff >>> 16));
      destination[(destOffset + 1)] = ((byte)(outBuff >>> 8));
      return 2;
    }

    int outBuff = (DECODABET[source[srcOffset]] & 0xFF) << 18 | 
      (DECODABET[source[(srcOffset + 1)]] & 0xFF) << 12 | 
      (DECODABET[source[(srcOffset + 2)]] & 0xFF) << 6 | 
      DECODABET[source[(srcOffset + 3)]] & 0xFF;

    destination[destOffset] = ((byte)(outBuff >> 16));
    destination[(destOffset + 1)] = ((byte)(outBuff >> 8));
    destination[(destOffset + 2)] = ((byte)outBuff);

    return 3;
  }

  public static byte[] decode(byte[] source)
    throws IOException
  {
    byte[] decoded = (byte[])null;

    decoded = decode(source, 0, source.length, 0);

    return decoded;
  }

  public static byte[] decode(byte[] source, int off, int len, int options)
    throws IOException
  {
    if (source == null) {
      throw new NullPointerException("Cannot decode null source array.");
    }
    if ((off < 0) || (off + len > source.length)) {
      throw new IllegalArgumentException(String.format(
        "Source array with length %d cannot have offset of %d and process %d bytes.", new Object[] { Integer.valueOf(source.length), Integer.valueOf(off), Integer.valueOf(len) }));
    }

    if (len == 0)
      return new byte[0];
    if (len < 4) {
      throw new IllegalArgumentException(
        "Base64-encoded string must have at least four characters, but length specified was " + len);
    }

    byte[] DECODABET = getDecodabet(options);

    int len34 = len * 3 / 4;
    byte[] outBuff = new byte[len34];
    int outBuffPosn = 0;

    byte[] b4 = new byte[4];
    int b4Posn = 0;
    int i = 0;
    byte sbiDecode = 0;

    for (i = off; i < off + len; i++)
    {
      sbiDecode = DECODABET[(source[i] & 0xFF)];

      if (sbiDecode >= -5)
      {
        byte[] out;
        if (sbiDecode >= -1) {
          b4[(b4Posn++)] = source[i];
          if (b4Posn > 3) {
            outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options);
            b4Posn = 0;

            if (source[i] == 61) {
              break;
            }
          }
        }
      }
      else
      {
        throw new IOException(String.format(
          "Bad Base64 input character decimal %d in array position %d", new Object[] { Integer.valueOf(source[i] & 0xFF), Integer.valueOf(i) }));
      }
    }

    out = new byte[outBuffPosn];
    System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
    return out;
  }

  public static byte[] decode(String s)
    throws IOException
  {
    return decode(s, 0);
  }

  public static byte[] decode(String s, int options)
    throws IOException
  {
    if (s == null) {
      throw new NullPointerException("Input string was null.");
    }

    try
    {
      bytes = s.getBytes("US-ASCII");
    }
    catch (UnsupportedEncodingException uee)
    {
      byte[] bytes;
      bytes = s.getBytes();
    }

    byte[] bytes = decode(bytes, 0, bytes.length, options);

    boolean dontGunzip = (options & 0x4) != 0;
    if ((bytes != null) && (bytes.length >= 4) && (!dontGunzip))
    {
      int head = bytes[0] & 0xFF | bytes[1] << 8 & 0xFF00;
      if (35615 == head) {
        ByteArrayInputStream bais = null;
        GZIPInputStream gzis = null;
        ByteArrayOutputStream baos = null;
        byte[] buffer = new byte[2048];
        int length = 0;
        try
        {
          baos = new ByteArrayOutputStream();
          bais = new ByteArrayInputStream(bytes);
          gzis = new GZIPInputStream(bais);

          while ((length = gzis.read(buffer)) >= 0) {
            baos.write(buffer, 0, length);
          }

          bytes = baos.toByteArray();
        }
        catch (IOException e)
        {
          e.printStackTrace();
          try
          {
            baos.close(); } catch (Exception localException) {
          }try { gzis.close(); } catch (Exception localException1) {
          }try { bais.close(); }
          catch (Exception localException2)
          {
          }
        }
        finally
        {
          try
          {
            baos.close(); } catch (Exception localException3) {
          }try { gzis.close(); } catch (Exception localException4) {
          }try { bais.close();
          } catch (Exception localException5) {
          }
        }
      }
    }
    return bytes;
  }

  public static Object decodeToObject(String encodedObject)
    throws IOException, ClassNotFoundException
  {
    return decodeToObject(encodedObject, 0, null);
  }

}
8
  • I'm not sure the decoding is the issue here as non of the online decoders seem to be fairing any better with your encoded content ( google.com.au/search?q=base64+decode ) Commented Dec 18, 2012 at 4:57
  • 1
    Your input is not valid Base64. It uses - and _ instead of + and /. Commented Dec 18, 2012 at 5:03
  • 3
    It looks like your string was encoded with RFC 4648 'base64url' encoding, which does use - and _. Commented Dec 18, 2012 at 5:14
  • Try this thread. They are getting the same error stackoverflow.com/questions/710853/… Commented Dec 18, 2012 at 5:39
  • Can you show us the Java code that produced this output? Are you at liberty to alter the Java code? Commented Dec 18, 2012 at 8:00

2 Answers 2

7

It should be as simple as replacing the - and _ that Java uses with the + and / that C# uses:

string s = "Vv7JKbNHOvHxC4L89be4vNw-J0KKPkMlq4iZb_T-35u-kjYhilF_ECJAPVufv2-2_ynUORVkIPPqd1H7MC-mrWW7Fu4ZcmsHG2Q1gJOU=";
string corrected = s.Replace('-', '+').Replace('_', '/');
var decodedBytes = System.Convert.FromBase64String(corrected);

However, your example string also seems to be incorrect; it's 105 characters long but (as it's padded) the length should be a multiple of 4. If you remove the trailing = from your input then this code works, but I'd be worried about how it got there. If it's meant to be there, you'll need to programatically trim/pad your input and then double-check that the results you get are what you're expecting.

Sign up to request clarification or add additional context in comments.

3 Comments

Sorry the actual string is this.. "x8QeoAdVOAwpKHAeXIxEticayZLMx7RP_baVdSpDSLLea5TZMxRT-IX93lA05MEUzmwtOvd6WLRBluLchZz2EJSHsFfxxtPQF1VEFv4rA5w=". I've updated the code above to reflect that. It's converting to Base64 string fine. Thank you. But I have another problem. When I use this string to decrypt in AES decryption algorithm using "SHA-1" encryption, I get the error - "Padding is invalid and cannot be removed." I'm using PKCS5 padding.
@InvisibleDev (Edit: Looks like something is weird here, the string in your question works fine but the one in the comment doesn't even though they looks the same... anyway:) If you have a followup question about encryption, please ask it as a separate question.
Replacing _ and - with / and + did the trick. Thank you for your help on this. It works great..
0

Try this code: (Note: this code is not optimized yet for performance, as it uses string concatenation)

using System;
namespace Crypto
{
    public class Base64
    {
        private const String STANDARD_FIRST_62_CHARS=
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
                "abcdefghijklmnopqrstuvwxyz"+
                "0123456789";

        public const String STANDARD_RADIX_STRING=
                STANDARD_FIRST_62_CHARS + "+/";

        public const String RFC4648_RADIX_STRING=
                STANDARD_FIRST_62_CHARS + "-_";

        private const char padding='=';
        private char[]radix_chars;

        public Base64(String radix_string)
        {
            radix_chars=radix_string.ToCharArray();
        }

        public Base64():this(STANDARD_RADIX_STRING)
        {
        }

        public String decode(String str)
        {
            String binary_str = "";
            char[]chars = str.ToCharArray();
            int i=0;
            for(;i<chars.Length && chars[i]!=padding;++i)
            {
                int index = indexOf(chars[i]);
                String bin_of_index = DecimalToBinary(index,6);
                binary_str = binary_str + bin_of_index;
            }
            binary_str = binary_str.Substring(0,binary_str.Length - (2*(chars.Length-i)));
            str = "";
            for(i = 0 ; i < binary_str.Length ; i = i+8)
            {
                String bin_str = binary_str.Substring(i,8);
                int char_point = Convert.ToInt16(bin_str,2);
                str = str + ((char)char_point);
            }
            return str;
        }

        public String encode(String str)
        {
            // TODO
            return null;
        }

        private String DecimalToBinary(int value,int length)
        {
            String bin_string = Convert.ToString(value, 2);
            length = length - bin_string.Length;
            while(length > 0 )
            {
                bin_string = "0"+bin_string;
                --length;
            }
            return bin_string;
        }

        private int indexOf(char c)
        {
            for(int index=0; index < radix_chars.Length ; ++ index)
                if(c == radix_chars[index])
                    return index;
            return -1;
        }
    }
}
public class Program
{
    public static void Main()
    {
        Crypto.Base64 b = new Crypto.Base64(Crypto.Base64.RFC4648_RADIX_STRING);
        Console.WriteLine(b.decode("x8QeoAdVOAwpKHAeXIxEticayZLMx7RP_baVdSpDSLLea5TZMxRT-IX93lA05MEUzmwtOvd6WLRBluLchZz2EJSHsFfxxtPQF1VEFv4rA5w="));
    }
}

In case you want the decode method to return a byte[] instead of String then change the decode method to this:

        public byte[] decode(String str)
        {
            String binary_str = "";
            char[]chars = str.ToCharArray();
            int i=0;
            for(;i<chars.Length && chars[i]!=padding;++i)
            {
                int index = indexOf(chars[i]);
                String bin_of_index = DecimalToBinary(index,6);
                binary_str = binary_str + bin_of_index;
            }
            binary_str = binary_str.Substring(0,binary_str.Length - (2*(chars.Length-i)));
            byte[]bytes=new byte[binary_str.Length/8];
            for(i = 0 ; i < binary_str.Length ; i = i+8)
            {
                String bin_str = binary_str.Substring(i,8);
                int char_point = Convert.ToInt16(bin_str,2);
                bytes[i/8] = (byte) char_point;
            }
            return bytes;
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.