How do I return a base64 encoded string given a string?
How do I decode a base64 encoded string into a string?
Encode
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
Decode
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
One liner code:
Note: Use System and System.Text directives.
Encode:
string encodedStr = Convert.ToBase64String(Encoding.UTF8.GetBytes("inputStr"));
Decode:
string inputStr = Encoding.UTF8.GetString(Convert.FromBase64String(encodedStr));
I'm sharing my implementation with some neat features:
uses Extension Methods for Encoding class. Rationale is that someone may need to support different types of encodings (not only UTF8).
Another improvement is failing gracefully with null result for null entry - it's very useful in real life scenarios and supports equivalence for X=decode(encode(X)).
Remark: Remember that to use Extension Method you have to (!) import the namespace with using keyword (in this case using MyApplication.Helpers.Encoding).
Code:
namespace MyApplication.Helpers.Encoding
{
public static class EncodingForBase64
{
public static string EncodeBase64(this System.Text.Encoding encoding, string text)
{
if (text == null)
{
return null;
}
byte[] textAsBytes = encoding.GetBytes(text);
return System.Convert.ToBase64String(textAsBytes);
}
public static string DecodeBase64(this System.Text.Encoding encoding, string encodedText)
{
if (encodedText == null)
{
return null;
}
byte[] textAsBytes = System.Convert.FromBase64String(encodedText);
return encoding.GetString(textAsBytes);
}
}
}
Usage example:
using MyApplication.Helpers.Encoding; // !!!
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
}
static void Test1()
{
string textEncoded = System.Text.Encoding.UTF8.EncodeBase64("test1...");
System.Diagnostics.Debug.Assert(textEncoded == "dGVzdDEuLi4=");
string textDecoded = System.Text.Encoding.UTF8.DecodeBase64(textEncoded);
System.Diagnostics.Debug.Assert(textDecoded == "test1...");
}
static void Test2()
{
string textEncoded = System.Text.Encoding.UTF8.EncodeBase64(null);
System.Diagnostics.Debug.Assert(textEncoded == null);
string textDecoded = System.Text.Encoding.UTF8.DecodeBase64(textEncoded);
System.Diagnostics.Debug.Assert(textDecoded == null);
}
}
}
Based on the answers by Andrew Fox and Cebe, I turned it around and made them string extensions instead of Base64String extensions.
public static class StringExtensions
{
public static string ToBase64(this string text)
{
return ToBase64(text, Encoding.UTF8);
}
public static string ToBase64(this string text, Encoding encoding)
{
if (string.IsNullOrEmpty(text))
{
return text;
}
byte[] textAsBytes = encoding.GetBytes(text);
return Convert.ToBase64String(textAsBytes);
}
public static bool TryParseBase64(this string text, out string decodedText)
{
return TryParseBase64(text, Encoding.UTF8, out decodedText);
}
public static bool TryParseBase64(this string text, Encoding encoding, out string decodedText)
{
if (string.IsNullOrEmpty(text))
{
decodedText = text;
return false;
}
try
{
byte[] textAsBytes = Convert.FromBase64String(text);
decodedText = encoding.GetString(textAsBytes);
return true;
}
catch (Exception)
{
decodedText = null;
return false;
}
}
}
A slight variation on andrew.fox answer, as the string to decode might not be a correct base64 encoded string:
using System;
namespace Service.Support
{
public static class Base64
{
public static string ToBase64(this System.Text.Encoding encoding, string text)
{
if (text == null)
{
return null;
}
byte[] textAsBytes = encoding.GetBytes(text);
return Convert.ToBase64String(textAsBytes);
}
public static bool TryParseBase64(this System.Text.Encoding encoding, string encodedText, out string decodedText)
{
if (encodedText == null)
{
decodedText = null;
return false;
}
try
{
byte[] textAsBytes = Convert.FromBase64String(encodedText);
decodedText = encoding.GetString(textAsBytes);
return true;
}
catch (Exception)
{
decodedText = null;
return false;
}
}
}
}
You can use below routine to convert string to base64 format
public static string ToBase64(string s)
{
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(s);
return System.Convert.ToBase64String(buffer);
}
Also you can use very good online tool OnlineUtility.in to encode string in base64 format
URL safe Base64 Encoding/Decoding
public static class Base64Url
{
public static string Encode(string text)
{
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).TrimEnd('=').Replace('+', '-')
.Replace('/', '_');
}
public static string Decode(string text)
{
text = text.Replace('_', '/').Replace('-', '+');
switch (text.Length % 4)
{
case 2:
text += "==";
break;
case 3:
text += "=";
break;
}
return Encoding.UTF8.GetString(Convert.FromBase64String(text));
}
}
// Encoding
string passw = "tes123";
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(passw);
string pass = System.Convert.ToBase64String(plainTextBytes);
// Normal
var encodedTextBytes = Convert.FromBase64String(pass);
string plainText = Encoding.UTF8.GetString(encodedTextBytes);
using System;
using System.Text;
public static class Base64Conversions
{
public static string EncodeBase64(this string text, Encoding encoding = null)
{
if (text == null) return null;
encoding = encoding ?? Encoding.UTF8;
var bytes = encoding.GetBytes(text);
return Convert.ToBase64String(bytes);
}
public static string DecodeBase64(this string encodedText, Encoding encoding = null)
{
if (encodedText == null) return null;
encoding = encoding ?? Encoding.UTF8;
var bytes = Convert.FromBase64String(encodedText);
return encoding.GetString(bytes);
}
}
Usage
var text = "Sample Text";
var base64 = text.EncodeBase64();
base64 = text.EncodeBase64(Encoding.UTF8); //or with Encoding
For those that simply want to encode/decode individual base64 digits:
public static int DecodeBase64Digit(char digit, string digit62 = "+-.~", string digit63 = "/_,")
{
if (digit >= 'A' && digit <= 'Z') return digit - 'A';
if (digit >= 'a' && digit <= 'z') return digit + (26 - 'a');
if (digit >= '0' && digit <= '9') return digit + (52 - '0');
if (digit62.IndexOf(digit) > -1) return 62;
if (digit63.IndexOf(digit) > -1) return 63;
return -1;
}
public static char EncodeBase64Digit(int digit, char digit62 = '+', char digit63 = '/')
{
digit &= 63;
if (digit < 52)
return (char)(digit < 26 ? digit + 'A' : digit + ('a' - 26));
else if (digit < 62)
return (char)(digit + ('0' - 52));
else
return digit == 62 ? digit62 : digit63;
}
There are various versions of Base64 that disagree about what to use for digits 62 and 63, so DecodeBase64Digit can tolerate several of these.
You can display it like this:
var strOriginal = richTextBox1.Text;
byte[] byt = System.Text.Encoding.ASCII.GetBytes(strOriginal);
// convert the byte array to a Base64 string
string strModified = Convert.ToBase64String(byt);
richTextBox1.Text = "" + strModified;
Now, converting it back.
var base64EncodedBytes = System.Convert.FromBase64String(richTextBox1.Text);
richTextBox1.Text = "" + System.Text.Encoding.ASCII.GetString(base64EncodedBytes);
MessageBox.Show("Done Converting! (ASCII from base64)");
I hope this helps!
To encode a string into a base64 string in C#, you can use the Convert.ToBase64String method:
string originalString = "Hello World";
string encodedString = Convert.ToBase64String(Encoding.UTF8.GetBytes(originalString));
To decode a base64 encoded string into a string in C#, you can use the Convert.FromBase64String method:
string encodedString = "SGVsbG8gV29ybGQ=";
string originalString = Encoding.UTF8.GetString(Convert.FromBase64String(encodedString));
Related
byte[] ba = Encoding.Default.GetBytes(input);
var hexString = BitConverter.ToString(ba);
hexString = hexString.Replace("-", "");
Console.WriteLine("Or: " + hexString + " in hexadecimal");
So I got this, now how would I convert hexString to a base64 string?
I tried this, got the error:
Cannot convert from string to byte[]
If that solution works for anyone else, what am I doing wrong?
edit:
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
I tried this, but it
returns "Cannot implicitly convert type 'byte[]' to 'string'" on the first
line, then "Argument 1: cannot convert from 'string' to 'byte[]'".
You first need to convert your hexstring to a byte-array, which you can then convert to base-64.
To convert from your hexstring to Base-64, you can use:
public static string HexString2B64String(this string input)
{
return System.Convert.ToBase64String(input.HexStringToHex());
}
Where HexStringToHex is:
public static byte[] HexStringToHex(this string inputHex)
{
var resultantArray = new byte[inputHex.Length / 2];
for (var i = 0; i < resultantArray.Length; i++)
{
resultantArray[i] = System.Convert.ToByte(inputHex.Substring(i * 2, 2), 16);
}
return resultantArray;
}
Since .NET5 it can be done using standard library only:
string HexStringToBase64String(string hexString)
{
// hex-string is converted to byte-array
byte[] stringBytes = System.Convert.FromHexString(hexString);
// byte-array is converted base64-string
string res = System.Convert.ToBase64String(stringBytes);
return res;
}
Also there are good examples in docs
public string HexToBase64(string strInput)
{
try
{
var bytes = new byte[strInput.Length / 2];
for (var i = 0; i < bytes.Length; i++)
{
bytes[i] = Convert.ToByte(strInput.Substring(i * 2, 2), 16);
}
return Convert.ToBase64String(bytes);
}
catch (Exception)
{
return "-1";
}
}
On the contrary: https://stackoverflow.com/a/61224900/3988122
I want to convert string "8BABEEF9D2472E65" to big endian.
I already input in this function, I receive UINT Size error.. How can i do?
Function :
string bigToLittle(string data)
{
int number = Convert.ToInt32(data, 16);
byte[] bytes = BitConverter.GetBytes(number);
string retval = "";
foreach (byte b in bytes)
retval += b.ToString("X2");
return retval;
}
I think you can use System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary class.
string input = "8BABEEF9D2472E65";
var output = new SoapHexBinary(SoapHexBinary.Parse(input).Value.Reverse().ToArray())
.ToString();
Output: 652E47D2F9EEAB8B
Or Maybe
var output = IPAddress.HostToNetworkOrder(long.Parse(input, NumberStyles.HexNumber))
.ToString("X");
As we can not guess what exacly you want as output I let myself write missing possibilities(in code comments)... you can choose which you trully need:
internal class Program
{
private static int ReverseBytes(long val)
{
byte[] intAsBytes = BitConverter.GetBytes(val);
Array.Reverse(intAsBytes);
return BitConverter.ToInt32(intAsBytes, 0);
}
private static string IntToBinaryString(long v)
{
string s = Convert.ToString(v, 2);
string t = s.PadLeft(32, '0');
string res = "";
for (int i = 0; i < t.Length; ++i)
{
if (i > 0 && i%8 == 0)
res += " ";
res += t[i];
}
return res;
}
private static void Main(string[] args)
{
string sValue = "8BABEEF9D2472E65";
long sValueAsInt = long.Parse(sValue, System.Globalization.NumberStyles.HexNumber);
//output {-8382343524677898651}
string sValueAsStringAgain = IntToBinaryString(sValueAsInt);
//output {10001011 10101011 11101110 11111001 11010010 01000111 00101110 01100101}
byte[] data = Encoding.BigEndianUnicode.GetBytes(sValue);
string decodedX = Encoding.BigEndianUnicode.GetString(data);
string retval = data.Aggregate("", (current, b) => current + b.ToString("X2"));
//output {0038004200410042004500450046003900440032003400370032004500360035}
char[] decodedX2 = Encoding.BigEndianUnicode.GetString(data).Reverse().ToArray();
StringBuilder retval2 = new StringBuilder(); //output {56E2742D9FEEBAB8}
foreach (var b in decodedX2)
retval2.Append(b);
Console.ReadLine();
}
}
}
and bout yours Method:
public static string bigToLittle(string data)
{
long sValueAsInt = long.Parse(data, System.Globalization.NumberStyles.HexNumber);
byte[] bytes = BitConverter.GetBytes(sValueAsInt);
string retval = "";
foreach (byte b in bytes)
retval += b.ToString("X2");
return retval; //output {652E47D2F9EEAB8B}
}
I liked #Sebatsian's answer but I ran into issues with the entry being padded by extra zeroes, so I modified it slightly, in case you are doing something like converting Linux VMUUID's in Azure over to standard format. I made use of IPAddress.HostToNetworkOrder, which handles breaking your long into bytes and reversing them.
private string BigToLittle(string data)
{
long sValueAsInt = long.Parse(data, System.Globalization.NumberStyles.HexNumber);
var length = data.Length;
return IPAddress.HostToNetworkOrder(sValueAsInt).ToString("X2").Substring(0, length);
}
In usage:
string uuid = "090556DA-D4FA-764F-A9F1-63614EDA0163";
private string BigToLittle(string data)
{
long sValueAsInt = long.Parse(data, System.Globalization.NumberStyles.HexNumber);
var length = data.Length;
return IPAddress.HostToNetworkOrder(sValueAsInt).ToString("X2").Substring(0, length);
}
var elements = uuid.Split(new char[] { '-' });
var outMe = new List<string> { };
foreach (var item in elements)
{
outMe.Add(BigToLittle(item));
}
var output = String.Join("-", outMe);
//DA560509-FAD4-4F76-F1A9-6301DA4E6163
I want to convert text into binary and after that, to try convert binary into string text.
How can i convert tobin back into text if it is already a string?
private void iTalk_Button_12_Click(object sender, EventArgs e)
{
ambiance_RichTextBox2.Text = tobin(ambiance_RichTextBox1.Text);
}
public string tobin(string inp)
{
StringBuilder sb = new StringBuilder();
foreach (char L in inp.ToCharArray())
{
sb.Append(Convert.ToString(L, 2).PadLeft(8, '0'));
}
return sb.ToString();
}
private void iTalk_Button_12_Click(object sender, EventArgs e)
{
ambiance_RichTextBox2.Text = BinaryToString(ambiance_RichTextBox1.Text);
//use what u need: BinaryToString or StringToBinary.
}
Convert String to Binary:
public static string StringToBinary(string data)
{
StringBuilder sb = new StringBuilder();
foreach (char c in data.ToCharArray())
{
sb.Append(Convert.ToString(c, 2).PadLeft(8, '0'));
}
return sb.ToString();
}
Convert Binary to String:
public static string BinaryToString(string data)
{
List<Byte> byteList = new List<Byte>();
for (int i = 0; i < data.Length; i += 8)
{
byteList.Add(Convert.ToByte(data.Substring(i, 8), 2));
}
return Encoding.ASCII.GetString(byteList.ToArray());
}
Good luck!
You can use like this,
public static string BinaryToString(string data)
{
List<Byte> byteList = new List<Byte>();
for (int i = 0; i < data.Length; i += 8)
{
byteList.Add(Convert.ToByte(data.Substring(i, 8), 2));
}
return Encoding.ASCII.GetString(byteList.ToArray());
}
Currently you are converting a char (which can be represented as a number) to its binary representation (this number is the ASCII number). But if you want to convert a string to binary, you should use an encoding. The encoding determines how the text is converted to binary.
For example:
static void Main(string[] args)
{
string input = "This is an example text.";
Console.WriteLine(input);
string asBin = ToBinary(input);
Console.WriteLine(asBin);
string asText = ToText(asBin);
Console.WriteLine(asText);
}
static string ToBinary(string input, System.Text.Encoding encoding = null)
{
if (encoding == null)
encoding = System.Text.Encoding.UTF8;
var builder = new System.Text.StringBuilder();
var bytes = encoding.GetBytes(input); // Convert the text to bytes using the encoding
foreach (var b in bytes)
builder.Append(Convert.ToString(b, 2).PadLeft(8, '0')); //Convert the byte to its binary representation
return builder.ToString();
}
static string ToText(string bytes, System.Text.Encoding encoding = null)
{
if (encoding == null)
encoding = System.Text.Encoding.UTF8;
var byteCount = 8;
var byteArray = new byte[bytes.Length / 8]; // An array for the bytes
for (int i = 0; i < bytes.Length / byteCount; i++)
{
var subBytes = bytes.Substring(i * byteCount, byteCount); // Get a subpart of 8 bits
var b = Convert.ToByte(subBytes.TrimStart('0'), 2); // Convert the subpart to a byte
byteArray[i] = b; // Add the byte to the array
}
return encoding.GetString(byteArray); // Convert the array to text using the right encoding.
}
Now if you want to use ASCII encoding, you can call the functions as follows:
Console.WriteLine(input);
string asBin = ToBinary(input, System.Text.Encoding.ASCII);
Console.WriteLine(asBin);
string asText = ToText(asBin, System.Text.Encoding.ASCII);
Console.WriteLine(asText);
To convert a string to binary
string s = "hai";
byte []arr = System.Text.Encoding.ASCII.GetBytes(s);
To convert binary to string
byte[] arr ;
string s = Encoding.ASCII.GetString(arr);
All i need to do is verify the message below but I can not get Bouncy Castle to take the data in and given the public key verify the message. I am happy for it to be some other Lib that is used if it is free. This is to be embedded in my app that receives data over the Internet so i would prefer to keep it all managed code if at all possible.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
SCI Version: 1.0
SCI Code: 1
SCI Reason: OK
SCI Balance: 0.00050000
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MBC v1.0
iQEcBAEBAgAGBQJOGSuYAAoJEJ+5g06lAnqFkdsH/0NoqQbNvR8ZPe8D4gL4gvff
6K1t2LOt0sQGj+RSPeEbag7ZnVNI65LiES/yie1N6cXMkFgb9/ttjxi9/wlbxD/j
gSkuZ6mT9Oc5ExLsRZq9ygytvVs7Ol7uQm6oxDzJX1JMs0ls2EwJbmmpTEOHn8Av
dGlxdZeh+3RlqHJmOdssQCJ0cw5VXuj5vfP35OYz2zO2+sNg0eCXdR5Ml+2S7n3U
n9VHPEECg72LvpxF/y/nApopXoHpwECXoBwHgyd9QIIw1IJgalyRLDmAJ2WXdROV
ln2Mkt/km3KtBS3h4QL407wi/KhgZ4tFohZupt7zq2zUwtHWOhbL2KSUu939OKk=
=mIjM
-----END PGP SIGNATURE-----
For those interested i discovered an example for this exact task in the BouncyCastle source code. You need to download the source code not the binary to get the examples and it seems to have examples for all the different OpenPGP use cases.
Following Seer's suggestion to look at this example I finally got message verification running.
I have method VerifyFile which takes signed message and public key and returns the content of the message if the verification passes. For example it can be used like this:
string key = #"-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG C# v1.6.1.0
mQENBFpc87wBCACK5FG6Z70iovzSzQF7OEB/YbKF7SPS1/GZAQhp/2n2G8x5Lxj5
/CKqR8JLj1+222unuWgfqvfny0fLvttt1r6lAH/kqDYMBg26GTbZy93R5BYatBjd
pzYl/lIyKxc/QwDdZm8zNxeUpDSfoe9jVULOg0MiMDtdQupOf6CanlEioXfyf88F
1BLcJyFSckaYieosBw5hnnI+1cZZ3k+4HpDJJslVzngfTPWRibtN5PKff1CKP55E
ME99XkuPDaNL7XZmu7lZSEUN3jJFVydZQrDkvxddihzV4pTgRI3gDAFoJxxIYZX3
JsQAJItlqq8bBsQ+bKPikgAiMySGcEi+ilI5ABEBAAG0GnNoYWxhbWFub3YubWFy
aW5AZ21haWwuY29tiQEcBBABAgAGBQJaXPO8AAoJEBvHdfmVFHzkvHEH/179VAdH
gWRN5HVprsp4vHP3q1CJV9j+fPlQIZU3JEwrM+INxzpfSqZeN4NwB7yoo2NCdCNP
Ndg8zhiuEYM51hNtqU5cwYBcaAbm1so6TSVo8i4nrfN3+oDYEfYPqglNrd1V233J
oyLriwpGkR6RBYMY2q2Re+EFNR1bxUmeE0wnb8FOodRCSh0Wd3Iy9mvmhv5voHIr
aZzgsuifGw1JilSu9+RoC6b1CHb9jUkWQ/odkTvl5/rxA14TKstgoLoSLHktYQfw
le6B8+lPtmODtagWoDEeR/M0zm/wyCOt5wqjjJCgvaipUaA+oiijIYwCpqUBwfm3
DZ9DStGHGVxQQnc=
=s91O
-----END PGP PUBLIC KEY BLOCK-----
";
string message = #"-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
test tes tes ts tse tse t
-----BEGIN PGP SIGNATURE-----
Version: OpenPGP.js v1.0.1
Comment: http://openpgpjs.org
wsBcBAEBCAAQBQJaXP5WCRAbx3X5lRR85AAAUcoH/jtcyWcpTVyXyz/ptWLo
Hx+g51EeeA0Hpq7kZCXu4FuyhNn/QvnvKyt9qegxQoRSZhT37ln8t80NW6sS
B4XVFziq8TBkjPuaYBI/ijbLigdPMEi81PsOpIXx3BXKCt27TLmUVHpFTWPa
u2NQUQl3k3Xc0H1sy1A+jmjfvCyqWxTOU1IY4rlzRKHdp+D1oCz5iKfyfUko
ktAZgqOMx5pWL975YhM793MS8aYqhOdQpeuW401fm18xxwE4x6svSSys+qq8
MdkL/i7YVjUKr/M8SIrGPb/IjKwClM7jfpN+sHv0p/GcQ7J1kmXYUdA6AJp5
Z0vYk4aPcMSlrPwdRX21I9w=
=zXfe
-----END PGP SIGNATURE-----
";
MemoryStream messageStream = new MemoryStream(Encoding.ASCII.GetBytes(message));
MemoryStream keyStream = new MemoryStream(Encoding.ASCII.GetBytes(key));
try {
var msg= VerifyFile(messageStream,
PgpUtilities.GetDecoderStream(keyStream));
// verification passes msg is the content of the message
} catch (Exception e) {
// verification fails
}
And here is the implementation:
private static String VerifyFile(Stream inputStream, Stream keyIn)
{
ArmoredInputStream aIn = new ArmoredInputStream(inputStream);
MemoryStream outStr = new MemoryStream(); // File.Create(resultName);
//
// write out signed section using the local line separator.
// note: trailing white space needs to be removed from the end of
// each line RFC 4880 Section 7.1
//
MemoryStream lineOut = new MemoryStream();
int lookAhead = ReadInputLine(lineOut, aIn);
byte[] lineSep = LineSeparator;
if (lookAhead != -1 && aIn.IsClearText())
{
byte[] line = lineOut.ToArray();
outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line));
outStr.Write(lineSep, 0, lineSep.Length);
while (lookAhead != -1 && aIn.IsClearText())
{
lookAhead = ReadInputLine(lineOut, lookAhead, aIn);
line = lineOut.ToArray();
outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line));
outStr.Write(lineSep, 0, lineSep.Length);
}
}
else
{
// a single line file
if (lookAhead != -1)
{
byte[] line = lineOut.ToArray();
outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line));
outStr.Write(lineSep, 0, lineSep.Length);
}
}
outStr.Flush();
//outStr.Close();
PgpPublicKeyRingBundle pgpRings = new PgpPublicKeyRingBundle(keyIn);
PgpObjectFactory pgpFact = new PgpObjectFactory(aIn);
PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
PgpSignature sig = p3[0];
var key = pgpRings.GetPublicKey(sig.KeyId);
if (key == null)
{
throw new Exception("Can't verify the message signature.");
}
sig.InitVerify(key);
//
// read the input, making sure we ignore the last newline.
//
outStr.Seek(0, SeekOrigin.Begin);
StreamReader reader = new StreamReader(outStr);
string messageContent = reader.ReadToEnd();
outStr.Seek(0, SeekOrigin.Begin);
Stream sigIn = outStr; //File.OpenRead(resultName);
lookAhead = ReadInputLine(lineOut, sigIn);
ProcessLine(sig, lineOut.ToArray());
if (lookAhead != -1)
{
do
{
lookAhead = ReadInputLine(lineOut, lookAhead, sigIn);
sig.Update((byte)'\r');
sig.Update((byte)'\n');
ProcessLine(sig, lineOut.ToArray());
}
while (lookAhead != -1);
}
sigIn.Close();
if (sig.Verify()) {
// signature verified
return messageContent;
} else {
// signature verification failed
throw new Exception("Can't verify the message signature.");
}
}
private static int ReadInputLine(
MemoryStream bOut,
Stream fIn)
{
bOut.SetLength(0);
int lookAhead = -1;
int ch;
while ((ch = fIn.ReadByte()) >= 0)
{
bOut.WriteByte((byte)ch);
if (ch == '\r' || ch == '\n')
{
lookAhead = ReadPassedEol(bOut, ch, fIn);
break;
}
}
return lookAhead;
}
private static int ReadPassedEol(
MemoryStream bOut,
int lastCh,
Stream fIn)
{
int lookAhead = fIn.ReadByte();
if (lastCh == '\r' && lookAhead == '\n')
{
bOut.WriteByte((byte)lookAhead);
lookAhead = fIn.ReadByte();
}
return lookAhead;
}
private static void ProcessLine(
PgpSignature sig,
byte[] line)
{
// note: trailing white space needs to be removed from the end of
// each line for signature calculation RFC 4880 Section 7.1
int length = GetLengthWithoutWhiteSpace(line);
if (length > 0)
{
sig.Update(line, 0, length);
}
}
private static void ProcessLine(
Stream aOut,
PgpSignatureGenerator sGen,
byte[] line)
{
int length = GetLengthWithoutWhiteSpace(line);
if (length > 0)
{
sGen.Update(line, 0, length);
}
aOut.Write(line, 0, line.Length);
}
private static int GetLengthWithoutSeparatorOrTrailingWhitespace(byte[] line)
{
int end = line.Length - 1;
while (end >= 0 && IsWhiteSpace(line[end]))
{
end--;
}
return end + 1;
}
private static bool IsLineEnding(
byte b)
{
return b == '\r' || b == '\n';
}
private static int GetLengthWithoutWhiteSpace(
byte[] line)
{
int end = line.Length - 1;
while (end >= 0 && IsWhiteSpace(line[end]))
{
end--;
}
return end + 1;
}
private static bool IsWhiteSpace(
byte b)
{
return IsLineEnding(b) || b == '\t' || b == ' ';
}
private static int ReadInputLine(
MemoryStream bOut,
int lookAhead,
Stream fIn)
{
bOut.SetLength(0);
int ch = lookAhead;
do
{
bOut.WriteByte((byte)ch);
if (ch == '\r' || ch == '\n')
{
lookAhead = ReadPassedEol(bOut, ch, fIn);
break;
}
}
while ((ch = fIn.ReadByte()) >= 0);
if (ch < 0)
{
lookAhead = -1;
}
return lookAhead;
}
private static byte[] LineSeparator
{
get { return Encoding.ASCII.GetBytes(Environment.NewLine); }
}
using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Bcpg.OpenPgp;
namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
{
/**
* A simple utility class that signs and verifies files.
* <p>
* To sign a file: SignedFileProcessor -s [-a] fileName secretKey passPhrase.<br/>
* If -a is specified the output file will be "ascii-armored".</p>
* <p>
* To decrypt: SignedFileProcessor -v fileName publicKeyFile.</p>
* <p>
* <b>Note</b>: this example will silently overwrite files, nor does it pay any attention to
* the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
* will have been used.</p>
* <p>
* <b>Note</b>: the example also makes use of PGP compression. If you are having difficulty Getting it
* to interoperate with other PGP programs try removing the use of compression first.</p>
*/
public sealed class SignedFileProcessor
{
private SignedFileProcessor() {}
/**
* verify the passed in file as being correctly signed.
*/
private static void VerifyFile(
Stream inputStream,
Stream keyIn)
{
inputStream = PgpUtilities.GetDecoderStream(inputStream);
PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
PgpCompressedData c1 = (PgpCompressedData) pgpFact.NextPgpObject();
pgpFact = new PgpObjectFactory(c1.GetDataStream());
PgpOnePassSignatureList p1 = (PgpOnePassSignatureList) pgpFact.NextPgpObject();
PgpOnePassSignature ops = p1[0];
PgpLiteralData p2 = (PgpLiteralData) pgpFact.NextPgpObject();
Stream dIn = p2.GetInputStream();
PgpPublicKeyRingBundle pgpRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn));
PgpPublicKey key = pgpRing.GetPublicKey(ops.KeyId);
Stream fos = File.Create(p2.FileName);
ops.InitVerify(key);
int ch;
while ((ch = dIn.ReadByte()) >= 0)
{
ops.Update((byte)ch);
fos.WriteByte((byte) ch);
}
fos.Close();
PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
PgpSignature firstSig = p3[0];
if (ops.Verify(firstSig))
{
Console.Out.WriteLine("signature verified.");
}
else
{
Console.Out.WriteLine("signature verification failed.");
}
}
/**
* Generate an encapsulated signed file.
*
* #param fileName
* #param keyIn
* #param outputStream
* #param pass
* #param armor
*/
private static void SignFile(
string fileName,
Stream keyIn,
Stream outputStream,
char[] pass,
bool armor,
bool compress)
{
if (armor)
{
outputStream = new ArmoredOutputStream(outputStream);
}
PgpSecretKey pgpSec = PgpExampleUtilities.ReadSecretKey(keyIn);
PgpPrivateKey pgpPrivKey = pgpSec.ExtractPrivateKey(pass);
PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
foreach (string userId in pgpSec.PublicKey.GetUserIds())
{
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
spGen.SetSignerUserId(false, userId);
sGen.SetHashedSubpackets(spGen.Generate());
// Just the first one!
break;
}
Stream cOut = outputStream;
PgpCompressedDataGenerator cGen = null;
if (compress)
{
cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.ZLib);
cOut = cGen.Open(cOut);
}
BcpgOutputStream bOut = new BcpgOutputStream(cOut);
sGen.GenerateOnePassVersion(false).Encode(bOut);
FileInfo file = new FileInfo(fileName);
PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
Stream lOut = lGen.Open(bOut, PgpLiteralData.Binary, file);
FileStream fIn = file.OpenRead();
int ch = 0;
while ((ch = fIn.ReadByte()) >= 0)
{
lOut.WriteByte((byte) ch);
sGen.Update((byte)ch);
}
fIn.Close();
lGen.Close();
sGen.Generate().Encode(bOut);
if (cGen != null)
{
cGen.Close();
}
if (armor)
{
outputStream.Close();
}
}
public static void Main(
string[] args)
{
// TODO provide command-line option to determine whether to use compression in SignFile
if (args[0].Equals("-s"))
{
Stream keyIn, fos;
if (args[1].Equals("-a"))
{
keyIn = File.OpenRead(args[3]);
fos = File.Create(args[2] + ".asc");
SignFile(args[2], keyIn, fos, args[4].ToCharArray(), true, true);
}
else
{
keyIn = File.OpenRead(args[2]);
fos = File.Create(args[1] + ".bpg");
SignFile(args[1], keyIn, fos, args[3].ToCharArray(), false, true);
}
keyIn.Close();
fos.Close();
}
else if (args[0].Equals("-v"))
{
using (Stream fis = File.OpenRead(args[1]),
keyIn = File.OpenRead(args[2]))
{
VerifyFile(fis, keyIn);
}
}
else
{
Console.Error.WriteLine("usage: SignedFileProcessor -v|-s [-a] file keyfile [passPhrase]");
}
}
}
}
I'm trying to convert this piece of code from PHP to C#. It's part of a Captive Portal. Could somebody explain what it does?
$hexchal = pack ("H32", $challenge);
if ($uamsecret) {
$newchal = pack ("H*", md5($hexchal . $uamsecret));
} else {
$newchal = $hexchal;
}
$response = md5("\0" . $password . $newchal);
$newpwd = pack("a32", $password);
$pappassword = implode ("", unpack("H32", ($newpwd ^ $newchal)));
I also encountered the need of php's pack-unpack functions in c# but did not get any good resource.
So i thought to do it myself. I have verified the function's input with pack/unpack/md5 methods found at onlinephpfunctions.com. Since i have done code only as per my requirements. This can be extended for other formats
Pack
private static string pack(string input)
{
//only for H32 & H*
return Encoding.Default.GetString(FromHex(input));
}
public static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
MD5
private static string md5(string input)
{
byte[] asciiBytes = Encoding.Default.GetBytes(input);
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string hashedString = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
return hashedString;
}
Unpack
private static string unpack(string p1, string input)
{
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
string a = Convert.ToInt32(input[i]).ToString("X");
output.Append(a);
}
return output.ToString();
}
Eduardo,
if you take a look at the pack manual, pack is used to convert a string in (hex, octal, binary )to his number representation.
so
$hexcal = pack('H32', $challenge);
would convert a string like 'cca86bc64ec5889345c4c3d8dfc7ade9' to the actual 0xcca... de9
if $uamsecret exist do the same things with the MD5 of hexchal concacteate with the uamsecret.
if ($uamsecret) {
$newchal = pack ("H*", md5($hexchal . $uamsecret));
} else {
$newchal = $hexchal;
}
$response = md5("\0" . $password . $newchal);
MD% '\0' + $password + $newchal
$newpwd = pack("a32", $password);
pad password to 32 byte
$pappassword = implode ("", unpack("H32", ($newpwd ^ $newchal)));
do a xor newpwd and newchal and convert it to a hexadecimal string, I don't get the implode() maybe it's to convert to string to an array of character.