How to reverse the process of this C# Decode method to create an Encode method?
I would like to know how to reverse the process of the below DecodeBinaryBase64 so that I can have a matching Encode method. In short C# code that if given the output开发者_如何学JAVA of this method it would return the same string that it took as input.
private static string DecodeBinaryBase64(string stringToDecode)
{
StringBuilder builder = new StringBuilder();
foreach (var b in Convert.FromBase64String(stringToDecode))
builder.Append(string.Format("{0:X2}", b));
return builder.ToString();
}
Here is an example of an encoded string and its decoded counterpart. The result is a SHA1 hash for a file. The above method is an example of understanding how the decoding works to get to the right string.
ENCODED
/KUGOuoESMWYuDb+BTMK1LaGe7k=
DECODED
FCA5063AEA0448C598B836FE05330AD4B6867BB9
or
0xFCA5063AEA0448C598B836FE05330AD4B6867BB9
Updated to reflect correct SHA1 value thanks to Porges and a fix for hex bug found by Dean 'codeka' Hardin.
Implemented Solution
Here is the the implementation I have now, it is from Porges post distilled down to two methods.
private static string EncodeFileDigestBase64(string digest)
{
byte[] result = new byte[digest.Length / 2];
for (int i = 0; i < digest.Length; i += 2)
result[i / 2] = byte.Parse(digest.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
if (result.Length != 20)
throw new ArgumentException("Not a valid SHA1 filedigest.");
return Convert.ToBase64String(result);
}
private static string DecodeFileDigestBase64(string encodedDigest)
{
byte[] base64bytes = Convert.FromBase64String(encodedDigest);
return string.Join(string.Empty, base64bytes.Select(x => x.ToString("X2")));
}
I don't believe it's physically possible. The problem is that string.Format("{0:X}", b)
will return either 1 or 2 characters depending on whether the input byte is < 16 or not. And you've got no way to know once the string has been joined together.
If you can modify the DecodeBinaryBase64
method so that it always appends two character for each byte, i.e. by using string.Format("{0:X2}", b)
then it will be possible by just taking the input string two characters at a time.
If you made that change to your DecodeBinaryBase64
, then you can use the following to convert back again:
private static string DecodeBinaryBase64(string stringToDecode)
{
StringBuilder builder = new StringBuilder();
foreach (var b in Convert.FromBase64String(stringToDecode))
builder.Append(string.Format("{0:X2}", b));
return "0x" + builder.ToString();
}
private static string EncodeBinaryBase64(string stringToEncode)
{
var binary = new List<byte>();
for(int i = 2; i < stringToEncode.Length; i += 2)
{
string s = new string(new [] {stringToEncode[i], stringToEncode[i+1]});
binary.Add(byte.Parse(s, NumberStyles.HexNumber));
}
return Convert.ToBase64String(binary.ToArray());
}
(Error checking and so on is missing, though)
Well, you're going from Base-64 to an ASCII/UTF-8 string - and then outputting each character as a 2-digit hex value.
I don't know of any way to automatically get that back. You may have to pull out two characters at a time, cast those as a "char", and use string.format() to turn those back into characters, maybe?
I've never seen the need to take hex output like that, and turn it back into a real string before. Hope that helps.
So I expanded my answer a bit:
/** Here are the methods in question: **/
string Encode(string input)
{
return SHA1ToBase64String(StringToBytes(input));
}
string Decode(string input)
{
return BytesToString(Base64StringToSHA1(input));
}
/****/
string BytesToString(byte[] bytes)
{
return string.Join("",bytes.Select(x => x.ToString("X2")));
}
byte[] StringToBytes(string input)
{
var result = new byte[input.Length/2];
for (var i = 0; i < input.Length; i+=2)
result[i/2] = byte.Parse(input.Substring(i,2), System.Globalization.NumberStyles.HexNumber);
return result;
}
string SHA1ToBase64String(byte[] hash)
{
if (hash.Length != 20)
throw new Exception("Not an SHA-1 hash.");
return Convert.ToBase64String(hash);
}
byte[] Base64StringToSHA1(string input)
{
return Convert.FromBase64String(input);
}
void Main() {
var encoded = "/KUGOuoESMWYuDb+BTMK1LaGe7k=";
var decoded = Decode(encoded);
var reencoded = Encode(decoded);
Console.WriteLine(encoded == reencoded); //True
Console.WriteLine(decoded);
// FCA5063AEA0448C598B836FE05330AD4B6867BB9
}
I guess the confusion in other comments was over whether you want to provide a left-inverse or a right-inverse.
That is do you want a function "f
" that does:
f(Decode(x)) == x // "left inverse"
or:
Decode(f(x)) == x // "right inverse"
I assumed the latter, because you said (1st comment on other answer) that you wanted to be able to replicate Microsoft's encoding. (And what Dean noted - your function wasn't providing reversible output.) :)
Either way the above reimplements your version for correct output, so both functions are inverses of each other.
精彩评论