Advertisment

Signing & Enveloping Files using .NET 2.0

author-image
PCQ Bureau
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.

STEP 1:



Open the 'My' store.

Advertisment

X509Store store = new X509Store();

Set it to read only property.

store.Open(OpenFlags.ReadOnly);

Advertisment

Construct a Signer Object

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

array called buffer.

ContentInfo contentInfo = new

ContentInfo(buffer);

Advertisment

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);

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

constructor.

Advertisment

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)

Advertisment