Invalid length for a Base-64 char array exception - c#

i have exception when i run this code ,, what is wrong
var encoder = new System.Text.UTF8Encoding();
System.Text.Decoder utf8Decode = encoder.GetDecoder();
byte[] todecodeByte = Convert.FromBase64String(encodedMsg);
int charCount = utf8Decode.GetCharCount(todecodeByte, 0, todecodeByte.Length);
var decodedChar = new char[charCount];
utf8Decode.GetChars(todecodeByte, 0, todecodeByte.Length, decodedChar, 0);
var message = new String(decodedChar);
exception occurs in this line
byte[] todecodeByte = Convert.FromBase64String(encodedMsg);

Base64 encoding encodes 6 bits per character. So the length of the string, multiplied by 6, must be divisible by 8. If it is not then it doesn't have enough bits to fill every byte and you'll get this exception.
So good odds that encodedMsg just isn't a properly encoded base64 string. You can append some = characters to bypass the exception and see if anything recognizable pops out. The = character is the padding character for base64:
while ((encodedMsg.Length * 6) % 8 != 0) encodedMsg += "=";
// etc...

Related

How do you convert UTF8 number into written text

I am writing a winform to convert written text into Unicode numbers and UTF8 numbers. This bit is working well
//------------------------------------------------------------------------
// Convert to UTF8
// The return will be either 1 byte, 2 bytes or 3 bytes.
//-----------------------------------------------------------------------
UTF8Encoding utf8 = new UTF8Encoding();
StringBuilder builder = new StringBuilder();
string utext = rchtxbx_text.Text;
// do one char at a time
for (int text_index = 0; text_index < utext.Length; text_index++)
{
byte[] encodedBytes = utf8.GetBytes(utext.Substring(text_index, 1));
for (int index = 0; index < encodedBytes.Length; index++)
{
builder.AppendFormat("{0}", Convert.ToString(encodedBytes[index], 16));
}
builder.Append(" ");
}
rchtxtbx_UTF8.SelectionFont = new System.Drawing.Font("San Serif", 20);
rchtxtbx_UTF8.AppendText(builder.ToString() + "\r");
As an example the characters 乘义ש give me e4b998 e4b989 d7a9, note I have a mix LtoR and RtoL text. Now if the user inputs the number e4b998 I want to show them it is 乘, in Unicode 4E58
I have tried a few things and the closest I got, but still far away, is
Encoding utf8 = Encoding.UTF8;
rchtxbx_text.Text = Encoding.ASCII.GetString(utf8.GetBytes(e4b998));
What do I need to do to input e4b998 and write 乘 to a textbox?
Something like this:
Split source into 2-character chunks: "e4b998" -> {"e4", "b9", "98"}
Convert chunks into bytes
Encode bytes into the final string
Implementation:
string source = "e4b998";
string result = Encoding.UTF8.GetString(Enumerable
.Range(0, source.Length / 2)
.Select(i => Convert.ToByte(source.Substring(i * 2, 2), 16))
.ToArray());
If you have an int as source:
string s_unicode2 = System.Text.Encoding.UTF8.GetString(utf8.GetBytes(e4b998));

Byte arrays to base64 string

Say I have two byte arrays.
In the first scenario, I concatenate the two arrays (using Buffer.BlockCopy), then convert the result to base64 string.
In the second scenario, I convert each byte array into base64 string and then concatenate those strings.
Would the two results be the same?
Results would be the same if length of the first array is divisible by 3, in all other cases result of concatenation of two base64 strings would be different (and invalid base64) due to padding bytes at the end of first string. Length of second array does not matter for this operation as padding is always at the end.
Why "divisible by 3" - since base64 encodes every 3 bytes into exactly 4 characters arrays of such length will not need padding at the end. See https://www.rfc-editor.org/rfc/rfc4648#section-4 for formal details and https://en.wikipedia.org/wiki/Base64#Padding for more readable explanation.
I.e. if first array is 4 bytes long you get == at the end of converted string and concatenation with other base64 string will result in invalid base64 text
Convert.ToBase64String(new byte[]{1,2,3,4}) // AQIDBA==
Sample case where concatenation works the same on arrays first or on strings:
Convert.ToBase64String(new byte[]{1,2,3}) + // length divisible by 3
Convert.ToBase64String(new byte[]{4,5})
==
Convert.ToBase64String(new byte[]{1,2,3,4,5}) // AQIDBAU=
void Main()
{
byte[] bytes1 = new byte[]{10, 20, 30, 40, 0, 0, 0, 0};
byte[] bytes2 = new byte[]{50, 60, 70, 80};
Buffer.BlockCopy(bytes2, 0, bytes1, 4, 4);
PrintByteArray(bytes1);
string bytesStr = Convert.ToBase64String(bytes1);
Console.WriteLine(bytesStr);
string bytesStr1 = Convert.ToBase64String(bytes1);
string bytesStr2 = Convert.ToBase64String(bytes2);
string bytesStrMerged = bytesStr1 + bytesStr2;
Console.WriteLine(bytesStrMerged);
}
public void PrintByteArray(byte[] bytes)
{
var sb = new StringBuilder();
foreach (var b in bytes)
{
sb.Append(b + " ");
}
Console.WriteLine(sb.ToString());
}
Outputs:
10 20 30 40 50 60 70 80
ChQeKDI8RlA=
ChQeKDI8RlA=MjxGUA==

BluetoothLEAdvertisementDataSection (ArgumentException)

I'm trying to advertise an Eddystone beacon but my code fails at advertisementData.Data with an ArgumentException:
Value does not fall within the expected range.
Any ideas of what's happening?
// ...
using (var memoryStream = new MemoryStream())
{
byte messageLengthByte = Convert.ToByte(message.Length);
memoryStream.WriteByte(messageLengthByte);
memoryStream.Write(message, 0, message.Length);
fullMessage = memoryStream.ToArray();
}
while (fullMessage.Length < 32)
{
byte[] newArray = new byte[fullMessage.Length + 1];
fullMessage.CopyTo(newArray, 0);
newArray[fullMessage.Length] = 0x00;
fullMessage = newArray;
}
var writer = new DataWriter();
writer.WriteBytes(fullMessage);
var advertisementData = new BluetoothLEAdvertisementDataSection();
advertisementData.Data = writer.DetachBuffer(); // Error!
publisher.Advertisement.DataSections.Add(advertisementData);
publisher.Start();
Most likely you're trying to fit in more bytes than the BLE packet allows. The max size is 32 bytes, but that's including:
3 bytes for the "flags" data section, which I believe is mandatory and might be automatically set by the Windows 10 BLE API
for each additional section, 1 byte for the length of the section, and 1 bytes for the type of the section
If you only broadcast a single section, that leaves you with 27 bytes for that section's actual payload.

how to convert function from VB.net to C#?

I have this function in VB.net and I am trying to convert this code from VB to C#.
Function HashEncode(strSecret)
' Function takes an ASCII string less than 2^61 characters long and
' one way hash encrypts it using 160 bit encryption into a 40 digit hex value.
' The encoded hex value cannot be decoded to the original string value.
'
' This is the only function that you need to call for encryption.
'
' Written By: Mark G. Jager
' Written Date: 8/10/2000
'
' Free to distribute as long as code is not modified, and header is kept intact
'
' The author makes no warranties as to the validity, and/or authenticity of this code.
' You may use any code found herein at your own risk.
' This code was written to follow as closely as possible the standards found in
' Federal Information Processing Standards Publication (FIPS PUB 180-1)
' http://csrc.nist.gov/fips/fip180-1.txt -- Secure Hash Standard SHA-1
'
' This code is for private use only, and the security and/or encryption of the resulting
' hexadecimal value is not warrented or gaurenteed in any way.
'
Dim strEncode, strH(4)
Dim intPos
If len(strSecret) = 0 or len(strSecret) >= 2^61 then
HashEncode = "0000000000000000000000000000000000000000"
exit function
end if
'Initial Hex words are used for encoding Digest.
'These can be any valid 8-digit hex value (0 to F)
strH(0) = "FB0C14C2"
strH(1) = "9F00AB2E"
strH(2) = "991FFA67"
strH(3) = "76FA2C3F"
strH(4) = "ADE426FA"
For intPos = 1 to len(strSecret) step 56
strEncode = Mid(strSecret, intPos, 56) 'get 56 character chunks
strEncode = WordToBinary(strEncode) 'convert to binary
strEncode = PadBinary(strEncode) 'make it 512 bites
strEncode = BlockToHex(strEncode) 'convert to hex value
'Encode the hex value using the previous runs digest
'If it is the first run then use the initial values above
strEncode = DigestHex(strEncode, strH(0), strH(1), strH(2), strH(3), strH(4))
'Combine the old digest with the new digest
strH(0) = HexAdd(left(strEncode, 8), strH(0))
strH(1) = HexAdd(mid(strEncode, 9, 8), strH(1))
strH(2) = HexAdd(mid(strEncode, 17, 8), strH(2))
strH(3) = HexAdd(mid(strEncode, 25, 8), strH(3))
strH(4) = HexAdd(right(strEncode, 8), strH(4))
Next
'This is the final Hex Digest
HashEncode = strH(0) & strH(1) & strH(2) & strH(3) & strH(4)
End Function
I have converted it in C# as
public string HashEncode(string strSecret)
{
string strEncode;
string[] strH = new string [4];
int intPos;
if (strSecret.Length == 0 || strSecret.Length >= Int64.MaxValue)
{
return "0000000000000000000000000000000000000000";
//break;
}
//Initial Hex words are used for encoding Digest.
//These can be any valid 8-digit hex value (0 to F)
strH[0] = "FB0C14C2";
strH[1] = "9F00AB2E";
strH[2] = "991FFA67";
strH[3] = "76FA2C3F";
strH[4] = "ADE426FA";
for(intPos = 1; intPos < strSecret.Length; intPos += 56)
{
strEncode = strSecret.Substring(intPos, strSecret.IndexOf(" ", 56));
//strEncode = Mid(strSecret, intPos, 56); //get 56 character chunks
strEncode = WordToBinary(strEncode); //convert to binary
strEncode = PadBinary(strEncode); //make it 512 bites
strEncode = BlockToHex(strEncode); //convert to hex value
//Encode the hex value using the previous runs digest
//If it is the first run then use the initial values above
strEncode = DigestHex(strEncode, strH[0], strH[1], strH[2], strH[3], strH[4]);
//Combine the old digest with the new digest
//strH[0] = HexAdd(left(strEncode, 8), strH[0]);
//strH[1] = HexAdd(mid(strEncode, 9, 8), strH[1]);
//strH[2] = HexAdd(mid(strEncode, 17, 8), strH[2]);
//strH[3] = HexAdd(mid(strEncode, 25, 8), strH[3]);
//strH[4] = HexAdd(right(strEncode, 8), strH[4]);
strH[0] = HexAdd(strEncode.Substring(0, 8), strH[0]);
strH[1] = HexAdd(strEncode.Substring(9, 8), strH[1]);
strH[2] = HexAdd(strEncode.Substring(17, 8), strH[2]);
strH[3] = HexAdd(strEncode.Substring(25, 8), strH[3]);
strH[4] = HexAdd(strEncode.Substring(strEncode.Length - 8,8),strH[4]);
}
//This is the final Hex Digest
return strH[0] + strH[1] + strH[2] + strH[3] + strH[4];
}
It successfully compiled but not working.
It gives exception at for loop as 'System.IndexOutOfRangeException was unhandled by user'
Is anyone help me to solve this problem
The code is an implementation of the SHA-1 algorithm, correct? In that case:
using System.Security.Cryptography;
using System.Text;
string str = "foobar";
byte[] data = Encoding.ASCII.GetBytes(str);
SHA1 sha = new SHA1Managed();
byte[] hash = sha.ComputeHash(data);
Console.WriteLine(String.Concat(Array.ConvertAll(hash, x => x.ToString("X2"))));
Translation complete.
Your 'for' loop is wrong for a couple of reasons:
1. the ending condition is incorrect - strSecret.Length has to be included if you start your indexing at 1.
2. when converting the legacy VB string functions, you have to be aware that they use 1-based indexing, while the .NET methods use 0-based indexing.
for (int intPos = 1; intPos <= strSecret.Length; intPos += 56)
{
strEncode = strSecret.ToString().Substring(intPos - 1, 56); //get 56 character chunks
strEncode = WordToBinary(strEncode); //convert to binary
strEncode = PadBinary(strEncode); //make it 512 bites
strEncode = BlockToHex(strEncode); //convert to hex value
//Encode the hex value using the previous runs digest
//If it is the first run then use the initial values above
strEncode = DigestHex(strEncode, strH[0], strH[1], strH[2], strH[3], strH[4]);
//Combine the old digest with the new digest
strH[0] = HexAdd(strEncode.Substring(0, 8), strH[0]);
strH[1] = HexAdd(strEncode.Substring(8, 8), strH[1]);
strH[2] = HexAdd(strEncode.Substring(16, 8), strH[2]);
strH[3] = HexAdd(strEncode.Substring(24, 8), strH[3]);
strH[4] = HexAdd(strEncode.Substring(strEncode.Length - 8), strH[4]);
}
You also could use:
for (int intPos = 0; intPos < strSecret.Length; intPos += 56)
{
strEncode = strSecret.ToString().Substring(intPos, 56); //get 56 character chunks
... (rest is identical)
}

trim hex from end of string

I have a byte array that's been initialized with 0xFF in each byte:
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = 0xFF;
}
Once this byte array has been filled with valid data, I need to extract an ASCII string that's stored at offset 192 and may be up to 32 characters in length. I'm doing this like so:
ASCIIEncoding enc = new ASCIIEncoding();
stringToRead = enc.GetString(buffer, 192, 32);
This works but I need to strip off the trailing bytes that contain 0xFF to avoid the string looking something like "John Smith??????????????????????". Is there a function in .NET that provides this ability? Something like the String.TrimEnd() function perhaps or am I looking at a regex to do this?
I would suggest just finding out how long the string will really be:
int firstFF = Array.IndexOf(buffer, (byte) 0xff, 192);
if (firstFF == -1)
{
firstFF = buffer.Length;
}
stringToRead = Encoding.ASCII(buffer, 192, firstFF - 192);
I would not try to give Encoding.ASCII bytes which aren't valid ASCII-encoded text. I don't know offhand what it would do with them - I suspect it would convert them to ? to show the error (as suggested by your existing output), but then you wouldn't be able to tell the difference between that and real question marks. For example:
byte[] data = { 0x41, 0x42, 0x43, 0xff, 0xff };
string text = Encoding.ASCII.GetString(data);
Console.WriteLine(text.Contains((char) 0xff)); // False
Console.WriteLine(text.TrimEnd((char) 0xff).Length); // Still 5...
Now you could create an encoding which used some non-ASCII replacement character... but that's a lot of hassle when you can just find where the binary data stops being valid.
var s = "Whatever" + new String((Char)0xFF, 32);
var trimmed = s.TrimEnd((Char)0xFF);
Alternatively, you can scan the string for the first index of the character, then take the substring:
var index = s.IndexOf((Char)0xFF);
var trimmed = s.Substring(0, index);

Categories