Making HTTPS call in C# with the BouncyCastle library - c#-4.0

Using C# 4.0, I need to make HTTPS call with the BouncyCastle library (Short story : Windows XP + TLS 1.2).
When using the following code, I get a "HTTP Error 400. The request verb is invalid."
Here is my code :
using (var client = new TcpClient("serverName", 443))
{
var sr = new SecureRandom();
var cl = new MyTlsClient();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
protocol.Connect(new MyTlsClient());
using (var stream = protocol.Stream)
{
var hdr = new StringBuilder();
hdr.AppendLine("GET /Url/WebService.asmx?wsdl HTTP/1.1");
hdr.AppendLine("Host: serverName");
hdr.AppendLine("Content-Type: text/xml; charset=utf-8");
hdr.AppendLine("Connection: close");
hdr.AppendLine();
var dataToSend = Encoding.ASCII.GetBytes(hdr.ToString());
sr.NextBytes(dataToSend);
stream.Write(dataToSend, 0, dataToSend.Length);
int totalRead = 0;
string response = "";
byte[] buff = new byte[1000];
do
{
totalRead = stream.Read(buff, 0, buff.Length);
response += Encoding.ASCII.GetString(buff, 0, totalRead);
} while (totalRead == buff.Length);
}
}
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) { return null; }
public void NotifyServerCertificate(Certificate serverCertificate) { }
}
What I've already done :
Using WireShark to decrypt the ssl stream and inspect the request send => I've never succeeded to decrypt ssl stream
Using fiddler to decrypt the https stream => No detection by fiddler so I suspect something might be badly encrypted
Any ideas ?

Thanks to PeterDettman who gave me the solution :
I must not use the sr.NextBytes(instructions), so the code becomes :
using (var client = new TcpClient("serverName", 443))
{
var sr = new SecureRandom();
var cl = new MyTlsClient();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
protocol.Connect(new MyTlsClient());
using (var stream = protocol.Stream)
{
var hdr = new StringBuilder();
hdr.AppendLine("GET /Url/WebService.asmx?wsdl HTTP/1.1");
hdr.AppendLine("Host: serverName");
hdr.AppendLine("Content-Type: text/xml; charset=utf-8");
hdr.AppendLine("Connection: close");
hdr.AppendLine();
var dataToSend = Encoding.ASCII.GetBytes(hdr.ToString());
stream.Write(dataToSend, 0, dataToSend.Length);
int totalRead = 0;
string response = "";
byte[] buff = new byte[1000];
do
{
totalRead = stream.Read(buff, 0, buff.Length);
response += Encoding.ASCII.GetString(buff, 0, totalRead);
} while (totalRead == buff.Length);
}
}

Related

Javascript GZIP and btoa and decompress with C#

i am developing an application where i compress large JSON data using pako.gzip and then use the btoa function to make it base64string in order to post the data to the server. In the javascript i wrote:
var data = JSON.stringify(JSONData);
var ZippedData = pako.gzip(data, { to: 'string' });
var base64String = btoa(ZippedData);
/* post to server*/
$http.post("URL?base64StringParam=" + base64String").then(function (response) {
//do stuff
});
the problem is that i need to decompress the data again in C# code after posting in order to do other workings on it. In the C# code i wrote:
byte[] data = Convert.FromBase64String(base64StringParam);
string decodedString = System.Text.ASCIIEncoding.ASCII.GetString(data);
Encoding enc = Encoding.Unicode;
MemoryStream stream = new MemoryStream(enc.GetBytes(decodedString));
GZipStream decompress = new GZipStream(stream, CompressionMode.Decompress);
string plainDef = "";
and i get the error here
using (var sr = new StreamReader(decompress))
{
plainDef = sr.ReadToEnd();
}
Found invalid data while decoding.
any help to decompress the data back in C# will be appreciated
EDIT:to sum up what needed to be done
javascript does the following:
Plain text >> to >> gzip bytes >> to >> base64 string
i need C# to do the reverse:
Base64 >> to >> unzip bytes >> to >> plain text
Assuming the following js:
dataToCommitString = btoa(pako.gzip(dataToCommitString, { to: "string" }));
This is the correct c# code to compress/decompress with GZip: Taken from https://stackoverflow.com/a/7343623/679334
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YourNamespace
{
public class GZipCompressor : ICompressor
{
private static void CopyTo(Stream src, Stream dest)
{
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
{
dest.Write(bytes, 0, cnt);
}
}
public byte[] Zip(string str)
{
var bytes = Encoding.UTF8.GetBytes(str);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(mso, CompressionMode.Compress))
{
//msi.CopyTo(gs);
CopyTo(msi, gs);
}
return mso.ToArray();
}
}
public string Unzip(byte[] bytes)
{
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(msi, CompressionMode.Decompress))
{
//gs.CopyTo(mso);
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
}
}
}
Calling it as follows:
value = _compressor.Unzip(Convert.FromBase64CharArray(value.ToCharArray(), 0, value.Length));
In client use:
let output = pako.gzip(JSON.stringify(obj));
send as: 'Content-Type': 'application/octet-stream'
=====================
then in C#:
[HttpPost]
[Route("ReceiveCtImage")]
public int ReceiveCtImage([FromBody] byte[] data)
{
var json = Decompress(data);
return 1;
}
public static string Decompress(byte[] data)
{
// Read the last 4 bytes to get the length
byte[] lengthBuffer = new byte[4];
Array.Copy(data, data.Length - 4, lengthBuffer, 0, 4);
int uncompressedSize = BitConverter.ToInt32(lengthBuffer, 0);
var buffer = new byte[uncompressedSize];
using (var ms = new MemoryStream(data))
{
using (var gzip = new GZipStream(ms, CompressionMode.Decompress))
{
gzip.Read(buffer, 0, uncompressedSize);
}
}
string json = Encoding.UTF8.GetString(buffer);
return json;
}

Streaming video files in asp.net core 2

I want to play video in browser using asp.net core
in html I have
<video width="320" height="240" controls>
<source src="http://localhost:55193/api/VideoPlayer/Download" type="video/mp4">
Your browser does not support the video tag.
</video>
and in asp.net core 2
[HttpGet]
[Route("Download")]
public async Task<IActionResult> Download()
{
var path = #"d:\test\somemovie.mp4";
var memory = new MemoryStream();
using (var stream = new FileStream(#"d:\test\somemovie.mp4", FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 65536, FileOptions.Asynchronous | FileOptions.SequentialScan))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, "application/octet-stream", Path.GetFileName(path));
}
Does this code play file by streaming( I mean buffer file chunk by chunk and play)?
And if I want to play file from any position which user set the player's progress, How I can do it?
Just use the normal return PhysicalFile here:
public class HomeController : Controller
{
public IActionResult Download()
{
return PhysicalFile(#"d:\test\somemovie.mp4", "application/octet-stream");
}
Because it supports range headers which are necessary for streaming and resuming a file download:
Also return File, FileStreamResult and VirtualFileResult support partial range requests too. Even static files middleware supports that too.
Something is wrong. My sample doesn't support resume
[HttpGet]
[Route("Download2")]
public IActionResult Download2()
{
return PhysicalFile(#"d:\test\somemovie.mp4", "application/octet-stream");
}
and there is no accept-ranges in response headers
but when I use
[HttpGet]
[Route("Download")]
public async Task<IActionResult> Download()
{
var path = #"d:\test\somemovie.mp4";
var memory = new MemoryStream();
using (var stream = new FileStream(#"d:\test\somemovie.mp4", FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 65536, FileOptions.Asynchronous | FileOptions.SequentialScan))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, "application/octet-stream", Path.GetFileName(path),true); //enableRangeProcessing = true
}
with "enableRangeProcessing" parameter true
Can you provide more explanation why the case is this?
And which solution I should use? I got confused.
static MediaStream song = null;
static byte[] SongArray = null;
song = await client.GetMediaStreamAsync(streamFilter).ConfigureAwait(false);
MemoryStream ms = new MemoryStream();
song.CopyTo(ms);
SongArray = ms.ToArray();
long fSize = song.Length, startbyte = 0, endbyte = fSize - 1;
int statusCode = 200;
var rangeRequest = Request.Headers["Range"].ToString();
if (!string.IsNullOrEmpty(rangeRequest))
{
string[] range = Request.Headers["Range"].ToString().Split(new char[] { '=', '-' });
startbyte = Convert.ToInt64(range[1]);
if (range.Length > 2 && range[2] != "")
{
endbyte = Convert.ToInt64(range[2]);
}
if (startbyte != 0 || endbyte != fSize - 1 || range.Length > 2 && range[2] == "")
{
statusCode = 206;
}
}
long desSize = endbyte - startbyte + 1;
Response.StatusCode = statusCode;
// Response.Headers.Add(ETag = new EntityTagHeaderValue(String.Format("\"{0}\"", _eTag));
Response.ContentType = "video/" + streamFilter.Container.GetFileExtension();
Response.Headers.Add("Content-Accept", Response.ContentType);
Response.Headers.Add("Content-Length", desSize.ToString());
Response.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", startbyte, endbyte, fSize));
return new FileStreamResult(new MemoryStream(SongArray, (int)startbyte, (int)desSize), Response.ContentType);

PCLCrypto exception 'CryptographicException: Bad PKCS7 padding. Invalid length'

I'm struggling with the PCLCryptho libraby, I can't get it working without retrieving the exception 'CryptographicException: Bad PKCS7 padding. Invalid length'. Running the code once is working, but running it multiple times after each other fails (with different input strings). The decryption takes place after a new instance of the program. I'm running this code on iOS with Xamarin Forms. Here's my code (I'm using the same VI each time and save the salt in the Settinsg for now):
public static string EncryptAnswer(string answer, string passWord)
{
try
{
var keyMaterial = CreateKey(passWord);
var cipherTextBuffer = GetBytes(answer);
var symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyMaterial);
using (var encryptor = WinRTCrypto.CryptographicEngine.CreateEncryptor(symmetricKey, GetBytes("vivivivivivivivi")))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (var bWriter = new BinaryWriter(cs))
{
bWriter.Write(cipherTextBuffer, 0, cipherTextBuffer.Length);
cs.FlushFinalBlock();
}
}
return GetString(ms.ToArray());
}
}
}
catch (Exception e)
{
return string.Empty;
}
}
public static string DecryptAnswer(string encryptedAnswer, string passWord)
{
try
{
var cipherTextBuffer = GetBytes(encryptedAnswer);
var keyMaterial = CreateKey(passWord);
var symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyMaterial);
using (var decryptor = WinRTCrypto.CryptographicEngine.CreateDecryptor(symmetricKey, GetBytes("vivivivivivivivi")))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
using (var binWriter = new BinaryWriter(cs))
{
binWriter.Write(cipherTextBuffer, 0, cipherTextBuffer.Length);
}
return GetString(ms.ToArray());
}
}
}
catch (Exception e)
{
}
return string.Empty;
}
public static byte[] CreateSalt()
{
var salt = WinRTCrypto.CryptographicBuffer.GenerateRandom(8);
CrossSettings.Current.AddOrUpdateValue("Salt", GetString(salt));
return salt;
}
private static byte[] GetSalt()
{
var saltString = CrossSettings.Current.GetValueOrDefault<string>("Salt");
var salt = GetBytes(saltString);
return salt;
}
private static byte[] CreateKey(string passWord)
{
var key = NetFxCrypto.DeriveBytes.GetBytes(passWord, GetSalt(), 1000, 32);
return key;
}
private static byte[] GetBytes(string str)
{
return Encoding.Unicode.GetBytes(str);
}
private static string GetString(byte[] bytes)
{
return Encoding.Unicode.GetString(bytes, 0, bytes.Length);
}
This seems to be equal to the answers and examples I found. Can someone tell me what's wrong?

how to use Management API in Windows Form / C# - but The remote server returned an error: (400) Bad Request

I have a problem in API Management, I want to create images in item 1 item, but I still can not do it forever. I use c # language, I feel depressed
i want to create a resource in catchoom.
can you help me
byte[] buffer = null;
byte[] data = null;
byte[] data1 = null;
HttpWebRequest request = null;
int bytesRead = 0;
long length = 0;
string boundary = DateTime.Now.Ticks.ToString("x");
// string boundary = "AaB03x";
StringBuilder sb = null;
// Create the HttpWebRequest object
request = (HttpWebRequest)HttpWebRequest.Create("https://crs.catchoom.com/api/v0/image/?api_key=5aba12ba6974c04ebc95da45ba1597d27d75238f");
// Specify the ContentType
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
// Specify the Method
request.Method = "POST";
request.KeepAlive = false;
// Create the StringBuilder object
sb = new StringBuilder();
// Constrcut the POST header message
sb.AppendLine("");
sb.AppendLine("--" + boundary);
sb.AppendLine("Content-Disposition: form-data; name=\"anh\"");
sb.AppendLine("");
sb.AppendLine("/api/v0/item/aee726ff67274fcb80f4c24f27861c1e/");
sb.AppendLine("--" + boundary);
sb.AppendLine("Content-Disposition: file; name=\"anh\"; filename=\"anh\"");
sb.AppendLine("Content-Type: image/jpg");
sb.AppendLine("");
StringBuilder sb1 = new StringBuilder();
sb1.AppendLine("");
sb1.AppendLine("--" + boundary + "--");
// Convert the StringBuilder into a string
data = Encoding.UTF8.GetBytes(sb.ToString());
data1 = Encoding.UTF8.GetBytes(sb1.ToString());
//
using (FileStream fs = new FileStream(#"D:\17. NHATLINH\ToolKit_Catchoom\ToolKit_Catchoom\bin\Debug\aa.jpg", FileMode.Open, FileAccess.Read))
{
length = data.Length + fs.Length + data1.Length;
// đưa thông tin chiều dài của gói gửi đi vào
request.ContentLength = length;
//
using (Stream stream = request.GetRequestStream())
{
// ghi header vào gói gửi đi
stream.Write(data, 0, data.Length);
//
buffer = new Byte[checked((uint)Math.Min(4096, (int)fs.Length))];
// buffer = new Byte[fs.Length];
// Write the file contents
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0)
{
stream.Write(buffer, 0, bytesRead);
}
stream.Write(data1, 0, data1.Length);
//
try
{
Console.WriteLine(request.ContentType);
Console.WriteLine(sb.ToString() + sb1.ToString());
WebResponse responce = request.GetResponse();
Stream s = responce.GetResponseStream();
StreamReader sr = new StreamReader(s);
MessageBox.Show(sr.ReadToEnd());
}
catch (Exception ec)
{
MessageBox.Show(ec.Message);
}
}
}
Building a multipart-encoded request is an error-prone task ( it is normal if you feel frustrated trying ), I recommend you to use a library to handle this kind of things, no point in reinventing the wheel :)
If you are using the Microsoft .NET Framework >= 4.5, you may use the HttpClient class as this answer explains.
Hope this help you ;)

How to create azure VM with Rest Api

Here is the code, but it prompts error:
The image o3lceiy3.ioa201305211013360129.vhd does not exist.
the subscriptionId and X509Certificate2 are valid
internal class Program
{
public static X509Certificate2 Certificate { get; set; }
private static void Main(string[] args)
{
const string subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
//#"https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments";
var url = string.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments",
subscriptionId, "edoc2cloudtest");
var myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = "POST";
myReq.Headers.Add("x-ms-version", "2012-03-01");
myReq.Proxy = null;
myReq.Timeout = 30000;
myReq.ContentType = "application/xml";
var postData = ReadConfig();
using (var reqStream = myReq.GetRequestStream())
{
var data = Encoding.UTF8.GetBytes(postData);
reqStream.Write(data, 0, data.Length);
reqStream.Flush();
}
Certificate = GetX509Certificate();
myReq.ClientCertificates.Add(Certificate);
try
{
var myRes = (HttpWebResponse) myReq.GetResponse();
}
catch (WebException exWeb)
{
// Parse the web response.
Stream responseStream = exWeb.Response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
XmlDocument xDocResp = new XmlDocument();
xDocResp.Load(reader);
HttpWebResponse responseStatus = (HttpWebResponse)exWeb.Response;
responseStream.Close();
reader.Close();
var result = NiceFormatXml(xDocResp);
Console.WriteLine(result);
}
}
private static string NiceFormatXml(XmlDocument xDoc)
{
StringBuilder niceString = new StringBuilder();
StringWriter strWriter = new StringWriter(niceString);
XmlTextWriter xmlWriter = new XmlTextWriter(strWriter);
xmlWriter.Formatting = Formatting.Indented;
xDoc.WriteTo(xmlWriter);
xmlWriter.Close();
strWriter.Close();
return niceString.ToString();
}
private static X509Certificate2 GetX509Certificate()
{
X509Certificate2 certificate2 = null;
var store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var collection = store.Certificates;
var fcollection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
const string certificateThumbprint = "‎‎‎‎7dfbc7369306ed096b7e5c7b4ba6e99f190240e9";
store.Close();
if (fcollection.Count > 0)
{
foreach (var variable in fcollection)
{
if (variable.Thumbprint != null &&
variable.Thumbprint.Equals(certificateThumbprint, StringComparison.InvariantCultureIgnoreCase))
{
certificate2 = variable;
}
}
}
return certificate2;
}
private static string ReadConfig()
{
string path = System.AppDomain.CurrentDomain.BaseDirectory + "Edoc2Cloud.xml";
//string path = System.AppDomain.CurrentDomain.BaseDirectory + "VM-CreateVM.xml";
string s;
using (var sr = new StreamReader(path, Encoding.GetEncoding("GB2312")))
{
s = sr.ReadToEnd();
}
return s;
}
}
Here is the XML:
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>EDoc2Test</Name>
<DeploymentSlot>Staging</DeploymentSlot>
<Label>EDoc2Testlabe</Label>
<RoleList>
<Role>
<RoleName>EDoc2TestRoleName</RoleName>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet>
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
<ComputerName>computer-name</ComputerName>
<AdminPassword>APasswor_324d</AdminPassword>
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
</ConfigurationSet>
</ConfigurationSets>
<AvailabilitySetName>EDoc2TestSetName</AvailabilitySetName>
<OSVirtualHardDisk>
<HostCaching>ReadWrite</HostCaching>
<DiskName>SomeName-0-20121007173943</DiskName>
<MediaLink>http://portalvhdsx4flx9dhmjyt1.blob.core.windows.net/vhds/o3lceiy3.ioa201305211013360129.vhd</MediaLink>
<SourceImageName>o3lceiy3.ioa201305211013360129.vhd</SourceImageName>
</OSVirtualHardDisk>
<RoleSize>Medium</RoleSize>
</Role>
Based on the error you're receiving and the XML you've specified, can you please check if there is an image by the name o3lceiy3.ioa201305211013360129.vhd in your custom images? You could find that information by logging into the portal and going to Virtual Machines --> Images.
Documentation regarding <SourceImageName> parameter states that it is needed when you want to create a virtual machine either by using system or custom images.
You can read the complete documentation here: http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx#OSVirtualHardDisk.

Resources