Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

signature with SHA256

I have a smartcard and I need to sign a file with this. That is a big problem as I see in stackover.

I couldnt use RSACryptoServiceProvider, bkz it doesnt support RSA-SHA256 alogrithm.

At First I used CAPICOM.dll , like code bellow,

SignedData sed = new SignedData();
sed.Content = "a"; // data to sign
Signer ser = new Signer();
ser.Certificate = cc;
string singnn = sed.Sign(ser, false, CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BASE64);

But there isnt a public key to validate my signature value,, I couldnt get a validate key from capicom.dll.

And after ,

I used X509Certificate2 , and RSACryptoServiceProvider like code below,

        X509Certificate2 certificate = new X509Certificate2();
        // Access Personal (MY) certificate store of current user
        X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        my.Open(OpenFlags.ReadOnly);

        // Find the certificate we'll use to sign            
        RSACryptoServiceProvider csp = null;
        foreach (X509Certificate2 cert in my.Certificates)
        {
            if (cert.Subject.Contains(certSubject))
            {
                // We found it. 
                // Get its associated CSP and private key
                certificate = cert;
                csp = (RSACryptoServiceProvider)cert.PrivateKey;
            }
        }
        if (csp == null)
        {
            throw new Exception("No valid cert was found");
        }

        // Hash the data
        SHA1Managed sha1 = new SHA1Managed();
        UnicodeEncoding encoding = new UnicodeEncoding();
        byte[] data = encoding.GetBytes(text);
        byte[] hash = sha1.ComputeHash(data);

        //byte[] data = Encoding.UTF8.GetBytes(text);
        //HashAlgorithm sha = new SHA256Managed();
        //byte[] hash = sha.TransformFinalBlock(data, 0, data.Length);

        string key = csp.ToXmlString(false);
        // Sign the hash
        csp.PersistKeyInCsp = true;
        byte[] response = csp.SignData(data, CryptoConfig.MapNameToOID("SHA1"));
        string signbase64 = Convert.ToBase64String(response);

It works , but I need to sign with RSA-SHA256 algorithm. When I changw hash algorithm like this

byte[] response = csp.SignData(data, CryptoConfig.MapNameToOID("SHA256"));

I m getting an

error : "unspecified error".

Thats my problem, What is the sollution , or which library should I use ??

Thanks for any advice..

like image 218
Turgay Gençer Avatar asked May 20 '12 11:05

Turgay Gençer


People also ask

Is SHA-256 still secure?

SHA 256 converts data into fixed-length, virtually irreversible hash values, and is mainly used to verify the authenticity data. As we mentioned earlier, no one has been able to crack SHA 256 to date, and it's used in some of the most secure networks in the world.

Should I use SHA-256 for passwords?

While SHA-256 has valid use cases, it is not really meant to be used in hashing passwords. While collisions have not been proven, and unique salts can make rainbow tables ineffective, high-end hardware can still generate billions of SHA-256 hashes every minute.

What algorithm is used to hash the signature?

About Signature Hashing There are three supported algorithms: SHA-1 - The default hashing algorithm applied to each signature item in the configuration. SHA-256 - A more complex, but slower hashing algorithm when compared with SHA-1. Adler-32 - A lighter weight hashing algorithm when compared to SHA-1.


1 Answers

RSACryptoServiceProvider does work with SHA2-based signatures, but you have to invest some effort into it.

When you use a certificate to get your RSACryptoServiceProvider it really matters what's the underlying CryptoAPI provider. By default, when you create a certificate with 'makecert', it's "RSA-FULL" which only supports SHA1 hashes for signature. You need the new "RSA-AES" one that supports SHA2.

So, you can create your certificate with an additional option: -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" (or an equivalent -sy 24) and then your code would look like (in .NET 4.0):

var rsa = signerCertificate.PrivateKey as RSACryptoServiceProvider;
//
byte[] signature = rsa.SignData(data, CryptoConfig.CreateFromName("SHA256"));

If you are unable to change the way your certificate is issued, there is a semi-ligitimate workaround that is based on the fact that by default RSACryptoServiceProvider is created with support for SHA2. So, the following code would also work, but it is a bit uglier: (what this code does is it creates a new RSACryptoServiceProvider and imports the keys from the one we got from the certificate)

var rsa = signerCertificate.PrivateKey as RSACryptoServiceProvider;
// Create a new RSACryptoServiceProvider
RSACryptoServiceProvider rsaClear = new RSACryptoServiceProvider();
// Export RSA parameters from 'rsa' and import them into 'rsaClear'
rsaClear.ImportParameters(rsa.ExportParameters(true));
byte[] signature = rsaClear.SignData(data, CryptoConfig.CreateFromName("SHA256"));

Hope you find this helpful.

like image 62
Vladik Branevich Avatar answered Dec 22 '22 19:12

Vladik Branevich