Coinspot REST API - C# - c#

I'm trying to hit the Coinspot REST API, but I'm getting an error returned. I'm having no trouble talking to Bittrex and Independent Reserve, but Coinspot is a bit different. This is my code:
protected override RESTClient RESTClient { get; } = new RESTClient(new NewtonsoftSerializationAdapter(), new Uri("https://www.coinspot.com.au/api"));
public class postdata
{
public string nonce { get; set; }
}
public string CalculateMD5Hash(string input)
{
//step 1, calculate MD5 hash from input
MD5 md5 = MD5.Create();
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
var sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
/// <summary>
/// Private IR Call: GetAccounts
/// </summary>
/// <returns></returns>
private async Task<List<AccountHolding>> Balances()
{
//https://github.com/geekpete/py-coinspot-api/blob/master/coinspot/coinspot.py
//var nonce = new Date().getTime();
//var postdata = postdata || { };
//postdata.nonce = nonce;
//var stringmessage = JSON.stringify(postdata);
//var signedMessage = new hmac("sha512", self.secret);
//signedMessage.update(stringmessage);
// 'sign': sign,
//'key': self.key
var nonce = APIHelpers.GetNonce();
var postdata = new postdata { nonce = nonce };
var json = JsonConvert.SerializeObject(postdata);
System.Diagnostics.Debug.WriteLine(json);
var sign = APIHelpers.GetHMACSHAHash(ApiSecret, json, APIHelpers.HMACSHAType.NineBit);
//Do we do this?
//The JavaScript samples seem to hash with MD5 afterwards for double encryption?
sign = CalculateMD5Hash(sign);
RESTClient.Headers.Clear();
RESTClient.Headers.Add("sign", sign);
RESTClient.Headers.Add("key", ApiKey);
try
{
var retVal = await RESTClient.PostAsync<string, postdata>(postdata, "/my/balances");
System.Diagnostics.Debug.WriteLine(retVal);
}
catch (Exception ex)
{
}
throw new NotImplementedException();
}
The doco is very scant! I'm stuck.
https://www.coinspot.com.au/api
I don't have the error handy right now, but it was a completely non-descript error with information about what went wrong. It was something like "invalid call". But, I know that it is accepted my posted data to some extent, because if I change the name of the property "nonce" to "noncey", I get a meaningful error back that says "no nonce".

Did you ever manage to get this API working. CoinSpot are not very supportive of this. I can only get 3 of the coins API working which isn't much help

I managed to get it working recently and put together a simple SDK in .NET
https://github.com/QuintinHumphreys/CoinspotAPI

tl:dr It's undocumented but you need to use port 443, I found it by digging through their node SDK.
I was having the same issue, getting the very non-descriptive {status: invalid} response, in my case using Elixir not C#. I got it to work by peeking into their node SDK - my details worked using their SDK so I knew it had to be something I wasn't doing properly (although their documentation is pretty shocking). They use port 443 and as soon as I set that it worked.
I tried 2 things, I'm 90% sure it was the port number but half way through my getting it to work I printed the sha512 sign created by their node sdk and compared it to the one I generating using Cryptex I saw that they were generating the same sha512 signature, but my one was in capital letters while the node one was in lowercase - this may or may not end up mattering but I did use String.downcase() on mine in the end.

Related

How do I sign with HashiCorp Vault

i don't know if this question is very easy and I just didn't figure it out how to sign with HashiCorp-VaultĀ“s Api VaultSharp, but I am despairing.
The entire Documentation with examples can be found here: https://github.com/rajanadar/VaultSharp
Encryption and Decryption works fine. Only Signing is a problem.
Code for Encryption:
public byte[] EncryptData(byte[] data, string keyName)
{
SecretsEngine transitSecretsEngine = new SecretsEngine
{
Type = SecretsEngineType.Transit,
Path = path
};
Client.V1.System.MountSecretBackendAsync(transitSecretsEngine).Wait();
Client.V1.Secrets.Transit.CreateEncryptionKeyAsync(keyName, new CreateKeyRequestOptions()
{
Exportable = true
}, path).Wait();
EncryptRequestOptions encryptOptions = new EncryptRequestOptions
{
Base64EncodedPlainText = Convert.ToBase64String(data),
ConvergentEncryption = true,
};
Secret<EncryptionResponse> encryptionResponse = Client.V1.Secrets.Transit.EncryptAsync(keyName,
encryptOptions, path).Result;
string cipherText = encryptionResponse.Data.CipherText;
return Encoding.Unicode.GetBytes(cipherText);
}
Code for Decryption:
public byte[] DecryptData(string ciphertext, string keyName)
{
DecryptRequestOptions decryptOptions = new DecryptRequestOptions
{
CipherText = ciphertext,
};
Secret<DecryptionResponse> decryptionResponse = Client.V1.Secrets.Transit.DecryptAsync(keyName,
decryptOptions, path).Result;
return Convert.FromBase64String(decryptionResponse.Data.Base64EncodedPlainText);
}
Here is my Code Trial for signing:
public byte[] Sign(byte[] plaintextBytes, string keyName)
{
byte[] hash = ComputeHash(plaintextBytes,SHA256.Create());
GCKMS.SignatureOptions options = new GCKMS.SignatureOptions()
{
Digest = Convert.ToBase64String(hash),
};
Secret<GCKMS.SignatureResponse> result = Client.V1.Secrets.GoogleCloudKMS.SignAsync(keyName,
options).Result;
return Encoding.Unicode.GetBytes(result.Data.Signature);
}
The Error is:
VaultSharp.Core.VaultApiException: {"errors":["no handler for route
'gcpkms/sign/Manuel'"]}
Last but not least my Code for validating the signature:
public bool ValidateSignature(byte[] plaintextByte, byte[] signature, string keyName)
{
GCKMS.VerificationOptions option = new GCKMS.VerificationOptions
{
Digest = Encoding.Unicode.GetString(ComputeHash(plaintextByte)),
Signature = Encoding.Unicode.GetString(signature)
};
Secret<GCKMS.VerificationResponse> result =
Client.V1.Secrets.GoogleCloudKMS.VerifyAsync(keyName, option).Result;
return result.Data.Valid;
}
I am not sure but this could be because I don't use a SecretsEngine with a Path. I could not find any SecretsEngine for GoogleCloudKms.
Useful information:
I generate the Path with Guid.NewGuid().ToString();.
ComputeHash is a self written Function that computes the Hash with a give Algorithm. The
default algorithm is SHA256.
GCMS is a short version of the Namespace VaultSharp.V1.SecretsEngines.GoogleCloudKMS
Any ideas and suggestions are very welcome.
Thanks in advance!
Although Vault offers convenient signature with Transit, the C# wrapper you are using does not support it.
Google KMS does offer signature, but its interface is more complex: you have to do the hash yourself and keep track of the key versions.
What I suggest is that you play a trick on your API wrapper:
Leave your encryption and decryption code as-is
Write to the the Transit backend as if it was a KV store version 1
Get your signature by sending your payload as the input parameter
You still have to base64 your data before sending it to Vault, to avoid binary encoding issues.
So assuming that:
You want to sign the text StackOverflow
The transit back-end is mounted under transit
Your signature key is named my-key
This should get you started:
var value = new Dictionary<string, object> { "input", Convert.ToBase64String(Encoding.UTF8.GetBytes("StackOverflow")) } };
var writtenValue = await vaultClient.V1.Secrets.KeyValue.V1.WriteSecretAsync("sign/my-key", value, "transit");

.NET ECDiffieHellmanCng and BouncyCastle Core compatible agreement

I have to make a Diffie Hellman agreement with a third party that communicates the public keys in the .NET ECDiffieHellmanCng XmlString format. I cannot change their code.
What they send looks like this:
<ECDHKeyValue xmlns="http://www.w3.org/2001/04/xmldsig-more#">
<DomainParameters>
<NamedCurve URN="urn:oid:1.3.132.0.35" />
</DomainParameters>
<PublicKey>
<X Value="11" xsi:type="PrimeFieldElemType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
<Y Value="17" xsi:type="PrimeFieldElemType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</PublicKey>
</ECDHKeyValue>
They generate that using typical .NET Framework code like this:
using (ECDiffieHellmanCng dhKey = new ECDiffieHellmanCng())
{
dhKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
dhKey.HashAlgorithm = CngAlgorithm.Sha256;
Console.WriteLine(dhKey.PublicKey.ToXmlString());
}
They expect to receive my public key in the same format.
They use my public key like this:
ECDiffieHellmanCngPublicKey pbkey = ECDiffieHellmanCngPublicKey.FromXmlString(xmlHere);
I work in .NET core 2.1. Unfortunately the ECDiffieHellmanCng classes and the like are currently not implemented in .NET core.
I thought I could use the BouncyCastle for .NET Core package for this: https://www.nuget.org/packages/BouncyCastle.NetCore/
I would assume these both implement the same standard and they would be compatible.
I know how to do the agreement completely with the bouncy castle, however it's not clear to me how to do that starting with the X and Y values in the xml that come out of the .NET ECDiffieHellmanCng and how to make sure I use compatible parameters.
It's also not clear to me how I get the X and Y values from the bouncy castle public key that I generate to send back to them.
It doesn't help that the bouncy castle for .net api is not exactly the same as the java api and the documentation is limited.
Update 1:
After reading some comments below, it appears indeed that the ECDiffieHellmanCng are partially implemented in .NET Core. Most of the logic works but only ToXmlString and FromXmlString don't work. That's ok, I can work around that.
However I'm now running into a different problem. The curve that the other side uses is oid:1.3.132.0.35.
However when I try to use this in .NET core, even with a basic example like this:
using (ECDiffieHellman dhBob = ECDiffieHellman.Create(ECCurve.CreateFromValue("1.3.132.0.35")))
{
using (ECDiffieHellman dhAlice = ECDiffieHellman.Create(ECCurve.CreateFromValue("1.3.132.0.35")))
{
byte[] b = dhAlice.DeriveKeyMaterial(dhBob.PublicKey);
byte[] b2 = dhBob.DeriveKeyMaterial(dhAlice.PublicKey);
Console.WriteLine(b.SequenceEqual(b2));
}
}
Then I get this error:
Unhandled Exception: System.PlatformNotSupportedException: The specified curve 'ECDSA_P521' or its parameters are not valid for this platform. ---> Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The parameter is incorrect
at System.Security.Cryptography.CngKeyLite.SetProperty(SafeNCryptHandle ncryptHandle, String propertyName, Byte[] value)
at System.Security.Cryptography.CngKeyLite.SetCurveName(SafeNCryptHandle keyHandle, String curveName)
at System.Security.Cryptography.CngKeyLite.GenerateNewExportableKey(String algorithm, String curveName)
at System.Security.Cryptography.ECCngKey.GenerateKey(ECCurve curve)
--- End of inner exception stack trace ---
at System.Security.Cryptography.ECCngKey.GenerateKey(ECCurve curve)
at System.Security.Cryptography.ECDiffieHellman.Create(ECCurve curve)
at TestCore.Program.Main(String[] args)
The error message is not clear to me. Is that curve really not supported? Or is something wrong in the parameters, but then what exactly?
It would surprise me if the curve is not supported because nistP521 curve is supported and according to this IBM document I found online they are the same: https://www.ibm.com/support/knowledgecenter/en/linuxonibm/com.ibm.linux.z.wskc.doc/wskc_r_ecckt.html
Thanks all for your help. Eventually I wrote this code which works on .Net Core 2.1 and which is compatible with the .Net Framework To/FromXmlString:
using (ECDiffieHellmanCng dhBob = new ECDiffieHellmanCng())
{
dhBob.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
dhBob.HashAlgorithm = CngAlgorithm.Sha256;
string xmlBob = ToXmlString(dhBob.PublicKey);
//Console.WriteLine(xmlBob);
using (ECDiffieHellmanCng dhAlice = new ECDiffieHellmanCng())
{
dhAlice.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
dhAlice.HashAlgorithm = CngAlgorithm.Sha256;
ECDiffieHellmanPublicKey keyBob = FromXmlString(xmlBob, dhAlice.KeySize);
byte[] b = dhAlice.DeriveKeyMaterial(keyBob);
string xmlAlice = ToXmlString(dhAlice.PublicKey);
ECDiffieHellmanPublicKey keyAlice = FromXmlString(xmlAlice, dhBob.KeySize);
byte[] b2 = dhBob.DeriveKeyMaterial(keyAlice);
Console.WriteLine(b.SequenceEqual(b2));
}
}
public static string ToXmlString(ECDiffieHellmanPublicKey key)
{
// the regular ToXmlString from ECDiffieHellmanPublicKey throws PlatformNotSupportedException on .net core 2.1
ECParameters parameters = key.ExportParameters();
return string.Format("<ECDHKeyValue xmlns='http://www.w3.org/2001/04/xmldsig-more#'><DomainParameters><NamedCurve URN='urn:oid:{0}' />" +
"</DomainParameters><PublicKey><X Value='{1}' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' />" +
"<Y Value='{2}' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' /></PublicKey></ECDHKeyValue>",
GetOid(parameters.Curve),
new BigInteger(parameters.Q.X.Reverse().ToArray().Concat(new byte[] { 0 }).ToArray()).ToString(System.Globalization.CultureInfo.InvariantCulture), // watch out for big endian - little endian
new BigInteger(parameters.Q.Y.Reverse().ToArray().Concat(new byte[] { 0 }).ToArray()).ToString(System.Globalization.CultureInfo.InvariantCulture));
}
public static ECDiffieHellmanPublicKey FromXmlString(string xml, int keySize)
{
// the regular FromXmlString from ECDiffieHellmanPublicKey throws PlatformNotSupportedException on .net core 2.1
XDocument doc = XDocument.Parse(xml);
XNamespace nsSys = "http://www.w3.org/2001/04/xmldsig-more#";
string xString = doc.Element(nsSys + "ECDHKeyValue").Element(nsSys + "PublicKey").Element(nsSys + "X").Attribute("Value").Value;
string yString = doc.Element(nsSys + "ECDHKeyValue").Element(nsSys + "PublicKey").Element(nsSys + "Y").Attribute("Value").Value;
string curve = doc.Element(nsSys + "ECDHKeyValue").Element(nsSys + "DomainParameters").Element(nsSys + "NamedCurve").Attribute("URN").Value;
curve = curve.Replace("urn:", "").Replace("oid:", "");
byte[] arrayX = BigInteger.Parse(xString, System.Globalization.CultureInfo.InvariantCulture).ToByteArray(false, true); // watch out for big endian - little endian
byte[] arrayY = BigInteger.Parse(yString, System.Globalization.CultureInfo.InvariantCulture).ToByteArray(false, true);
// make sure each part has the correct and same size
int partSize = (int) Math.Ceiling(keySize / 8.0);
ResizeRight(ref arrayX, partSize);
ResizeRight(ref arrayY, partSize);
ECParameters parameters = new ECParameters() { Q = new ECPoint() { X = arrayX, Y = arrayY }, Curve = GetCurveByOid(curve) };
ECDiffieHellman dh = ECDiffieHellman.Create(parameters);
return dh.PublicKey;
}
/// <summary>
/// Resize but pad zeroes to the left instead of to the right like Array.Resize
/// </summary>
public static void ResizeRight(ref byte[] b, int length)
{
if (b.Length == length)
return;
if (b.Length > length)
throw new NotSupportedException();
byte[] newB = new byte[length];
Array.Copy(b, 0, newB, length - b.Length, b.Length);
b = newB;
}
private static ECCurve GetCurveByOid(string oidValue)
{
// there are strange bugs in .net core 2.1 where the createfromvalue doesn't work for the named curves
switch (oidValue)
{
case "1.2.840.10045.3.1.7":
return ECCurve.NamedCurves.nistP256;
case "1.3.132.0.34":
return ECCurve.NamedCurves.nistP384;
case "1.3.132.0.35":
return ECCurve.NamedCurves.nistP521;
default:
return ECCurve.CreateFromValue(oidValue);
}
}
private static string GetOid(ECCurve curve)
{
// there are strange bugs in .net core 2.1 where the value of the oid of the named curves is empty
if (curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP256.Oid.FriendlyName)
return "1.2.840.10045.3.1.7";
else if (curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP384.Oid.FriendlyName)
return "1.3.132.0.34";
else if (curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP521.Oid.FriendlyName)
return "1.3.132.0.35";
else
return curve.Oid.Value;
}
It looks like there's just an equivalence problem with the handling of these OIDs with ECDH (it's turning it into the Windows ECDSA name instead of the Windows ECDH name). You can solve it with something like
private static ECCurve GetCurveByOid(string oidValue)
{
switch (oidValue)
{
case "1.2.840.10045.3.1.7":
return ECCurve.NamedCurves.nistP256;
case "1.3.132.0.34":
return ECCurve.NamedCurves.nistP384;
case "1.3.132.0.35":
return ECCurve.NamedCurves.nistP521;
}
return ECCurve.CreateFromValue(oidValue);
}

"vshost32.exe has stopped working" OR "fatal execution engine error" in Visual Studio

I'm encountering some odd errors in Visual Studio and can't find head or tail. I'm coding some backend in C# which contacts a third party API to retrieve data. The code in question, a single class, is part of a larger solution, but must be the problem as the errors encountered does not occur when not using this class.
Computer setup:
Visual Studio 2013, update 4
Windows 10, Preview Build 10041
Errors encountered
Yesterday the application started behaving weird when debugging it.
The first error I don't remember exactly, but it was something along the lines of "bad" or "corrupted memory".
Without altering the program, I could also encounter a FatalExecutionEngineError exception, which would be thrown immediately after trying to run the program (It didn't make it to the first breakpoint, which was on the first line in the Main entry of the program. Weird!
EDIT: Looks like this:
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 'PathRedacted\whatsfordinner\whatsfordinner\bin\Debug\whatsfordinner.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x613e4379, on thread 0x11ac. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
In the end I rebooted my computer since it was all very strange. Problem solved until today.
Now I can't seem to run the program at all; Upon running the program, vshost32.exe just crashes. I don't get any error messages or anything to hint at where the issue is.
Troubleshooting steps
Rebooted my computer - No change, vshost32.exe crashes upon execution
Outcommented the two lines where the class in question was used - Program runs fine.
Tried starting the program as "Release" rather than "Debug". - Program seems to run fine, although I can't test it to the end. (The class is not entirely done yet, and I don't want to spam the API in question)
Tried running the program on another computer running Windows 7 and Visual Studio 2012. - Program seemed to run fine.
At this point I'm pretty lost. I have little idea as to where the issue might be. The source code unfortunately consists of nearly 200 lines, but as I have no clue, I am posting it all.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Specialized;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
namespace whatsfordinner {
public class eTilbudRetriever {
//Web method names
readonly String Get = "GET";
readonly String Post = "POST";
readonly String Update = "UPDATE";
readonly String Delete = "DELETE";
//Parameter identifiers
readonly String ParamApiKey = "api_key";
readonly String ParamLatitude = "r_lat";
readonly String ParamLongitude = "r_lng";
readonly String ParamRadius = "r_radius";
readonly String ParamLimit = "limit";
readonly String ParamOffset = "offset";
//Parameter values
String Latitude = "57.051188"; //Aalborg coordinates
String Longitude = "9.922371";
String Radius = "800000"; //Radius in meters (800km)
String Limit = "48"; // Results per query
//Custom header identifiers
readonly String HeaderXToken = "X-Token";
readonly String HeaderXSignature = "X-Signature";
//Custom header values
readonly String ContentType = "application/json";
//Web Addresses
readonly String HostAddress = "https://api.etilbudsavis.dk/v2/";
readonly String Sessions = "sessions";
readonly String Stores = "stores";
readonly String Offers = "offers";
readonly String Dealers = "dealers";
//Keys
readonly String ApiKey = "<Redacted>";
readonly String ApiSecret = "<Redacted>";
String XToken; //Same as a Session Token in documentation
String XSignature; //Same as a Session Signature in documentation
public eTilbudRetriever() {
//Create a body consisting of the API key
List<KeyValuePair<String, String>> body = new List<KeyValuePair<String, String>>();
body.Add(new KeyValuePair<String, String>(ParamApiKey, ApiKey));
//Send request to create a new session
String response = SendWebRequest(Post, Sessions, body);
//Get the Session Token from the response
dynamic json = JObject.Parse(response);
XToken = json.token;
//Save the Session Signature as well (SHA256 version of API Secret combined with Session Token)
XSignature = ConvertToSha256(ApiSecret + XToken);
}
public void GetDealersList() {
GetList(Dealers);
}
public void GetStoresList() {
GetList(Stores);
}
public void GetOffersList() {
GetList(Offers);
}
private void GetList(string target) {
List<String> resultSet = new List<String>();
String result;
int offset = 0;
//Add desired parameters as headers for the eTilbudsavisen API
List<KeyValuePair<String, String>> query = new List<KeyValuePair<String, String>>();
query.Add(new KeyValuePair<String, String>(ParamLatitude, Latitude));
query.Add(new KeyValuePair<String, String>(ParamLongitude, Longitude));
query.Add(new KeyValuePair<String, String>(ParamRadius, Radius));
query.Add(new KeyValuePair<String, String>(ParamLimit, Limit));
query.Add(new KeyValuePair<String, String>(ParamOffset, offset.ToString()));
//Retrieve a result through the request
result = SendWebRequest(Get, target, query);
/*
* If result is valid, add it to the set of valid results.
* Keep sending requests and increase the offset to avoid duplicated results
* Stop when returned results are no longer valid
*/
while (!String.IsNullOrEmpty(result)) {
resultSet.Add(result);
offset += Int32.Parse(Limit);
query[query.Count-1] = new KeyValuePair<String, String>(ParamOffset, offset.ToString());
result = SendWebRequest(Get, target, query);
}
}
private String SendWebRequest(String method, String extension, List<KeyValuePair<String, String>> arguments) {
try {
String finalAddress = HostAddress + extension;
//Add query to Address (if applicable)
if (method.Equals(Get)) {
finalAddress += '?';
finalAddress += arguments[0].Key + '=' + arguments[0].Value;
for (int i = 1; i < arguments.Count; i++) {
finalAddress += '&' + arguments[i].Key + '=' + arguments[i].Value;
}
}
//Create request and set mandatory header properties
var request = (HttpWebRequest)WebRequest.Create(finalAddress);
request.Method = method;
request.ContentType = ContentType;
request.Accept = ContentType;
//If a Session Token and Signature are available (= After session create), add as headers
if (!String.IsNullOrEmpty(XToken)) {
request.Headers.Add(HeaderXToken, XToken);
request.Headers.Add(HeaderXSignature, XSignature);
}
//Create JSON string containing the desired body arguments (if applicable)
if (method.Equals(Post)) {
//Write body to API
using (var writer = new StreamWriter(request.GetRequestStream())) {
writer.Write(MakeJsonBody(arguments));
}
}
//get response as a JSON object in string format
var response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream()).ReadToEnd();
} catch (UriFormatException e) {
Console.WriteLine(e.ToString());
return null;
} catch (WebException e) {
Console.WriteLine(e.ToString());
return null;
}
}
private String ConvertToSha256(String text) {
byte[] bytes = Encoding.UTF8.GetBytes(text);
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
string hashString = string.Empty;
foreach (byte x in hash) {
hashString += String.Format("{0:x2}", x);
}
return hashString;
}
private String MakeJsonBody(List<KeyValuePair<String, String>> arguments) {
String json = "{";
foreach (KeyValuePair<String, String> kv in arguments) {
json += "\"" + kv.Key + "\": \"" + kv.Value + "\"";
if (arguments.IndexOf(kv) != arguments.Count() - 1) {
json += ", ";
}
}
json += "}";
return json;
}
}
}
In Main, this is what is executed in relation to the class. The program runs fine when removing these lines from the solution.
eTilbudRetriever retriever = new eTilbudRetriever();
retriever.GetDealersList();
Windows 10, Preview Build 10041
That's the only cue to the possible reason why your program is crashing like this. There are no other ones, your code doesn't do anything dangerous and Newtonsoft.Json has been slammed every possible way by millions of programs. You are using beta versions of both the .NET Framework (v4.6) and the operating system. Thanks on behalf of all Microsoft customers to help debug this new software, your problem is not one that we'll have to troubleshoot. Hopefully, FEEE crashes are exceedingly nasty and hard to debug.
What you are supposed to do is submit a minidump of the crashed process to Microsoft so they can fix the underlying bug. Whatever it might be, there are no cues in your question. Maybe it is the complete rewrite of the x64 jitter (project code name RyuJit). The odds that it has no bugs right now are very slim and such a bug can certainly crash your program like this. That's just a wild guess though.
Microsoft makes these previews available at no cost. Their underlying intention is to get the bugs out before the product ships. Should happen somewhere around the summer. Only real way they can have some confidence that their Support phone lines are not going to get overloaded once they ship the product. The beta updates come fast and furious, there have been 6 CTP versions of .NET 4.6. Quite unprecedented, there usually are no more than 3. At least part of it is the beta for VS2015, lots and lots of new stuff in that release. Which you are not using, that doesn't help either.
Your role in this is one as an unpaid beta-tester. This tends to be rather incompatible with your other role, a programmer that makes a living writing and debugging code. Your code, not somebody else's. When you can't afford to be bogged-down like this then the only sensible thing to do is to unsubscribe from that beta program. Restore your machine to a known-good version of the framework and the operating system. Right now that's .NET 4.5.2 and Windows 8.1

How do I use a Facebook signed_request in .NET?

I'm using Facebook as a login provider for my web application (ASP.NET MVC).
My login works similar to another StackOverflow post How to securely authorize a user via Facebook's Javascript SDK. I also share the user's concerns.
The flow for my login is as Follows:
1. The user presses the login button.
2. The user must accept the app.
3. A javascript callback retrieves the response.
var authResponse = response.authResponse;
Object returned:
{
accessToken: "...",
expiresIn: 1234,
signedRequest: "...",
userID: "123456789"
}
I've heard that I can used the signed_request to validate the user's request, but all the examples online are for PHP. How do I do this in .NET?
To compile Rowan's answer into its final code:
public static string DecodeSignedRequest(string signed_request)
{
try
{
if (signed_request.Contains("."))
{
string[] split = signed_request.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
byte[] appSecretBytes = Encoding.UTF8.GetBytes(app_secret);
System.Security.Cryptography.HMAC hmac = new System.Security.Cryptography.HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
if (expectedHash.SequenceEqual(signature))
{
return data;
}
}
}
catch
{
// error
}
return "";
}
private static string FixBase64String(string str)
{
while (str.Length % 4 != 0)
{
str = str.PadRight(str.Length + 1, '=');
}
return str.Replace("-", "+").Replace("_", "/");
}
Thanks Rowan!
Yes, the signed_request can be used to verify that an incoming login request is genuine. If you're logging in a user with Javascript (via AJAX, for example) you can use the signed_request to ensure that the data isn't false.
According to Parsing the Signed Request, there are 3 major steps, however I'll be a little more specific.
Take the signed_request string and split it into two strings. There is a period character (full stop) which is a delimiter.
The first part of the string (the signature) is a hash of the second part.
The second part contains some information about the user and the request (user ID, timestamp).
The strings are in Base64, but cannot be decoded straight away.
They are Base64-URL-encoded which means that + and / characters have been replaced with URL-friendly - and _ characters. Replace - characters with + and _ characters with /.
The strings may not be fully Base64 padded. Base64 strings should be divisible by 4; pad the strings out as necessary.
Hash the signature using HMAC (SHA256) using your app secret as the key and compare the result to the signature that was provided.
Use the .NET class HMACSHA256.
1. Split and decode
Code
string response = ""; // the signed_request
string[] split = response.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
FixBase64String()
static string FixBase64String(string str)
{
string result = str;
while (result.Length % 4 != 0)
{
result = result.PadRight(result.Length + 1, '=');
}
result = result.Replace("-", "+").Replace("_", "/");
return result;
}
2. Compare the hashes
byte[] appSecretBytes = Encoding.UTF8.GetBytes("my_app_secret_here");
HMAC hmac = new HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataRaw));
bool areEqual = expectedHash.SequenceEqual(signature);
If areEqual is true then you can be sure that the signed request is valid and has not been tampered with (assuming your app secret is secure).
Remember to keep your app secret secure, otherwise malicious users can do bad things.

How to get the facebook signed request in c#

I'm new to Facebook apps. I'm trying to create an MVC 4 application with Facebook Application as my Project Template.
I'm trying to catch the page id on which the page tab is created and I've got it somehow.
My problem here is when someone visits my app, I want to know the page id through which they are viewing the page tab. I've searched a lot where I got to know that I've to use FacebookSignedRequest for this. But this class is not available to me.
Thanks in advance for any help.
If you are simply trying to parse the signed_request parameter from Facebook, you can do so using the following C# code.
This code also verifies the hash using your own app_secret param, to ensure the signed_request originated from Facebook.
public static string DecodeSignedRequest(string signed_request)
{
try
{
if (signed_request.Contains("."))
{
string[] split = signed_request.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
byte[] appSecretBytes = Encoding.UTF8.GetBytes(app_secret);
System.Security.Cryptography.HMAC hmac = new System.Security.Cryptography.HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
if (expectedHash.SequenceEqual(signature))
{
return data;
}
}
}
catch
{
// error
}
return "";
}
private static string FixBase64String(string str)
{
while (str.Length % 4 != 0)
{
str = str.PadRight(str.Length + 1, '=');
}
return str.Replace("-", "+").Replace("_", "/");
}
All I had to do was create a Facebook Client object and call the ParseSignedRequest method with the app secret.
var fb = new FacebookClient();
dynamic signedRequest = fb.ParseSignedRequest(appSecret, Request.Form["signed_request"]);
This returns a Json object which we have to parse using JObject.Parse

Categories