Can someone tell me how I can recreate the hash from WooCommerce webhook to compare with the "X-WC-Webhook-Signature" header hash from the request?
The documentation specifies the hash is generated from the 'payload', but I am unable to generate the same hash.
My API is .NET Core 3.1
First thing i tried:
var secret = "XXX";
var requestHash = Request.Headers["X-WC-Webhook-Signature"];
var generatedHash = "";
Stream byteContent = Request.Body;
byte[] keyByte = encoding.GetBytes(secret);
using(var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(byteContent);
generatedHash = Convert.ToBase64String(hashmessage);
}
if(requestHash == generatedHash)
{
// Succes
}
Second:
using(StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
String json = await reader.ReadToEndAsync();
var generatedHash = "";
byte[] messageBytes = encoding.GetBytes(json);
keyByte = encoding.GetBytes(secret);
using(var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
generatedHash = Convert.ToBase64String(hashmessage);
}
if(requestHash == generatedHash)
{
// Succes
}
}
I had the same problem and here's what I did:
using System.Security.Cryptography;
if (Request.Headers.TryGetValue("X-WC-Webhook-Signature", out var headerValues))
{
XWCWebhookSignature = headerValues.FirstOrDefault();
}
var encoding = new UTF8Encoding();
var key = "yourKeyValue";
var keyBytes = encoding.GetBytes(key);
var hash = new HMACSHA256(keyBytes);
var computedHash = hash.ComputeHash(Request.Body);
var computedHashString = System.Convert.ToBase64String(computedHash);
if (XWCWebhookSignature != computedHashString)
{
return Unauthorized();
}
Update: For this to work you will need to go to Startup.cs file and find "services.Configure" section.
Add options.AllowSynchronousIO = true;
It should look like this:
services.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
Related
I'm trying to establish mtls connection using https://github.com/chkr1011/MQTTnet library in my xamarin.android project. During this process I encountered with such an exception in Init method on calling conResult.Wait(TimeSpan.FromSeconds(60));
{MQTTnet.Exceptions.MqttCommunicationException: Authentication failed, see inner exception. ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> System.Security.Cryptography.CryptographicException: Caught…}
{System.Security.Cryptography.CryptographicException: Caught unhandled exception in MonoBtlsSslCtx.ProcessHandshake. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at Mono.Btls.MonoBtlsSsl.SetPrivateKey (Mono.Btls.…}
This is my code:
public void Init()
{
ILoadCertificate certificateService = DependencyService.Get<ILoadCertificate>();
var cert = certificateService.LoadPemCertificate("certificate", "private_key");
Console.WriteLine(cert.GetRSAPrivateKey());
string clientId = Guid.NewGuid().ToString();
string mqttURI = "";
int mqttPort = 8883;
var factory = new MqttFactory();
var mqttClient = factory.CreateMqttClient();
bool disableServerValidation = true;
var tlsParameters = new MqttClientOptionsBuilderTlsParameters
{
UseTls = true,
Certificates = new[] { new X509Certificate(cert.Export(X509ContentType.Cert)) },
IgnoreCertificateChainErrors = disableServerValidation,
AllowUntrustedCertificates = disableServerValidation,
SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
CertificateValidationHandler = (o) =>
{
return true;
},
};
var connectOptions = new MqttClientOptionsBuilder()
.WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V311)
.WithClientId(clientId)
.WithTcpServer(mqttURI, mqttPort)
.WithCommunicationTimeout(new TimeSpan(0, 2, 30))
.WithCleanSession()
.WithTls(tlsParameters)
.Build();
var conResult = mqttClient.ConnectAsync(connectOptions);
conResult.ContinueWith(r =>
{
Console.WriteLine(r.Result.ResultCode);
Console.WriteLine(r.Exception.StackTrace);
});
conResult.Wait(TimeSpan.FromSeconds(60));
var t = mqttClient.PublishAsync("events/test", "test");
t.ContinueWith(r =>
{
Console.WriteLine(r.Result.PacketIdentifier);
Console.WriteLine(r.Exception.StackTrace);
});
t.Wait();
}
//This methods is used to construct certificate:
public X509Certificate2 GetCertificate(string pemCert, string pemKey)
{
string fileNameCert = Path.Combine(Environment
.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), pemCert);
var pem = File.ReadAllText(fileNameCert);
string fileNameKey = Path.Combine(Environment
.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), pemKey);
var key = File.ReadAllText(fileNameKey);
var keyPair = (AsymmetricCipherKeyPair)new PemReader(new StringReader(key))
.ReadObject();
var cert = (Org.BouncyCastle.X509.X509Certificate)new PemReader(new
StringReader(pem)).ReadObject();
var builder = new Pkcs12StoreBuilder();
builder.SetUseDerEncoding(true);
var store = builder.Build();
var certEntry = new X509CertificateEntry(cert);
store.SetCertificateEntry("", certEntry);
store.SetKeyEntry("", new AsymmetricKeyEntry(keyPair.Private), new[] { certEntry });
byte[] data;
using (var ms = new MemoryStream())
{
store.Save(ms, Array.Empty<char>(), new SecureRandom());
data = ms.ToArray();
}
return new X509Certificate2(data);
}
public byte[] GetBytesFromPEM(string pemString, string type)
{
string header; string footer;
switch (type)
{
case "cert":
header = "-----BEGIN CERTIFICATE-----";
footer = "-----END CERTIFICATE-----";
break;
case "key":
header = "-----BEGIN RSA PRIVATE KEY-----";
footer = "-----END RSA PRIVATE KEY-----";
break;
default:
return null;
}
int start = pemString.IndexOf(header) + header.Length;
int end = pemString.IndexOf(footer, start) - start;
return Convert.FromBase64String(pemString.Substring(start, end));
}
I have several options:
Maybe there is some issue with constructing certificate in GetCertificate method;
There is issue with MqttNet library itself. I suspect that the library does not work with certificates in xamarin.android, because i found such topics: https://github.com/xamarin/xamarin-android/issues/4481, https://github.com/chkr1011/MQTTnet/issues/883.
I tried to construct certificate this way, but xamarin does not support rsa.ImportRSAPrivateKey. I have got: System.PlatformNotSupportedException: Operation is not supported on this platform.
string fileNameCert = Path.Combine(Environment
.GetFolderPath(Environment
.SpecialFolder.LocalApplicationData), certificatePath);
using var publicKey = new X509Certificate2(fileNameCert);
string fileNameKey = Path.Combine(Environment
.GetFolderPath(Environment
.SpecialFolder.LocalApplicationData), privateKeyPath);
using var rsa = RSA.Create();
byte[] keyBuffer =
GetBytesFromPEM(File.ReadAllText(fileNameKey), "key");
int o;
rsa.ImportRSAPrivateKey(keyBuffer, out o);
var keyPair = publicKey.CopyWithPrivateKey(rsa);
return new X509Certificate2(keyPair.Export(X509ContentType.Pkcs12));
I have the followinf code for verification of GKLocalPlayer:
var cert = await GetCertificate(gameCenter.PublicKeyURL);
if (cert.Verify())
{
var rsa = cert.GetRSAPublicKey();
if (rsa != null)
{
var sha256 = new SHA256Managed();
var sig = ConcatSignature(gameCenter.PlayerID, gameCenter.BundleID, gameCenter.TimeStamp, gameCenter.Salt);
var hash = sha256.ComputeHash(sig);
if (rsa.VerifyHash(hash, Convert.FromBase64String(gameCenter.Signature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1))
{
return true;
}
return false;
}
}
private async Task<X509Certificate2> GetCertificate(string url)
{
var client = new HttpClient();
var response = await client.GetAsync(url);
var rawData = await response.Content.ReadAsByteArrayAsync();
return new X509Certificate2(rawData);
}
private byte[] ConcatSignature(string playerId, string bundleId, string timestamp, string salt)
{
var b = Convert.FromBase64String(salt);
var data = new List<byte>();
data.AddRange(Encoding.UTF8.GetBytes(playerId));
data.AddRange(Encoding.UTF8.GetBytes(bundleId));
data.AddRange(ToBigEndian(Convert.ToUInt64(timestamp)));
data.AddRange(Convert.FromBase64String(salt));
return data.ToArray();
}
private static byte[] ToBigEndian(ulong value)
{
var buffer = new byte[8];
for (int i = 0; i < 8; i++)
{
buffer[7 - i] = unchecked((byte)(value & 0xff));
value = value >> 8;
}
return buffer;
}
but this always returns false, when I am trying to verify the accurate GameCenter. I browsed through all the comments, but I cannot find anything posted specifically for .net Core and GKLocalPlayer verification.
Your code worked for me.
Note it will fail if you not testing it on a device (as the data is time sensitive)
I have next error:
"The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256."
When I try download a file from my bucket on Amazon S3. My code is the next:
AmazonS3Config config = new AmazonS3Config();
config.CommunicationProtocol = Protocol.HTTP;
config.RegionEndpoint = Amazon.RegionEndpoint.USEast1;
AmazonS3Client s3Client = new AmazonS3Client("MyAccesKeyAWS", "MyAccesSecretAWS", config);
TransferUtility transfer = new TransferUtility(s3Client);
TransferUtilityDownloadRequest downloader = new TransferUtilityDownloadRequest();
downloader.BucketName = "bucketName";
downloader.FilePath = "MyPath\\To\\Local\\File\\";
downloader.Key = "NameFile.pdf";
transfer.Download(downloader); //<-- here the ERROR:
this generete the next error: The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.
I was reasearch it on google and on some blogs.
some suggest using the property "signature version" to v4.
something like...
config.signatureVersion = "v4";
but my config object, not have this property.
any suggestion?
thank you!!!
Try This Code
AmazonS3Config config = new AmazonS3Config();
string accessKey = WebConfigurationManager.AppSettings["AWSaccessKey"].ToString();
string secretKey = WebConfigurationManager.AppSettings["AWSsecretKey"].ToString();
config.ServiceURL = WebConfigurationManager.AppSettings["AWSServiceURL"].ToString();
string storageContainer = WebConfigurationManager.AppSettings["AWSBucketName"].ToString();
AmazonS3Client client2 = new AmazonS3Client(
accessKey,
secretKey,
config
);
Amazon.S3.AmazonS3 client3 = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretKey, config);
GetObjectRequest request1 = new GetObjectRequest();
request1.BucketName = storageContainer;
request1.WithBucketName(storageContainer);
request1.WithKey(originalfileName);
GetObjectResponse response1 = client3.GetObject(request1);
using (Stream responseStream = response1.ResponseStream)
{
var bytes = ReadStream(responseStream);
var download = new FileContentResult(bytes, "application/pdf");
download.FileDownloadName = response1.Key;
int c = filePath.Split('/').Length;
byte[] fileBytes = download.FileContents;
//return download;
var fileEntry = new ZipEntry(filePath.Split('/')[c - 1].ToString());
zipStream.PutNextEntry(fileEntry);
zipStream.Write(fileBytes, 0, fileBytes.Length);
}
zipStream.Flush();
zipStream.Close();
I am trying to build a SCEP server to support Apple MDM Device Enrollment. This needs to be implemented into our current MDM Service, written in C#.
I have looked into the following for inspiration:
JSCEP, a java library for scep server implementation https://github.com/jscep/jscep
Bouncy Castle (complicated, and not a lot of documentation on the C# side)
Cisco SCEP documentation http://www.cisco.com/c/en/us/support/docs/security-vpn/public-key-infrastructure-pki/116167-technote-scep-00.html
Does anyone know of any solid examples, on creating a C# SCEP server? I haven't been able to find any good documentation for this.
UPDATE
This is what i have by now, it is still not working, but i think the issue lies with the signed pkcs7, but I am not sure what i am missing?
public class ScepModule: NancyModule
{
/// <summary>
/// The _log.
/// </summary>
private readonly ILog log = LogManager.GetLogger(typeof(ScepModule));
/// <summary>
/// Initializes a new instance of the <see cref="ScepModule"/> class.
/// </summary>
/// <param name="cp">
/// The certificate provider.
/// </param>
/// <param name="config">
/// The config.
/// </param>
public ScepModule(MdmConfigDTO config)
: base("/cimdm/scep")
{
this.log.Debug(m => m("Instanciating scep Module."));
this.Get["/"] = result =>
{
var message = Request.Query["message"];
var operation = Request.Query["operation"];
if (operation == "GetCACert")
{
return RespondWithCACert();
}
else if (operation == "GetCACaps")
{
return RespondWithCACaps();
}
return "";
};
this.Post["/"] = result =>
{
var message = Request.Query["message"];
var operation = Request.Query["operation"];
byte[] requestData = null;
using (var binaryReader = new BinaryReader(Request.Body))
{
requestData = binaryReader.ReadBytes((int)Request.Body.Length);
}
var headers = Request.Headers;
foreach (var header in headers)
{
this.log.Debug(m => m("Header: {0}, Value: {1}", header.Key, String.Join(",", header.Value)));
}
var caCert = getSignerCert();
var signingCert = createSigningCert(caCert, requestData, config);
return signingCert;
};
this.log.Debug(m => m("Finished Instanciating scep Module."));
}
private Response RespondWithCACert()
{
var caCert = getSignerCert();
var response = new Response();
response.ContentType = "application/x-x509-ca-cert";
response.Contents = stream =>
{
byte[] data = caCert.Export(X509ContentType.Cert);
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
};
return response;
}
private Response RespondWithCACaps()
{
var response = new Response();
response.ContentType = "text/plain; charset=ISO-8859-1";
//byte[] data = Encoding.UTF8.GetBytes("POSTPKIOperation\nSHA-512\nSHA-256\nSHA-1");
byte[] data = Encoding.UTF8.GetBytes("POSTPKIOperation\nSHA-1");
response.Contents = stream =>
{
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
};
return response;
}
private Response createSigningCert(X509Certificate2 caCert, byte[] data, MdmConfigDTO config)
{
var signedResponse = new SignedCms();
signedResponse.Decode(data);
var caChain = new X509Certificate2Collection(caCert);
signedResponse.CheckSignature(caChain, true);
var attributes = signedResponse
.SignerInfos
.Cast<System.Security.Cryptography.Pkcs.SignerInfo>()
.SelectMany(si => si.SignedAttributes.Cast<CryptographicAttributeObject>());
// Any errors then return null
if (attributes.Any(att => att.Oid.Value.Equals(Oids.Scep.FailInfo)))
{
return null;
}
byte[] msg = DecryptMsg(signedResponse.ContentInfo.Content, caChain);
byte[] certResult = GenerateSelfSignedClientCertificate(msg, caCert, config);
X509Certificate2Collection reqCerts = signedResponse.Certificates;
//Create Enveloped PKCS#7 data
var envelpeDataPkcs7 = createEnvelopedDataPkcs7(certResult);
//Create Signed PKCS#7 data
var signedDataPkcs7 = createSignedDataPkcs7(envelpeDataPkcs7, caCert, attributes);
var response = new Response();
response.ContentType = "application/x-pki-message";
response.WithHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.WithHeader("Pragma", "no-cache");
var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
File.WriteAllBytes(execPath + "\\signedDataPkcs7.p7b", signedDataPkcs7);
File.WriteAllBytes(execPath + "\\envelpeDataPkcs7.p7b", envelpeDataPkcs7);
response.Contents = stream =>
{
stream.Write(signedDataPkcs7, 0, signedDataPkcs7.Length);
stream.Flush();
stream.Close();
};
return response;
}
private byte[] GenerateSelfSignedClientCertificate(byte[] encodedPkcs10, X509Certificate2 caCert, MdmConfigDTO config)
{
var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
File.WriteAllText(execPath + "\\scepPkcs10.csr", "-----BEGIN CERTIFICATE REQUEST-----\n" + Convert.ToBase64String(encodedPkcs10) + "\n-----END CERTIFICATE REQUEST-----");
Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest(encodedPkcs10);
CertificationRequestInfo csrInfo = csr.GetCertificationRequestInfo();
SubjectPublicKeyInfo pki = csrInfo.SubjectPublicKeyInfo;
Asn1Set attributes = csrInfo.Attributes;
//pub key for the signed cert
var publicKey = pki.GetPublicKey();
// Build a Version3 Certificate
DateTime startDate = DateTime.UtcNow.AddMonths(-1);
DateTime expiryDate = startDate.AddYears(10);
BigInteger serialNumber = new BigInteger(32, new Random());
this.log.Debug(m => m("Certificate Signing Request Subject is: {0}", csrInfo.Subject));
CmsSignedDataGenerator cmsGen = new CmsSignedDataGenerator();
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
string signerCN = caCert.GetNameInfo(X509NameType.SimpleName, true);
certGen.SetSubjectDN(new X509Name(String.Format("CN={0}", config.HostName)));
certGen.SetSerialNumber(serialNumber);
certGen.SetIssuerDN(new X509Name(String.Format("CN={0}", signerCN)));
certGen.SetNotBefore(startDate);
certGen.SetNotAfter(expiryDate);
certGen.SetSignatureAlgorithm("SHA1withRSA");
certGen.SetPublicKey(PublicKeyFactory.CreateKey(pki));
AsymmetricCipherKeyPair caPair = DotNetUtilities.GetKeyPair(caCert.PrivateKey);
for(int i=0; i!=attributes.Count; i++)
{
AttributeX509 attr = AttributeX509.GetInstance(attributes[i]);
//process extension request
if (attr.AttrType.Id.Equals(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest.Id))
{
X509Extensions extensions = X509Extensions.GetInstance(attr.AttrValues[0]);
var e = extensions.ExtensionOids.GetEnumerator();
while (e.MoveNext())
{
DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
Org.BouncyCastle.Asn1.X509.X509Extension ext = extensions.GetExtension(oid);
certGen.AddExtension(oid, ext.IsCritical, ext.GetParsedValue());
}
}
}
//certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment));
certGen.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeID.AnyExtendedKeyUsage));
certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0));
Org.BouncyCastle.X509.X509Certificate selfSignedCert = certGen.Generate(caPair.Private);
//Check if the certificate can be verified
selfSignedCert.Verify(caPair.Public);
if (log.IsDebugEnabled)
{
//var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
File.WriteAllBytes(execPath + "\\scepCertificate.pfx", selfSignedCert.GetEncoded());
}
return selfSignedCert.GetEncoded();
}
private byte[] createEnvelopedDataPkcs7(byte[] pkcs7RequestData)
{
var recipient = new CmsRecipient(new X509Certificate2(pkcs7RequestData));
var envelopedContent = new System.Security.Cryptography.Pkcs.ContentInfo(new Oid(Oids.Pkcs7.EncryptedData, "envelopedData"), pkcs7RequestData);
//var envelopedContent = new System.Security.Cryptography.Pkcs.ContentInfo(pkcs7RequestData);
var envelopedMessage = new EnvelopedCms(envelopedContent);
//var envelopedMessage = new EnvelopedCms(Con);
envelopedMessage.Encrypt(recipient);
var encryptedMessageData = envelopedMessage.Encode();
return encryptedMessageData;
}
private byte[] createSignedDataPkcs7(byte[] encryptedMessageData, X509Certificate2 localPrivateKey, IEnumerable<CryptographicAttributeObject> attributes)
{
var senderNonce = attributes
.Single(att => att.Oid.Value.Equals(Oids.Scep.SenderNonce))
.Values[0];
var transactionId = attributes
.Single(att => att.Oid.Value.Equals(Oids.Scep.TransactionId))
.Values[0];
// Create the outer envelope, signed with the local private key
var signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, localPrivateKey);
//{
// DigestAlgorithm = new Oid(Oids.Pkcs.SHA1, "digestAlorithm")
//};
//signer.SignedAttributes.Add(signingTime);
var messageType = new AsnEncodedData(Oids.Scep.MessageType, DerEncoding.EncodePrintableString("3"));
signer.SignedAttributes.Add(messageType);
signer.SignedAttributes.Add(transactionId);
var recipientNonce = new Pkcs9AttributeObject(Oids.Scep.RecipientNonce, DerEncoding.EncodeOctet(senderNonce.RawData));
signer.SignedAttributes.Add(recipientNonce);
var pkiStatus = new AsnEncodedData(Oids.Scep.PkiStatus, DerEncoding.EncodePrintableString("0"));
signer.SignedAttributes.Add(pkiStatus);
var nonceBytes = new byte[16];
RNGCryptoServiceProvider.Create().GetBytes(nonceBytes);
senderNonce = new Pkcs9AttributeObject(Oids.Scep.SenderNonce, DerEncoding.EncodeOctet(nonceBytes));
signer.SignedAttributes.Add(senderNonce);
//var failInfo = new Pkcs9AttributeObject(Oids.Scep.FailInfo, DerEncoding.EncodePrintableString("2"));
//signer.SignedAttributes.Add(failInfo);
// Seems that the oid is not needed for this envelope
var contentInfo = new System.Security.Cryptography.Pkcs.ContentInfo(encryptedMessageData); //new Oid("1.2.840.113549.1.7.1", "data"), encryptedMessageData);
var signedCms = new SignedCms(contentInfo, false);
signedCms.ComputeSignature(signer);
return signedCms.Encode();
}
private X509Certificate2 getSignerCert()
{
string thumbprint = "CACertThumbprint";
thumbprint = Regex.Replace(thumbprint, #"[^\da-zA-z]", string.Empty).ToUpper();
// Get a local private key for sigining the outer envelope
var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.ReadOnly);
var signerCert = certStore
.Certificates
.Find(X509FindType.FindByThumbprint, thumbprint, false)
.Cast<X509Certificate2>()
.Single();
certStore.Close();
return signerCert;
}
// Decrypt the encoded EnvelopedCms message for one of the
// recipients.
public Byte[] DecryptMsg(byte[] encodedEnvelopedCms, X509Certificate2Collection caChain)
{
// Prepare object in which to decode and decrypt.
EnvelopedCms envelopedCms = new EnvelopedCms();
// Decode the message.
envelopedCms.Decode(encodedEnvelopedCms);
// Display the number of recipients
DisplayEnvelopedCms(envelopedCms, false);
// Decrypt the message.
this.log.Debug("Decrypting Data for one recipient ... ");
envelopedCms.Decrypt(envelopedCms.RecipientInfos[0], caChain);
this.log.Debug("Done.");
// The decrypted message occupies the ContentInfo property
// after the Decrypt method is invoked.
return envelopedCms.ContentInfo.Content;
}
// Display the ContentInfo property of an EnvelopedCms object.
private void DisplayEnvelopedCmsContent(String desc,
EnvelopedCms envelopedCms)
{
this.log.Debug(string.Format(desc + " (length {0}): ",
envelopedCms.ContentInfo.Content.Length));
foreach (byte b in envelopedCms.ContentInfo.Content)
{
this.log.Debug(b.ToString() + " ");
}
}
// Display some properties of an EnvelopedCms object.
private void DisplayEnvelopedCms(EnvelopedCms e,
Boolean displayContent)
{
this.log.Debug("\nEnveloped PKCS #7 Message Information:");
this.log.Debug(string.Format(
"\tThe number of recipients for the Enveloped PKCS #7 " +
"is: {0}", e.RecipientInfos.Count));
for (int i = 0; i < e.RecipientInfos.Count; i++)
{
this.log.Debug(string.Format(
"\tRecipient #{0} has type {1}.",
i + 1,
e.RecipientInfos[i].RecipientIdentifier.Type));
}
if (displayContent)
{
DisplayEnvelopedCmsContent("Enveloped PKCS #7 Content", e);
}
}
}
I have a token, a file containing public key and I want to verify the signature.
I tried to verify signature based on this.
However, decodedCrypto and decodedSignature don't match.
Here is my code:
public static string Decode(string token, string key, bool verify)
{
var parts = token.Split('.');
var header = parts[0];
var payload = parts[1];
byte[] crypto = Base64UrlDecode(parts[2]);
var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
var headerData = JObject.Parse(headerJson);
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
var payloadData = JObject.Parse(payloadJson);
if (verify)
{
var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
var keyBytes = Encoding.UTF8.GetBytes(key);
var algorithm = (string)headerData["alg"];
var signature = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);
var decodedCrypto = Convert.ToBase64String(crypto);
var decodedSignature = Convert.ToBase64String(signature);
if (decodedCrypto != decodedSignature)
{
throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
}
}
return payloadData.ToString();
}
I'm sure that the signature of token is valid. I try to verify on https://jwt.io/ and it showed that Signature verified.
So the problem is the algorithm to encode, decode.
Is there anyone can solve this problem? The algorithm is RS256
How about using JwtSecurityTokenHandler?
it could look something like this:
public bool ValidateToken(string token, byte[] secret)
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningToken = new BinarySecretSecurityToken(secret)
};
SecurityToken validatedToken;
try
{
tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
}
catch (Exception)
{
return false;
}
return validatedToken != null;
}
Be aware I haven't tested it but we used a similar implementation in one of the projects
I finally got a solution from my colleague.
For those who have the same problem, try my code:
public static string Decode(string token, string key, bool verify = true)
{
string[] parts = token.Split('.');
string header = parts[0];
string payload = parts[1];
byte[] crypto = Base64UrlDecode(parts[2]);
string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
JObject headerData = JObject.Parse(headerJson);
string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
JObject payloadData = JObject.Parse(payloadJson);
if (verify)
{
var keyBytes = Convert.FromBase64String(key); // your key here
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
SHA256 sha256 = SHA256.Create();
byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + '.' + parts[1]));
RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA256");
if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
throw new ApplicationException(string.Format("Invalid signature"));
}
return payloadData.ToString();
}
It works for me. The algorithm is RS256.
I know this is an old thread but I could have recommended you to use this library instead of writing on your own. It has got some good documentation to get started. Am using it without any issues.
byte[] crypto = Base64UrlDecode(parts[2]);
In this line you are base64 decoding signature part of JWT token, but as I know that part isn't base64 encoded. Please try this code. ( I have commented out unnecessary lines )
public static string Decode(string token, string key, bool verify)
{
var parts = token.Split('.');
var header = parts[0];
var payload = parts[1];
// byte[] crypto = Base64UrlDecode(parts[2]);
var jwtSignature = parts[2];
var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
var headerData = JObject.Parse(headerJson);
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
var payloadData = JObject.Parse(payloadJson);
if (verify)
{
var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
var keyBytes = Encoding.UTF8.GetBytes(key);
var algorithm = (string)headerData["alg"];
var computedJwtSignature = Encoding.UTF8.GetString(HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign));
// var decodedCrypto = Convert.ToBase64String(crypto);
// var decodedSignature = Convert.ToBase64String(signature);
if (jwtSignature != computedJwtSignature)
{
throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
}
}
return payloadData.ToString();
}