I am trying to perform active card authentication on a PIV compliant smartcard. See Appendix A.2 of this document for more details.
I have the public key from the associated X.509 Certificate. I need to send the card some random data, which it will sign with its private key, then I need 开发者_开发技巧to verify the signature with the public key.
The example in the document I sited notes that the data they send to be signed is "encoded in accordance with the PKCS #1 v1.5 signature padding scheme". How do I encode my random data like that? I thought padding the data was part of the RSA signing process.
// Generate random data
byte[] randomData = new byte[128];
Random random = new Random();
random.NextBytes(randomData);
// Hash the random data
SHA1Managed sha1 = new SHA1Managed();
byte[] hash = sha1.ComputeHash(randomData);
// Send the hash to the Smart Card and get back signed data
byte[] signature = SendToSmartCardForSignature(hash);
// Verify the data and the signature match using the public key
RSACryptoServiceProvider rsa = smartCardCertificate.PublicKey;
bool verified = rsa.VerifyData(randomData, CryptoConfig.MapNameToOID("SHA1"), signature);
// verified is false...why?
The "right" way to do this using the .NET crypto-functionality is to implement your own implementation of System.Security.Cryptography.RSA. The DecryptValue
-method should call the smartcards "raw" RSA private key encryption method. Also, remember to override the KeySize
property.
You can then use RSAPKCS1SignatureFormatter to pad the data and call the smartcard.
Section 9.2 - EMSA-PKCS1-v1_5 of this document describes the encoding method.
I couldn't find anything exposed by the .NET library to do this for me, so I did it manually, since it's pretty easy.
Hash your data as I did in my original code example.
Encode hashed data into ASN.1 value of type DigestInfo - the cited document actually provides the byte arrays needed for this so you don't have to figure it out. I used SHA1, so I just had to insert the following byte array into my hashed data byte array at index 0: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14
The PKCS #1 v1.5 encoded byte array is {0x00, 0x01, PS, 0x00, T}, where T is the DigestInfo byte array from the first step and PS is a byte array of 0xFF's. The length of array PS is up to you. In my case, this array was going to be signed by an RSA-2048 private key, so the array needed to be length 0x100, so I made PS long enough to reach that goal.
Send the encoded byte array to the smart card to sign. The smart card will perform the actual RSA operation with the private key and return the result. The .NET VerifyData function returns true.
精彩评论