Invalid length for a Base-64 char array while decryption - c#

I get the following exception in some cases through (decryption) , and i can't recognize exactly the reason :
Invalid length for a Base-64 char array
My Code :
public static string encodeSTROnUrl(string thisEncode)
{
if (null == thisEncode)
return string.Empty;
return HttpUtility.UrlEncode(Encrypt(thisEncode));
}
// string thisDecode = "3Dn%2bsJJPXprU4%3d"; //this is the value which cause the exception.
public static string decodeSTROnUrl(string thisDecode)
{
return Decrypt(HttpUtility.UrlDecode(thisDecode));
}
QueryStringEncryption.Cryptography.decodeSTROnUrl(Request.QueryString["val"].ToString());
The exact line which throw the exception is :
Byte[] byteArray = Convert.FromBase64String(text);
I thought i fix this problem by encoding and decoding before and after the encryption and the decryption operation.but some values still throw this exception .
Note: i note some strange behavior :
the id as a query string sent to my mail is : n%2bsJJPXprU4%3d and it works without exceptions ..
and the user who has the problem the sent url contains 3Dn%2bsJJPXprU4%3d
is this a browser problem ??!!

Decoding the querystring values is done already when it's parsed into the Request. try without
'HttpUtility.UrlDecode'
public static string decodeSTROnUrl(string thisDecode)
{
return Decrypt(thisDecode);
}

The 64-bit encoding has problems with spaces in the string.
Try to add the following after encrypting
sEncryptedString = sEncryptedString.Replace(' ', '+');

Related

Could not decode JWT payload from base64

I'm going to decode a JWT token from request header, it looks like this:
eyJzdWIiOiIxIiwiZXZlbnRfaWQiOiI3ZTA3Y2JmNC0wYjYyLTQ1MzMtYmE5ZC1mZGFjNDkyNTNjZTUiLCJpYXQiOiIxNTkwODk4Mzg1IiwiZXhwIjoiMTU5MDkwMTk4NSIsImlzcyI6ImxvY2FsaG9zdDo0NDM4NyIsInRpbWV6b25lX29mZnNldCI6LTcsInVzciI6Im1pbmcuaGlldS4xMzEyIiwiYWxpYXMiOiJNaW5nIEhpZXUiLCJwaG9uZSI6IjA4NDQ1OTAyNTIiLCJlbWFpbCI6ImhpZXVhbWlAZ21haWwuY29tIn0
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
return Encoding.UTF8.GetString(base64EncodedBytes);
}
When passing the token above to decode method, it throws an exception that tells:
Invalid length for a Base-64 char array or string
dotnetfiddle referrence: https://dotnetfiddle.net/Z2TUz9
But when using it in javascript (using atob function), it works properly.
Could anyone tell me why, then tell me how can I decode it in C#?
Before I get into detail about the question, I would generally suggest using a JWT library that can do all that needs to be done with a few function calls.
As a Base64 string, it is indeed too short. A valid Base64 encoded string should have a length that is dividable by 4 and should be padded with 1 or 2 padding characters = if necessary. But JWT uses the slightly different Base64url encoding and in this encoding padding is optional.
But the C# Base64 decoder is quite strict in this regard.
Therefore you need to convert from Base64Url to Base64 and add the missing padding. Besides that, there are also two Base64Url specific characters that need to be converted back to Base64, as shown in the following code:
using System;
public class Program
{
public static void Main()
{
string token = "eyJzdWIiOiIxIiwiZXZlbnRfaWQiOiI3ZTA3Y2JmNC0wYjYyLTQ1MzMtYmE5ZC1mZGFjNDkyNTNjZTUiLCJpYXQiOiIxNTkwODk4Mzg1IiwiZXhwIjoiMTU5MDkwMTk4NSIsImlzcyI6ImxvY2FsaG9zdDo0NDM4NyIsInRpbWV6b25lX29mZnNldCI6LTcsInVzciI6Im1pbmcuaGlldS4xMzEyIiwiYWxpYXMiOiJNaW5nIEhpZXUiLCJwaG9uZSI6IjA4NDQ1OTAyNTIiLCJlbWFpbCI6ImhpZXVhbWlAZ21haWwuY29tIn0";
token = token.Replace('_', '/').Replace('-', '+');
switch (token.Length % 4)
{
case 2: token += "=="; break;
case 3: token += "="; break;
}
var decoded = Convert.FromBase64String(token);
var decodedToken = System.Text.Encoding.Default.GetString(decoded);
Console.WriteLine(decodedToken);
}
}
Code in dotnetfiddle
The datatype of decoded is byte[] and the output would be just the name of the type. To convert it to string and print the JSON I added another line.
The next step from here would be to convert the JSON to a C# object or to use a library as mentioned in the beginning.
You can do it without DRY , this problem can be resolved by
System.IdentityModel.Tokens.Base64UrlEncoder.DecodeBytes(someBase64Url);
or
WebEncoders.Base64UrlDecode(someBase64Url);

Invalid length for a Base-64 char array while decryption issue

I'm having a very strange issue and have no idea what can be causing it.
A customer this morning emailed me about some customers getting an error when trying to view the his website, he also got the error but then when he tried again it worked.
Looking at the logs, the error is with Chrome 65 and 67, I use 67 and do not get the error.
The querystring which is encrypted is below, this never worked for a customer but worked for me:
AQAAANCMnd8BFdERjHoAwE%2fCl%2bsBAAAA0PyFDdX%2brkGTpXZG7C49nAQAAAACAAAAAAAQZgAAAAEAACAAAACI39m3OhUEFw3GBxXP%2bsVpw6zLJOqRkcJx1%2bFPcozLZgAAAAAOgAAAAAIAACAAAAAJpDYiaxnPjDprOQEA9u02%2bU0%2fDQDCIF7sXsjxaU3onYAAAACWWCv%2bKNSRbQjLTNeJjgE37yHviV1UmfJyoUn%2fcUg%2f0MTr23%2b16qZs9F%2fDNm4wU%2bJITVn3xXuarzcNB6ClJ2ZpwtEsMdUNBRUW0B7XA9%2bQjC69V1O2XqTp%2fgXQazHOITEBpgokD1tSbnv4pRMUfkVlogYoo0H9Lnf24FEDEnSp30AAAACwtnrmVACY71%2bcAAMANRoCuihUumid0i8P75KV0ZlUIRBXyOzASHwq9I7icvXWDbI2nNOa0mQDOgNdvZEti%2bYz
Below is my code, I'm hoping the issue is with this, but as some customers are having the issue and some not, I'm not holding my breath.
var encrtptUserId = EncryptionDecryption.WindowsEncrypted(encryptQueryParameters);
string urlToValidateUser = $"{baseUrl}?id={HttpUtility.UrlEncode(encrtptUserId)}";
public static string WindowsEncrypted(string text)
{
return Convert.ToBase64String(ProtectedData.Protect(Encoding.Unicode.GetBytes(text), null, DataProtectionScope.LocalMachine));
}
public static string WindowsDecrypted(string text)
{
return Encoding.Unicode.GetString(ProtectedData.Unprotect(Convert.FromBase64String(text), null, DataProtectionScope.LocalMachine));
}
Its the decryption that is causing the issue, but not all the time
Any help would be appreciated.
The query string includes encoded values, e.g. "%2b". That's at least inconvenient.
You could decode those values to end up with the original base64 value that you could then convert back to a byte array. but it would be better to use a web-safe base64 encoding to start with.
Convert.ToBase64String doesn't provide a URL-safe approach, but you can easily just use Replace on the result:
public static string WindowsEncrypted(string text)
{
byte[] plainBinary= Encoding.Unicode.GetBytes(text);
byte[] encrypted = ProtectedData.Protect(plainBinary, null, DataProtectionScope.LocalMachine);
string base64 = Convert.ToBase64String(encrypted);
// Return a url-safe string
return base64.Replace("+", "-").Replace("/", "_").Replace("=", ".");
}
public static string WindowsDecrypted(string text)
{
string base64 = text.Replace("-", "+").Replace("_", "/").Replace(".", "=");
byte[] encrypted = Convert.FromBase64String(base64);
byte[] plainBinary = ProtectedData.Unprotect(encrypted, null, DataProtectionScope.LocalMachine);
return Encoding.Unicode.GetString(plainBinary);
}

"Specified value has invalid Control characters" when converting SHA512 output to string

I am attempting to create an Hash for an API.
my input is something like this:
FBN|Web|3QTC0001|RS1|260214133217|000000131127897656
And my expected output is like :
17361DU87HT56F0O9967E34FDFFDFG7UO334665324308667FDGJKD66F9888766DFKKJJR466634HH6566734JHJH34766734NMBBN463499876554234343432456
I tried the bellow but I keep getting
"Specified value has invalid Control characters. Parameter name: value"
I am actually doing this in a REST service.
public static string GetHash(string text)
{
string hash = "";
SHA512 alg = SHA512.Create();
byte[] result = alg.ComputeHash(Encoding.UTF8.GetBytes(text));
hash = Encoding.UTF8.GetString(result);
return hash;
}
What am I missing?
The problem is Encoding.UTF8.GetString(result) as the data in result is invalid UTF-8 (it's just binary goo!) so trying to convert it to text is invalid - in general, and specifically for this input - which results in the Exception being thrown.
Instead, convert the byte[] to the hex representation of said byte sequence; don't treat it as UTF-8 encoded text.
See the questions How do you convert Byte Array to Hexadecimal String, and vice versa? and How can I convert a hex string to a byte array?, which discuss several different methods of achieving this task.
In order to make this work you need to convert the individual byte elements into a hex representation
var builder = new StringBuilder();
foreach(var b in result) {
builder.AppendFormat("{0:X2}", b);
}
return builder.ToString();
You might want to consider using Base64 encoding (AKA UUEncode):
public static string GetHash(string text)
{
SHA512 alg = SHA512.Create();
byte[] result = alg.ComputeHash(Encoding.UTF8.GetBytes(text));
return Convert.ToBase64String(result);
}
For your example string, the result is
OJgzW5JdC1IMdVfC0dH98J8tIIlbUgkNtZLmOZsjg9H0wRmwd02tT0Bh/uTOw/Zs+sgaImQD3hh0MlzVbqWXZg==
It has an advantage of being more compact than encoding each byte into two characters: three bytes takes four characters with Base64 encoding or six characters the other way.

string to byte array (to string to XML) and back again

i know there are 1million questions about "string - byte array" conversion out there but none of them fit my problem.
For the installation of my software i need to save some informations from the user (serveraddress, userID, password and so on). Some of these informations need do be protected (encrypted using DPAPI). For that i have to convert the string (SecureString) to byte[]
public static byte[] StringToByte(string s)
{
return Convert.FromBase64String(s);
}
where i get my first problem. If the strings lenght is a not a multiple of 4 (s.lenght % 4 == 0) i get a "Invalid length for a Base-64 char array" error. I've read that i can (have to) add "=" to the end of the string but some of these strings may be passwords (which may contain "="). I need to store the (encrypted) data in a XML-file why i can't use Unicode encoding (i don't know why but it corrupts the XML file ... because of encoding i would suppose).
As last step i have to go back the way to get the stored data on app startup.
Does someone of you can help me solving this problem ? I don't care the output in the XML as long as it is "readable".
best regards Alex
where i get my first problem. If the strings lenght is a not a multiple of 4 (s.lenght % 4 == 0) i get a "Invalid length for a Base-64 char array" error.
That suggests that it's not base64 to start with. It sounds like you're going in the wrong direction here - base64 is used to convert binary data into text. To convert text into a binary form, you should normally just use Encoding.GetBytes:
return Encoding.UTF8.GetBytes(text);
Now if you needed to encode the result of the encryption (which will be binary data) as text, then you'd use base64. (Because the result of encrypting UTF-8-encoded text is not UTF-8-encoded text.)
So something like:
public static string EncryptText(string input)
{
byte[] unencryptedBytes = Encoding.UTF8.GetBytes(input);
byte[] encryptedBytes = EncryptBytes(unencryptedBytes); // Not shown here
return Convert.ToBase64String(encryptedBytes);
}
public static string DecryptText(string input)
{
byte[] encryptedBytes = Convert.FromBase64String(input);
byte[] unencryptedBytes = DecryptBytes(encryptedBytes); // Not shown here
return Encoding.UTF8.GetString(unencryptedBytes);
}

Invalid length for a Base-64 char array

I'm getting a "Invalid length for a Base-64 char array." inside of the IF(){...} are variations i have tried to get it to work. it fails in the first line without calling decrypt(...) proving it's not that functions problem. i get the same error inside with the first decrypt(...) call. the last one using the encoding.ascii... will get me inside the function, but then it fails inside the function. I'm getting the proper encrypted info from the database to string SSnum. it's value is: 4+mFeTp3tPF
try
{
string SSnum = dr.GetString(dr.GetOrdinal("Social Security"));
if (isEncrypted)
{
byte[] temp = Convert.FromBase64String(SSnum);
//SSnum = decrypt(Convert.FromBase64String(SSnum), Key, IV);
//SSnum = decrypt(Encoding.ASCII.GetBytes(SSnum), Key, IV);
}
txt_Social_Security.Text = SSnum;
}
catch { txt_Social_Security.Text = ""; }
I've been told to use the Convert.FromBase64String() and not the ASCII method...so why is it failing, how can i fix it?
Base64 data length should be multiple of 4 and with padding char '='
You can change your data as valid base64 data.
string dummyData = imgData.Trim().Replace(" ", "+");
if (dummyData.Length % 4 > 0)
dummyData = dummyData.PadRight(dummyData.Length + 4 - dummyData.Length % 4, '=');
byte[] byteArray = Convert.FromBase64String(dummyData);
https://stackoverflow.com/a/9301545/2024022
This will help you , try once.
Thanks
suribabu.
it's value is: 4+mFeTp3tPF
You are receiving this error because that value, 4+mFeTp3tPF, is in fact not valid Base64.
Is it possible you are simply missing the required padding character, as so 4+mFeTp3tPF=?
Are you certain that you have a Base64 string? Base64 is a means of encoding binary data into a string while only using standard 7-bit ASCII characters. It's not a string encoding like ASCII and has some control bytes present. You have a Base64 string if you're using Convert.ToBase64String to obtain the value (which, if you're trying to store binary data as a string, is your best bet)
Judging by your error (and your example data), I'm assuming that you do not have a Base64 string. If you need to store binary data in the database, you can either create a column using a binary type or encode the string into Base64 by using Convert.ToBase64String.
byte[] inputData = ...;
string base64String = Convert.ToBase64String(inputData);
byte[] outputData = Convert.FromBase64String(base64String);
Here, outputData should contain the same data as inputData.
If what you have is just an ASCII-encoded string, then your original practice of using System.Text.Encoding.ASCII.GetBytes() is correct, but you should change this to use a Base64 string if you can.
Are you sure that string 4+mFeTp3tPF is well-formed Base64 string?
I've tried some online services - no one could convert it.
replace
byte[] temp = Convert.FromBase64String(SSnum);
to this
var temp = UTF8Encoding.UTF8.GetBytes(SSnum);

Categories