Advertisment

Signing & enveloping files using .NET 2.0

author-image
CIOL Bureau
Updated On
New Update

For document reading applications, where storage of large, digitally signed documents is not desirable, preference is for detaching digital signatures and storing them separately from a document's sizeable contents. In this article, we look at how this can be done through X.509 certificates using the .NET 2.0 framework. We'll concentrate on features that developers should use to include file signing functionalities within their applications using the new classes in .NET 2.0. You can download the complete source code that's been explained in this article from forums.pcquest.com under the Developer thread.

Advertisment

Support for PKCS#7 in .NET

X.509 certificates represent a bond between a public key and the name of its owner, as certified by trusted third party Certifying Authorities such as iCERT CA. An X.509 certificate follows specifications provided in RFC 2459 and ensures non-repudiation by the message sender. Messages signed and encrypted using X.509 certificates are legally acceptable under India's IT Act 2000.

Cryptographic support for X.509 certificates has been available under Windows operating systems primarily through the CryptoAPIs since Windows NT days. However, Microsoft introduced CAPICOM in 2001 as a wrapper for useful Crypto API functions to reduce the complexity in implementing solutions requiring digital signs and encryption associated with X.509 certificates. Support for public key cryptography in .NET 1.1 required extraction of keys from X.509 certificates in order to complete the process of generating digital signature. Cryptographic capabilities of .NET 1.1 were available in the following namespaces:

Direct Hit!

Applies To: Advanced .NET developers

USP: Implement detached digital

signatures for large docs and files through X.509 certificates

Primary Link: msdn.microsoft.com/ msdnmag/ issues/07/03/NETSecurity

Google Keywords: .NET 2.0 digital certificates, MSDN

Source Code: Developer thread in forums.pcquest.com

Advertisment
  •  System.Security.Cryptography
  •  System.Security.Cryptography.Xml
  •  System.Security.Cryptography.X509-Certificates

However, for rapid application development, developers preferred to use functionalities of signing, enveloped messages, encryption, hashing and certificate store access through CAPICOM. Functionalities which were not available through CAPICOM were supplemented using P/Invoke with CryptoAPI libraries.

However, with the introduction of  in .NET 2.0, necessary classes have been provided to create objects. This allows for the use of certificates and helps create PKCS#7 enveloped or signed messages directly. Developers need not use CAPICOM to extend support for digital signatures within their .NET applications.

Advertisment

 

Signing a file

Certificates in Windows are maintained in Crypto API-managed certificate stores (MY, AddressBook, Root, etc.) that are organized according to the intended use. In .NET 2.0 we can manage the default key store of Windows certificate stores, which is used to store X.509 certificates and certificate chains of trusted signers. The .NET 2.0 classes nicely wrap the key management functionalities of the Crypto API and also provide extra functionalities of their own.

The System.Security.Cryptography. Pkcs namespace provides the SignedCms and CmsSigner classes which expose underlying Windows Crypto API functionalities and help us extend the digital signing capability to our application. Those familiar with CAPICOM may note that the two classes encapsulate similar objects that CAPICOM provides through its SignedData and Signer objects. Let's see how it's done.

Advertisment

STEP 1:

Open the 'My' store.

X509Store store = new X509Store();

Set it to read only property.

Advertisment

store.Open(OpenFlags.ReadOnly);

Construct a Signer Object

First set the content for the signer object. We read the file into a byte array called buffer.

Advertisment

ContentInfo contentInfo = new ContentInfo(buffer);

Use the constructor to initialize a CmsSigner object which stores PKCS#7 signatures along with the signing X.509 certificate in addition to other properties. The SignedCms constructor creates an instance of the SignedCms class by using the specified content information. The SignedCms constructor also takes a bool value that specifies whether the object is for a detached signature. If we keep the value as true, the signature is detached, otherwise it is attached. Remember that this figures as the SignedData object in CAPICOM.

SignedCms signedCms = new SignedCms(contentInfo,true);

Advertisment

Now we create a CmsSigner object that takes the specified certificate in its constructor.

CmsSigner cmsSigner = new CmsSigner( signerCert );

 

STEP 2:

We use the SignedCms.ComputeSignature method to create a signature using the specified CmsSigner. This overloaded method also takes a bool value and if the CmsSigner.Certificate property of the CmsSigner object is not set to a valid certificate, it presents a dialog box where the user can select the appropriate signer's certificate.

Thus, the certificate selection functionalities are also provided by this method and make the task of selection of a valid certificate from the certificate store very easy. Now, specify whether the signer's certificate chain should be included in whole or in part within the CmsSigner.IncludeOption property. We can set the option that controls whether the root and entire chain associated with the signing certificate are included with the created CMS/PKCS #7 message.

cmsSigner.IncludeOption = X509IncludeOption.WholeChain;

Now we create a detached digital signature using the cmsSigner and add the signature to the CMS/PKCS #7 message. We set the value of the silent parameter to False and the CmsSigner.Certificate property of the CmsSigner object to a valid certificate to get the prompts to select a signing certificate.

signedCms.ComputeSignature(cmsSigner, false);

Encode the CMS/PKCS #7 message as a byte array.

byte<> encodedSignedCms = signedCms.Encode();

Now save the byte array into a file with .p7s extension which can be read by the windows machine.

File.WriteAllBytes(OutputFileName, encodedSignedCms);

When you double click on the .p7s file, Windows automatically shows the certificates contained within the signature. You can view the signing certificate information when you double click on the certificate icon.

Verifying signatures

To verify the message, first associate the content of the message with the SignedCms message by constructing a ContentInfo object with the file byte content. Use that to construct a SignedCms object by using, for example, the SignedCms constructor.

Set the second parameter to true to indicate that the message is detached. Decode the encoded SignedCms message to be verified, using the Decode method. Finally, check the signature as previously described.

Now convert the stored signature file into a byte array as follows:

byte<> bufferfile = File.ReadAllBytes(FileBase);

byte<> buffersignature =

File.ReadAllBytes(FileToVerify);

Place signature buffer in a ContentInfo object.

ContentInfo contentInfo = new ContentInfo(bufferfile);

Now Instantiate a SignedCms object with the ContentInfo above. Set the detached content file upon which the signature is based.

SignedCms signedCms = new SignedCms(contentInfo, true);

Decode buffersignature bytes into the pkcs7 object.

signedCms.Decode(buffersignature);

Now check for the detached signature; the CheckSignature function should return a 'true' value.

signedCms.CheckSignature(true);

Display the first signing certificate.

signedCms.Certificates<0>.Display();

The verification method can be viewed in the source code.

 

Enveloping and decrypting a file using digital signature certificates

Enveloping a file involves the use of a message encryption key with a symmetric encryption algorithm such as triple DES. Then the public key extracted from the X.509 certificate of the receiver is used to encrypt the encryption key of the encrypted file. The resulting encrypted file can only be decrypted after the receiver, who alone has access to the X.509 certificate's private keys, decrypts the symmetrical key. So, the sender just needs to have the certificate of the receiver installed in his key store. Typically, a certificate belonging to other individuals, installed in a Windows machine, is found in the 'AddressBook' store. We can search for certificates belonging to the recipient in our 'AddressBook' store:

X509Certificate2Collection certColl = storeAddressBook. Certificates.Find(X509FindType.FindBySubjectName, recipientName, false);

In case certificates of the receiver are found in the machine store by the above function then we choose the first certificate from the returned array, 'certColl<0>.' We can now instantiate an EnvelopedCms object with the required content.

EnvelopedCms envelopedCms =

new EnvelopedCms(contentInfo);

We then set the CmsRecipient object through the following commands:

CmsRecipient recipient1 = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, recipientCert);

The EnvelopedCms.Encrypt(CmsRecipientCollection) method encrypts the contents of the CMS/PKCS #7 message using the information for the specified list of recipients. The method then automatically extracts the public key from the certificate and uses that key to encrypt the symmetric encryption keys.

envelopedCms.Encrypt(recipient1);

The method returns a byte array which can be serialized and stored as an encrypted file on the disk. The file can then be sent to the receiver who would decrypt the message using his private key, which corresponds to the public key used to encrypt the file. The enveloped object can then be encoded as a byte array for serialization and sent to the sender. At the receiver's end the received enveloped object would be decoded. The EnvelopedCms.Decode (System.Byte<>) method decodes the specified enveloped CMS/PKCS #7 message and resets all member variables in the EnvelopedCms object.

Then the EnvelopedCms.Decrypt() method decrypts the contents of decoded enveloped messages. The EnvelopedCms.Decrypt() method searches the current user and computer 'MY stores' for the appropriate certificate and private key. The method searches for private keys in the 'MY' certificate store for the certificate and uses the associated private key to decrypt the message. In case no private keys are found the message is not decrypted and an exception is thrown.

envelopedCms.Decode(encodedEnvelopedCms);

envelopedCms.Decrypt(envelopedCms.RecipientInfos<0>);

The decrypted byte array can then be saved as a file.

Conclusion

.NET 2.0 provides comprehensive support for digital signature certificate based signing and encryption than .NET 1.1. The new classes provided by the pkcs namespace provides comprehensive out of the box functionalities that enables developers to build very secure applications utilizing the PKI technologies more quickly. With the features exposed in the article the developers should be able to integrate rapidly the file signing capabilities with the new classes in .NET 2.0.

Suvir Misra, Indian Revenue Service (Customs and Central Excise)

tech-news