So I'm trying to do a REST API call to AWS' SNS service, but I keep getting an IncompleteSignature error. I based myself on http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/#csharp on how to create the signature and http://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/HMACAuth.html to find out what to sign.
Here's the test code I came up with:
static void Main(string[] args)
{
string region = "us-west-2";
string msg = "This is a test!";
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string key = "XXXXXXXXXXXXXXX";
string arn = "arn:aws:sns:us-west-2:xxxxxxxxxx:snstest1";
string query = "Action=Publish&Message=" + HttpUtility.UrlEncode(msg) + "&MessageStructure=json&TargetArn=" + HttpUtility.UrlEncode(arn) + "&SignatureMethod=HmacSHA256&AWSAccessKeyId=" + key + "&SignatureVersion=2&Timestamp=" + HttpUtility.UrlEncode(DateTime.UtcNow.ToString("o"));
string tosign = "GET\nsns." + region + ".amazonaws.com\n/\n" + query;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(tosign);
var hmacsha256 = new HMACSHA256(keyByte);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
query += "&signature=" + HttpUtility.UrlEncode(Convert.ToBase64String(hashmessage));
Console.WriteLine("REST Call: https://sns." + region + ".amazonaws.com/?" + query);
}
Any idea what might be wrong?
EDIT: I tried changing the signature part with the code from http://wiki.alphasoftware.com/~alphafiv/DotNet+Example%3A+Digital+Hash it uses CharArray instead of the byte[], not sure which is right, it produces a different signature but it still doesn't work with AWS.
EDIT2: After long tries I finally figured out that AWS expects Signature= and not signature=, but now I'm getting a SignatureDoesNotMatch error, so I need to figure that out next. Also I don't know why this kind of question would get downvoted. Once I figure out the syntax, an AWS API call would be trivial to do in any app. If you use the AWS .NET SDK you're adding 6 megs to your binary. How is that not a worthwhile endeavor?
SOLUTION:
This code works and will send a SNS notification without the AWS SDK:
static void Main(string[] args)
{
string region = "us-west-2";
string msg = "Test test: sfdfds\nfsd: sdsda\n";
string secret = "XXXXXXXXXXXXXXXXXXX";
string key = "ZZZZZZZZZZZ";
string arn = "arn:aws:sns:us-west-2:YYYYYYYYYYY:snstest1";
string query = "AWSAccessKeyId=" + Uri.EscapeDataString(key) + "&Action=Publish&Message=" + Uri.EscapeDataString(msg) + "&SignatureMethod=HmacSHA256&SignatureVersion=2&TargetArn=" + Uri.EscapeDataString(arn) + "&Timestamp=" + Uri.EscapeDataString(System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"));
string tosign = "GET\nsns." + region + ".amazonaws.com\n/\n" + query;
Console.WriteLine(tosign + "\n");
UTF8Encoding encoding = new UTF8Encoding();
HMACSHA256 hmac = new HMACSHA256(encoding.GetBytes(secret));
string signature = Convert.ToBase64String(hmac.ComputeHash(encoding.GetBytes(tosign)));
query += "&Signature=" + Uri.EscapeDataString(signature);
Console.WriteLine("REST Call: https://sns." + region + ".amazonaws.com/?" + query);
}
There is nothing wrong with rolling your own solution rather than using the SDKs. In fact, I prefer it, because in addition to more lightweight code, you are more likely to understand problems with unexpected behavior because you are working with the native interface.
Here's what you are missing:
Add the query string parameters ... sorted using lexicographic byte ordering
http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
For example, TargetArn should not be before SignatureMethod. They all need to be sorted. There is only one possible correct signature for any given message, so the sort order is critical.
Related
How to verify xml signature (used in SOAP requests) without usage of SignedXml (which is not available in dotnet core)?
I am trying like this, but it gives me false all the time:
public static void CheckSignature(XElement responseXml, MyResponseType response)
{
string originalDigestValue = Convert.ToBase64String(response.Signature.SignedInfo.Reference.FirstOrDefault().DigestValue);
var originalSignatureValue = response.Signature.SignatureValue.Value;
X509DataType certificateData = (X509DataType)response.Signature.KeyInfo.Items[0];
X509Certificate2 certificate = new X509Certificate2((byte[])certificateData.Items[0]);
//for calculating digest value
//responseXml.Descendants(nm + "Signature").SingleOrDefault().Remove();
//var digestValue = Convert.ToBase64String(SHA1.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(responseXml.Document.ToString())));
XNamespace nm = #"http://www.w3.org/2000/09/xmldsig#";
var signedInfoNode = responseXml.Descendants(nm + "SignedInfo").SingleOrDefault();
var signedInfo = signedInfoNode.ToString().Trim();
byte[] signedInfoBytes = Encoding.UTF8.GetBytes(signedInfo);
var hash = SHA1.Create().ComputeHash(signedInfoBytes);
RSA rsa = certificate.GetRSAPublicKey();
try
{
Console.WriteLine("Signed Info: \n" + signedInfo);
Console.WriteLine("Verification: \n" + rsa.VerifyData(signedInfoBytes, originalSignatureValue, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
Console.WriteLine("Verification hash: \n" + rsa.VerifyData(hash, originalSignatureValue, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
}
catch (Exception exc)
{
//
}
}
xmldsig is a very large, very complicated spec. You can try to implement it if you like, the complicated bits are turning the XML document into bytes for doing signing and verification (the canonicalization (or c14n) spec is separate, and large).
SignedXml should be available now with .NET Core 2.0 Preview 1, and upgrading is definitely your easiest bet.
I have been wrapping my head around this problem for some time now. I am to implement a signature check, which is already implemented using c# but we need to implement it on iOS also.
The c# code looks like this.
var signedData = version + "#" + string.Join("#", deltas.Select(s => s.Key + "=" + s.Value));
var signature = Convert.FromBase64String(vertification);
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{ //TODO: Configuration
rsa.FromXmlString("<RSAKeyValue><Modulus>a long text here</Modulus><Exponent>a small text here</Exponent></RSAKeyValue>");
var valid = rsa.VerifyData(Encoding.UTF8.GetBytes(signedData), new SHA256Managed(), signature);
return valid;
}
A little catch is that we can't use any cocoa pods or external libraries.
I'm new at SSDP/UPNP/Sockets and all that jazz. I'm playing around with it a bit and I just want to see what a generic SSDP search on my network will bring up.
Using this SSDP Sniffer app, I get a lot of results so I'm attempting to recreate this.
I'm using the following code, which I've found various versions of, but all the tweaking I do doesn't appear to bring back any results. I pretty much at a loss here and would appreciate any guidance.
thanks!
private const string SSDP_IP = "239.255.255.250";
private const string SSDP_PORT = "1900";
private const string SSDP_QUERY = "M-SEARCH * HTTP/1.1\r\n" +
"Host: " + SSDP_IP + ":" + SSDP_PORT + "\r\n" +
"Man: ssdp:discover\r\n" +
"ST: ssdp:all\r\n";
DataGramSocket socket;
async public void SsdpQueryAsync()
{
var remoteIP = new Windows.Networking.HostName(SSDP_IP);
var reqBuff = Encoding.UTF8.GetBytes(SSDP_QUERY);
socket = new DatagramSocket();
socket.MessageReceived += (sender, args) =>
{
// This is invoked for each device that responds to the query...
Task.Run(() =>
{
// do something useful
});
};
await socket.BindEndpointAsync(null, "");
socket.JoinMulticastGroup(remoteIP);
using (var stream = await socket.GetOutputStreamAsync(remoteIP, SSDP_PORT))
{
await stream.WriteAsync(reqBuff.AsBuffer());
}
await Task.Delay(5000);
}
I'm not familiar with C# or dotnet APIs, but I can see some details wrong with the M-SEARCH message:
MAN header must be enclosed in double quotes, so MAN: "ssdp:discover"\r\n
MX header is missing (required for multicast)
USER-AGENT header is missing
missing an empty line in the end
Header names are supposedly case insensitive, but I'd use upper case just in case...
See the Device Architecture reference pdf for more details
I am building a C#/Winforms application that requires a map (a la Google maps, Bing maps etc.). But I am terribly confused by the ToU (licensing) - non-commercial use etc.
My questions:
What mapping provider would you suggest (preferably free) to embed with a winforms application, for commercial purposes.
What mapping provider would you recommend if the app is "offline" i.e. cannot get tiles from a mapping server.
Google Earth seemed quite promising until I read in the ToU of non-commercial use only clause, would you know if that is waivable through purchase of a license? Any commercial alternatives?
For Windows application, try looking for OpenStreetMap for windows form integration using a browser control
For offline solution you will require map data. One of the most used map data format is Shapefiles which is an ESRI standard, you can download OpenStreetMap data and convert it to Shapefiles and then you can import them in your application. There are open source project which are using Shapefiles for map rendering and other GIS functionalities. namely SharpMap and DotSpatial (Both are .Net implementation)
You can search for Google Earth Pro, also try World Wind from NASA (which is free)
This is excellent, you can check different providers and select one that meets both legal and tech requirenments:
Great Maps for Windows Forms & Presentation
Just download code and check out the demo!
Try This Code Using Web browser control
this code to get direction between two location
System.Text.StringBuilder queryaddress = new System.Text.StringBuilder();
string sStreet = string.Empty;
string sCity = string.Empty;
string sState = string.Empty;
string sPincode = string.Empty;
string sProvider_no = string.Empty;
queryaddress.Append("https://www.google.com/maps/dir/");
if (!string.IsNullOrEmpty(txtprovider_no.Text)) {
sProvider_no = txtprovider_no.Text.Replace(" ", "+");
queryaddress.Append(sProvider_no + "," + "+");
}
if (!string.IsNullOrEmpty(txtState.Text)) {
sState = txtState.Text.Replace(" ", "+");
queryaddress.Append(sState + "," + "+");
}
if (!string.IsNullOrEmpty(txtCity.Text)) {
sCity = txtCity.Text.Replace(" ", "+");
queryaddress.Append(sCity + "," + "+");
}
if (!string.IsNullOrEmpty(txtPincode.Text)) {
sPincode = txtPincode.Text.Replace(" ", "+");
queryaddress.Append(sPincode);
}
queryaddress.Append("/");
sStreet = string.Empty;
sCity = string.Empty;
sState = string.Empty;
sPincode = string.Empty;
if (!string.IsNullOrEmpty(txtlindmark.Text)) {
sStreet = txtlindmark.Text.Replace(" ", "+");
queryaddress.Append(sStreet + "," + "+");
}
if (!string.IsNullOrEmpty(txtclient_city.Text)) {
sCity = txtclient_city.Text.Replace(" ", "+");
queryaddress.Append(sCity + "," + "+");
}
if (!string.IsNullOrEmpty(ttxtclient_city.Text)) {
sPincode = ttxtclient_city.Text.Replace(" ", "+");
queryaddress.Append(sPincode);
}
if (!string.IsNullOrEmpty(txtclient_state.Text)) {
sState = txtclient_state.Text.Replace(" ", "+");
queryaddress.Append(sState + "," + "+");
}
WBR.Navigate(queryaddress.ToString());
This question already has answers here:
Tool to convert java to c# code [closed]
(4 answers)
Closed 6 years ago.
Are there any converters available that converts Java code to C#?
I need to convert the below code into C#
String token = new String("");
URL url1 =new URL( "http", domain, Integer.valueOf(portnum), "/Workplace/setCredentials?op=getUserToken&userId="+username+"&password="+password +"&verify=true");
URLConnection conn1=url1.openConnection();
((HttpURLConnection)conn1).setRequestMethod("POST");
InputStream contentFileUrlStream = conn1.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(contentFileUrlStream));
token=br.readLine();
String encodedAPIToken = URLEncoder.encode(token);
String doubleEncodedAPIToken ="ut=" + encodedAPIToken;//.substring(0, encodedAPIToken.length()-1);
//String doubleEncodedAPIToken ="ut=" + URLEncoder.encode(encodedAPIToken);
//String userToken = "ut=" + URLEncoder.encode(token, "UTF-8"); //URLEncoder.encode(token);
String vsId = "vsId=" + URLEncoder.encode(docId.substring(5, docId.length()), "UTF-8");
url="http://" + domain + ":" + portnum + "/Workplace/getContent?objectStoreName=RMROS&objectType=document&" + vsId + "&" +doubleEncodedAPIToken;
String vsId = "vsId=" + URLEncoder.encode(docId.substring(5, docId.length()), "UTF-8");
url="http://" + domain + ":" + portnum + "/Workplace/getContent?objectStoreName=RMROS&objectType=document&" + vsId + "&" +doubleEncodedAPIToken;
Thanks in advance
The below links might help:
Microsoft Launches Java-to-C# Converter;
Tangible Software Solutions inc..
The code is not very complicated, but if you don't have the time to translate it, you can use a tool like JLCA(Java Language Conversion Assistant 2.0).
You can try VaryCode Domain no longer exists and no valid snapshots in the Wayback Machine
But you used classes like URLEncoder, BufferedReader etc. that are hard to convert to C# without losing some Java-specific features. For this particular part of code it is insignificant but in prospect you can get some unpredicted behavior of the whole converted program.