3

Everytime i encode a string using Base64 and a + is added, the decoding will fail regarding the length of the string is invalid. If the encoding does not have the leading + it'll decode just fine. Can anyone please explain why this happens? What would cause the + sign to be generated on some cases? Example below, this string was encoded but can't be decoded.

+ueJ0q91t5XOnFYP8Xac3A== 

An example of a parameter i am passing would be in the following format prior to encoding, 123_true or 123_false. Would the "_" be causing the random issue with the "+" showing up?

user1732364
  • 925
  • 4
  • 28
  • 58

2 Answers2

4

+ is one of the regular base64 characters, used when the 6 bits being encoded have a value of 62.

My guess is that you're putting this in the query parameter of a URL, where + is the escaped value of space. For that use case, you should use a URL-safe base64 encoding instead:

Using standard Base64 in URL requires encoding of '+', '/' and '=' characters into special percent-encoded hexadecimal sequences ('+' becomes '%2B', '/' becomes '%2F' and '=' becomes '%3D'), which makes the string unnecessarily longer.

For this reason, modified Base64 for URL variants exist, where the '+' and '/' characters of standard Base64 are respectively replaced by '-' and '_', so that using URL encoders/decoders is no longer necessary and have no impact on the length of the encoded value, leaving the same encoded form intact for use in relational databases, web forms, and object identifiers in general. Some variants allow or require omitting the padding '=' signs to avoid them being confused with field separators, or require that any such padding be percent-encoded. Some libraries (like org.bouncycastle.util.encoders.UrlBase64Encoder) will encode '=' to '.'.

Exactly which path you choose here will depend on whether or not you control both sides - if you do, using the modified decodabet is probably the best plan. Otherwise, you need to just escape the query parameter.

Example below, this string was encoded but can't be decoded.

+ueJ0q91t5XOnFYP8Xac3A==

That's not true, in itself:

byte[] bytes = Convert.FromBase64String("+ueJ0q91t5XOnFYP8Xac3A==");

works fine... suggesting that it's the propagation of the string that's broken, which is in line with what I've said above.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Encoding produces a byte[] so your plus sign is combining an array. Base 64 expects the length of the array to be divisible by 8 since Base 64 is rows of 8 bytes. – jdweng Jan 06 '16 at 15:10
  • Can you elaborate a bit more about escaping this character? I am using this in a url parameter. If i don't do this escape method, the other option is to use a 3rd party encoder? – user1732364 Jan 06 '16 at 15:10
  • @jdweng: It's not at all clear whether this was aimed at me or the OP, but I would expect the `+` to be part of a string value... – Jon Skeet Jan 06 '16 at 15:11
  • 2
    @user1732364: Well you can just use `WebUtility.UrlEncode` or something similar. You can use an alternative decodabet by just using `string.Replace` on the results, but only if you control both the encoding and the decoding side. It really doesn't help that your question is missing large amounts of context. – Jon Skeet Jan 06 '16 at 15:12
  • Jon : it is unclear where the plus sign is going. If the plus sign was combining strings then there wouldn't be an error, so I assume the plus sign is going after the encoding is performed. – jdweng Jan 06 '16 at 15:18
  • @jdweng: Well, that seems a heck of an assumption. Given what we know, it seems much more likely to me that the + is used as part of a URL, and is being validly decoded as a space on the receiving end. It would be odd for part of a value to suddenly become part of code, outside SQL Injection attacks. – Jon Skeet Jan 06 '16 at 15:22
  • Trying the webutlity method now..will post back once testing has concluded. – user1732364 Jan 06 '16 at 15:29
  • The urlencoding worked but is not what i am looking for. I just want to encrypt the parameter of the url. I'll try the escaping of the "+" sign – user1732364 Jan 06 '16 at 16:23
  • @user1732364: So just encode the parameter value. Note that base64 encoding is *not* encryption. You shouldn't do the escaping yourself - let WebUtility do it for you. – Jon Skeet Jan 06 '16 at 16:25
  • Can i not just trim the value before encoding? That should remove any possibility of a "+" right? – user1732364 Jan 06 '16 at 17:10
  • @user1732364: No, absolutely not. The point of base64 encoding is to convert arbitrary binary data into text. Do you not want to preserve that arbitrary binary data? I don't know why you're shying away from the simplest approach, which is to URL-encode the query parameter... – Jon Skeet Jan 06 '16 at 17:23
  • Because you can easily tell what the data is using urlencode. For example my query parameter is value=123_true. This would basically encode to value%A123%Btrue. Someone could very easily alter those values in the query string to manipulate the system which is bad. Using base 64 just makes it a bit harder without going with encryption and a key value. Most users i deal with won't know they can alter those values...some will so making it "look" harder to alter should deter them away from trying. – user1732364 Jan 06 '16 at 18:57
  • @user1732364: I was suggesting url-encoding the base64 data. No-one ever suggested URL-encoding the original data. But this is really, *really* poor obfuscation. If the only reason for using base64 is to obfuscate the data, I would strongly suggest doing something else. This might be okay for just a trivial personal project, but if it's in any way professional, you should absolutely use something more appropriate. – Jon Skeet Jan 06 '16 at 19:11
  • Thanks! I was able to get it working i believe. The DLL i was using was performing incorrect encoding. I updated my dll and everything seems to be working now. I did learn a lot from this though so thanks again :) – user1732364 Jan 06 '16 at 19:52
2

Similar to the PHP solution for this problem, you can replace +,/ and = with the safe characters -,_, and ,

string safeBase64= base64.Replace('+', '-').Replace('/', '_').Replace('=', ',')

Just before decoding you can replace back the original characters:

string base64 = safeBase64.Replace('-','+').Replace('_','/').Replace(',','=')
Community
  • 1
  • 1
Alex
  • 21,273
  • 10
  • 61
  • 73