RSA Security – Digitally Signing the HTTP Header

Recently I worked on a BizTalk project, where we wanted to digitally sign in one of the HTTP header fields when we post the messages to the client’s WCF service.

As part of the requirement, I need to create an HTTP header “signature-token” with a value which is signed. To sign the value we have been provided with a secret which we used to hash the value and pass it as part of the HTTP header “signature-token” as”signature-token: {value:hashedSecrete}”

When I started, there were some communication issue existed between us and the client in terms of terminologies used in RSA security implementation. This may sound trivial for those who have worked at RSA, but not for those who work on it for the first time.

First, there is a difference between digitally signing and encrypting .When they wanted to hash the secret and send the hash in the HTTP header, you could also assume as decrypting the secrete and send the decrypted hash in the HTTP header. But digital signature and encryption are different.

For hash, everyone follows their own way to hash. For example, in the HTTP header you may send the signature-token as follows

signature-token: {value: <<HashedValue>>, created: ‘2013-07-31T09:37:50’, KeyFieldName: ‘<<KeyFieldValue>>’ }

Where

HashedValue is the hashed value following the method I am going to mention in later

KeyFieldName/KeyFieldValue = are the secrete you will use to get the hash

Created: the timestamp when this hash was created. While hashing you will use the timestamp along with the key KeyFieldName/KeyFieldValue.

There is no strict rule to follow while generating hash/digitally signing. As long you have the agreed way between the parties (the sending party who is going to digitally sign following an agreed way – key fields/secrete used in the signature and the receiving party who is going to validate the signature follow the same agreed way  – – key fields/secrete used resolve the hash and validate the signature)

You will be using an RSA private and public keys for the digital signature. In general people would refer to PEM format for the private and public keys.

So for hashing, for digitally signing, as a sender I’ll use an RSA private key along with the secrete to generate the hash and the receiver will use the shared RSA public key  along with the secrete to validate the hash .

But in the .NET world, PEM format is not supported. This is where the BouncyCastle C# library comes handy. There are also some good online tools to convert the PEM RSA key into a XML RSA key format and vice versa.

https://superdry.apphb.com/tools/online-rsa-key-converter (This online tool is also is built on top of BouncyCastle C# library)

Once you have the XML file, you can use the following helper methods to digitally sign using the private XML Key file and another method to verify the signature using RSA public key.

For BizTalk you can use the WCF custom end point behavior where you call these methods.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Net;
using System.Xml;

namespace AshwinPrabhu.Helper.RSASecurity
{
public class RSAXMLKeyHandler
{

public static string RsaSignWithPrivateKeyFromXML(string clearText, string privateXMLKeyPath)
{
string base64signature = string.Empty;
var bytesToSign = Encoding.UTF8.GetBytes(clearText);
XmlDocument xml = new XmlDocument();
//Load the XML key file
xml.Load(privateXMLKeyPath);

string privateKey = xml.OuterXml;
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
rsa.FromXmlString(privateKey);
var signature = rsa.SignData(bytesToSign, new SHA1CryptoServiceProvider());
base64signature = Convert.ToBase64String(signature);
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
return base64signature;
}

public static bool RsaVerifyWithPublicKeyFromXML(string sSignaturePrivateKey, string secret, string publicXMLKeyPath)
{
bool isVerified = false;
string decrypted = string.Empty;
var signatureInByte = Convert.FromBase64String(sSignaturePrivateKey);
byte[] originalData = Encoding.ASCII.GetBytes(secret);
XmlDocument xml = new XmlDocument();
//Load the XML key file
xml.Load(publicXMLKeyPath);

string publicKey = xml.OuterXml;
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
rsa.FromXmlString(publicKey);
isVerified = rsa.VerifyData(originalData, new SHA1CryptoServiceProvider(), signatureInByte);
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
return isVerified;

}
}
}

 

 

Posted in: BizTalk, RSA-Security, Security Leave a comment March 29, 2017

About M.R.ASHWINPRABHU

M.R.ASHWINPRABHU is the founder and CEO of Fortuvis Systems Limited, a consulting company specialised in Microsoft technologies. Ashwin is a highly experienced integration consultant who works with clients to deliver high quality solutions. He works as technical lead developer, application architect and consultant, specializing in custom applications, enterprise application integration (BizTalk), Web services and Windows Azure.

Leave a Reply

Your email address will not be published. Required fields are marked *