Part-I of this article covered cryptography in the context of encryption. This part continues from where part-I left. It assumes that the reader understands the purpose of encryption, knows about the two types of encryption namely asymmetric encryption and symmetric encryption and the fundamental differences between them. It also assumes that the reader understands encryption-decryption classes in System.Security.Cryptography namespace and the stream based encryption model in. NET framework class library (FCL).
This part discusses developing secured applications using cryptographic solutions like digital envelops, digital signature and digital certificates, with .NET. It uses nine sample visual studio projects (DigitalEnvelopCode.zip) to explain the cryptographic concepts and their support in .NET. It also includes a full-fledged sample for securing .NET remoting application using .NET FCLs cryptographic classes. Part-I of this article is available at
Cryptography in Microsoft.NET Part I: Encryption
Cryptography
In a distributed environment, for a server to trust the data it received from its peer-server there are three issues that must be addressed, namely
- Authenticity: There should be a way for the receiving server to ascertain that the message came from its peer-server only.
- Data Integrity: There should be a way for the receiving server to verify that the message was not altered in the way after it was sent by its peer-server.
- Non-repudiation: There should be a way for the receiving server to protect it from the sender falsely denying the knowledge of the message sender sent.
For a server to send any data confidently to its peer-server there is one more issue that must be addressed in addition to the above, namely
- Privacy: There should be a way for the sending server to ensure that the message will be secure during transit, and except for the intended receiving server no one would be able to read it.
Cryptography, with its encryption and hashing algorithms, solves all these issues.
Hashing Algorithm
Hashing is the focal point of almost all the cryptographic solutions for real world security problems. It is a method of reducing a message (string) of any length to a message (string) of fixed length, called message digest, in such a way that it is computationally infeasible to
- Find two different messages producing same digest (collision)
- Find a message from the given message digest (retracing)
Even when one bit is changed in the input message about half of the bits in the message digest gets changed.
In cryptographys terminology, the mathematical functions that do this are called One-Way Hash Functions or Hash Algorithms. They are also called compression functions, message-digests, and fingerprints. The variable-length message that the hash algorithms take is called pre-image and the fixed-length output string that they produce is called hash value.
Hash algorithms are characterized by the size of the hash value that they produce. Following are some of the popular hash algorithms and the size of the hash value that they produce.
- MD2, MD4 and MD5 128 bits
- SHA and SHA-1 160 bits
MD2, MD4 and MD5 are Message Digest algorithms developed by Ron Rivest of RSA Labs (http://www.rsasecurity.com/) for use in digital signature applications. Of these MD2 is used in 8 bits systems. MD4 and MD5 are used in 32 bit systems. MD5 is slower than MD4, but it is more secure
Secure Hash Algorithm (SHA/SHA-1) was developed by National Institute for Standards and Technology (NIST) (http://www.nist.gov/). SHA-1 is more secure than SHA. Until now no cryptanalysts could find a single collision for SHA-1.
SHA256/384/512
On October 12, 2000, NIST proposed three new secure hash algorithms to succeed SHA-1. These algorithms, SHA-256, SHA-384 and SHA-512, are intended to meet the three security levels of the recently proposed Advanced Encryption Standard, which comes with three key sizes: 128 bits, 192 bits and 256 bits.
Advanced Encryption Standard is implemented in RijndaelManaged class. SHA algorithms are implemented in SHA256Managed, SHA384Managed and SHA512Managed classes in System.Security.Cryptography namespace.
Keyed Hash Algorithm
A keyed hash algorithm is a secret-key dependent one-way hash function. It is very similar to the normal hash algorithms (called free functions) except that, in this the hash value is a function of the pre-image and a secret-key. Only someone who knows the secret-key can verify the hash. Hence it is used to do message integrity checks for messages exchanged between two parties that share a secret-key. It can also be used to authenticate files shared between users or even a single user can use it to verify that viruses did not alter the files.
Since the hash generated by keyed hash algorithm is used as a secured checksum, it is known as message authentication code (MAC), or data authentication code (DAC).
MAC can be created out of a hash algorithm or a block symmetric encryption algorithm. Following are some of the commonly used MACs
- MACs using block encryption algorithm:
MAC with RC5, MAC with CAST-128, MAC with TripleDES and MAC with CBC (AES).
- MACs using hash algorithm:
Keyed-hash MAC (HMAC) with MD5, HMAC with SHA-1, HMAC with RIPEMD-128 and HMAC with RIPEMD-160.
Cryptographic Applications
Although asymmetric encryption, symmetric encryption and hash functions are powerful by themselves, any real world application of them in enterprise is possible only by their combination.
To epitomize their strengths,
- Asymmetric Encryption: Encrypting data with a key (public-key or private-key) of a key-pair makes it computationally infeasible to decrypt without using the complement key in the same key-pair.
- Symmetric Encryption: Encrypting data with a key (secret-key) makes it computationally infeasible to decrypt without using the same key. Also symmetric encryption is faster than asymmetric encryption.
- Hashing: Produces a unique message digest of known fixed size and it is computationally infeasible to get the original data from Message Digest.
Following applications of cryptography uses some or all of the above algorithms.
- Digital Envelope
- Digital Signature
- Digital Certificate
For discussing these applications, assume three users (or servers) named Alice, Bob and Eve. Alice is the sender of the message, Bob is the receiver of the message and Eve is the malicious eavesdropper. Alice has an asymmetric key-pair with a public-key called PBa and a private-key called PRa. Bob also has an asymmetric key pair with public-key called PBb and private-key called PRb. Since PBa and PBb are public-keys every one, Alice, Bob and Eve, knows them.
Digital Envelope
Digital enveloping is an application in which the sender seals the message in such a way that no one other than the intended recipient can open the sealed message. It uses both content-encryption algorithm (symmetric encryption) and key-encryption algorithm (asymmetric encryption).
Alice encrypts the message (Plain) with Bobs public-key (PBb) using some asymmetric algorithm and sends the message to Bob. Since the message is encrypted with a public-key, it can be decrypted with complement key in the same key- pair, which is Bobs private-key (PKb) and only Bob knows it. Even though Eve can eavesdrop the ciphertext he wont know what is the actual message that is being sent.
Since asymmetric encryption is slower to do (asymmetric encryption is about 1000 times slower than symmetric encryption), Alice will create a new secret-key in the beginning, encrypt it with Bobs public-key and send it to Bob. For the exchange of actual messages, Alice will use this secret-key to encrypt the message using symmetric encryption.
Digital Signing
Digital Signing is an application in which the sender signs the message in such a way that anyone can verify that the message is from the sender only and no one modified the message after sender signed it. It uses message-digest functions (hash algorithms) and message-digest encryption algorithm (asymmetric encryption).
Alice creates the message-digest (hash) for the message (Plain) and encrypts it with her private-key (PRa) to create a digital signature (Sign) of the message. She sends the message along with the signature to the receiver, Bob.
When Bob receives the message-signature pair from Alice, he hashes the message (Plain), with the same hash algorithm that Alice used, to generate a hash, and decrypts the Sign with Alices public-key (PBa) to generate another hash. If both the hashes are same then the message came from Alice only and no one did alter the message in the transit.
If Eve attempts to forge Alice, he would capture the message-signature pair send by Alice and send a different message-signature pair to Bob. Eve can either send a modified message with the same signature that Alice sent, or he can modify the message and create a new signature with his private-key. Bob can identify both, as the hash that he creates from the message wont match the hash that he gets by decrypting the signature using Alices public-key (PAa).
Digital Certificates
The above applications have three loopholes, which are plugged by using digital certificates. Following are those loopholes
- How does Bob know Alices public-key and how can he be sure of it?
- How does Bob know which hash algorithms to use (MD5 or SHA) and what are its parameters?
- How does Box know which encryption algorithms to use (DES or RC2, RSA or DSA) and what are the its parameters?
Digital certification is an application in which a certification authority signs a special message m, containing the name of user and the users public-key in such a way that any one can verify that the message was signed by no one other than the centralized authority. The certificate also has the algorithms used and their parameters.
The typical implementation of digital certification involves signature algorithm that both hashes the message and signs the hash with the private-key, rather than using a message-digest function followed by message-digest encryption algorithm.
This whole solution hinges on Bob trusting the certification authority.
For more details on certification please refer
http://www.verisign.com/resources/gd/buildEcommerce/index.html
http://www.msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/digital_certificates.asp
Cryptography in Microsoft .NET
Microsoft.NET has classes that extend the cryptographic services provided by Windows CryptoAPI.
System.Security.Cryptography namespace of .NET Framework Class Library (FCL) provides classes for
- Symmetric Encryption
- Asymmetric Encryption
- Hashing
- Digital Signatures
- Digital Certificates
- XML Signatures
Part-I of this article discussed symmetric and asymmetric encryption. This part discuss hashing and signature. Subsequent parts will discuss digital certificates and XML signatures.
Hash Algorithms
Similar to encryption algorithms, hashing algorithms are also implemented using three level inheritance patterns. The root class HashAlgorithm is abstract and it has an overloaded method to compute hash (message-digest) for any message passed either as a byte array or as a stream.
- Computes the hash value for the specified byte array.
byte[] ComputeHash(byte[]);
- Computes the hash value for the specified Stream.
byte[] ComputeHash(Stream);
- Computes the hash value for the specified region of the specified
byte array. byte[] ComputeHash(byte[], int, int);
Only MD5 and SHA1 are available in Windows CryptoAPI. Hence there only two unmanaged hashing classes in FCL, MD5CryptoServiceProvider and SHA1CryptoServiceProvider. All the other hash functions are implemented in the managed class having the standard Managed suffix as in SHA256Managed. However there are two keyed-hash functions implemented in managed class but without the Managed suffix, HMACSHA1 and MACTripleDES. FCL has a managed class implementation also for SHA1.
Similar to encryption classes, hash algorithms also can be created either using static create method of the root class or using constructors.
Following snippet creates using the static method
HashAlgorithm hash = HashAlgorithm.Create();
Console.Out.WriteLine("Algorithm : {0}",hash.ToString());
Console.Out.WriteLine("Hash Size : {0} bits",hash.HashSize);
SHA1CryptoServiceProvider is the default algorithm for hashing. Hence the output generated is:
Algorithm: System.Security.Cryptography.SHA1CryptoServiceProvider
Hash Size: 160 bits
Following snippet creates using the constructor
SHA512Managed hash = new SHA512Managed();
Console.Out.WriteLine("Algorithm : {0}",hash.ToString());
Console.Out.WriteLine("Hash Size : {0} bits",hash.HashSize);
The output generated is:
Algorithm: System.Security.Cryptography.SHA512Managed
Hash Size: 512 bits
Following snippet shows how to generate a simple hash for a file. For full source code please refer File Hash project in the attached source code.
//Open the Source file
FileStream fsSource = File.OpenRead(_SourceFilepath);
//Create the default hash algorithm
HashAlgorithm hash = HashAlgorithm.Create();
//Compute the hash
hashbyte = hash.ComputeHash(fsSource);
//close the streams
fsSource.Close();
Keyed Hash Algorithm
FCL has managed implementations for two keyed hash algorithms
- MAC using symmetric encryption algorithm (block): MAC with TripleDES in System.Security.Cryptography.MACTripleDES
- MAC using hashing algorithm: HMAC with SHA1 in System.Security.Cryptography.HMACSHA1
Both the classes take the secret-key in the constructor and as a property.
Following snippet shows creating KeyedHashAlgorithm object using static create
KeyedHashAlgorithm hash = KeyedHashAlgorithm.Create();
Console.Out.WriteLine("Algorithm : {0}",hash.ToString());
Console.Out.WriteLine("Hash Size : {0} bits",hash.HashSize);
HMACSHA1 is the default algorithm for keyed hashing. Hence the output generated is:
Algorithm: System.Security.Cryptography.HMACSHA1
Hash Size: 160 bits
Following snippet shows how to generate a keyed hash for a file. For full source code please refer the File Hash project in the attached source code.
//Open the Source file
FileStream fsSource = File.OpenRead(_SourceFilepath);
//Create the default hash algorithm
KeyedHashAlgorithm hash = KeyedHashAlgorithm.Create();
//Set the key
hash.Key = _key;
//Compute the hash
hashbyte = hash.ComputeHash(fsSource);
//close the streams
fsSource.Close();
Digital Envelopes and Signatures
As discussed in the beginning of this article, digital enveloping is done in two phases. In the first phase a secret-key is exchanged using asymmetric encryption (key-encryption algorithm). Secret-key is encrypted with the public-key of the receiver. In the second phase actual messages are exchanged using symmetric key encryption (content-encryption algorithm). Messages are encrypted with the previously exchanged secret-key. In digital signature, the message-digest is signed using the private-key of sender by the sender and verified using the public-key of the sender by receiver.
Since the receiver of a message in digital enveloping can be the sender of another message in digital signing, generally users (or servers) maintain two distinct asymmetric encryption key-pairs. One key-pair is used to encrypt session-keys and the other is used to create digital signatures. They are known as the key exchange key-pair and signature key-pair, respectively.
FCL in Microsoft .NET has two asymmetric encryption classes
- RSA System.Security.Cryptography.RSACryptoServiceProvider
- DSA System.Security.Cryptography.DSACryptoServiceProvider
RSA can be used for both digital enveloping and signature. But DSA, as the name (Digital Signature Algorithm) suggest, is strictly for digital signature. Hence while RSACryptoServiceProvider has two sets of methods, one for encrypting the secret key (key-exchange) and another for signing the message (digital signature), whereas DSACryptoServiceProvider has methods for signing the message only.
Key-Exchange with RSACryptoServiceProvider
RSACryptoServiceProvider has two methods, one for encryption and another for decryption. Both take two parameters, secret-key and a flag that indicates whether RSA should use a special padding while it encrypts, called Optimal Asymmetric Encryption Padding (OAEP). OAEP is not available in all the machines. For more details on OAEP please refer
http://www.rsasecurity.com/rsalabs/faq/7-10.html
byte[] Encrypt(byte[] rgb,bool fOAEP);
byte[] Dencrypt(byte[] rgb,bool fOAEP);
Article Key-Exchange .Net Remoting Sample Explained
This sample works on the same personalities that were used before, Alice and Bob. Alice is the sender and Bob is the receiver of the information. Also it is a one-way communication where only Alice sends message to Bob. Both Alice and Bob are implemented as two separate classes and in two separate assemblies, both aptly named after them. But both the classes, Bob and Alice are in the same namespace Gowri.
Key Install
In a real world application, Bob will have a digital certificate that will carry his public-key and Alice will use that to encrypt the session-key. But for simplification, this sample installs a fixed RSA key-pair in the key container in both Bobs and Alices machine. Key Install is a simple application, which based on the user choice will either install the public-key in Alices machine or install the key-pair (both public-key and private-key) in Bobs machine. To aid Key Install, Alice class exposes a public method called void SetBobPublicKey (RSAParamaters pubkey) and similarly Bob class also exposes a public method called void SetBobKeyPair (RSAParamaters privatekey)
While Bob keeps his key-pair in Bob's Keys key container, Alice keeps Bobs public-key in Bob's Public Keys key container. Both of them use RSA implemented by Microsoft Enhanced Cryptographic Provider v1.0. Both have a helper method, private CspParameters GetCryptoServiceProvider(), to return proper key container.
Text encryption
Text Encryption is a minor modification to the sample of the Part I of this article. It encrypts and decrypts using AES symmetric encryption algorithm.
Bob Service
Bob Service is a console application that exposes Bob as a remotable object. The Remoting configuration is in BobService.exe.config.
Alice Client
Alice Client is a console application that creates Alice class locally and Bob class remotely. The remoting configuration is in AliceClient.exe.config. It uses the metadata (Bob_meta.dll) extracted from Bob assembly using SoapSuds. SoapSuds ia:Bob nowp oa:Bob_meta.dll
Alice
Alice is a class library that implements Gowri.Alice class. Gowri.Alice class has two important methods one for each phase of digital enveloping.
- Envelope: Envelope concatenates AES secret-key with the IV to generate the session-key. Then the session-key is enveloped with the receivers (Bobs) public-key taken from the key container named Bob's Public Keys.
public byte[] Envelope()
- Message: Message encrypts the messages exchanged using secret-key.
public byte[] Message(string message)
Bob
Bob is a class library that implements Gowri.Bob class. Gowri.Bob class has two important methods one for each phase of digital enveloping
- Envelope: Envelope decrypts the envelope using receivers (Bobs) private-key to get the session-key and then splits the session-key to obtain the AES secret-key and the IV.
public void Envelope(byte[] envelope)
- Message: Message decrypts the messages exchanged using secret-key.
public void Message(byte[]message)
How to run it locally?
- Bob Service: Copy BobService.exe, BobService.exe.config, Bob.dll and TextEncryption.dll to a directory and execute BobService.exe
- Alice Client: Copy AliceClient.exe, AliceClient.exe.config, Alice.dll, Bob_meta.dll and TextEncryption.dll to a directory and execute AliceClient.exe
How to run it remotely?
- Bob Service: Copy BobService.exe, BobService.exe.config, Bob.dll and TextEncryption.dll to remote machine and execute BobService.exe
- Alice Client: Copy AliceClient.exe, AliceClient.exe.config, Alice.dll, Bob_meta.dll and TextEncryption.dll and to local machine. Modify the AliceClient.exe.Config file. Change the client URL to read as http://<MachineName>:8080/BobsSerivice, where <MachineName> is the placeholder name of the machine where BobService runs. Execute AliceClient.exe
Make sure that client can reach port 8080 on the remote machine or accordingly change the port number in both AliceClient.exe.config and BobService.exe.config.
How it works?
Following picture shows the phase I
Following picture shows the phase II
Digital Signature with RSACryptoServiceProvider
RSACryptoServiceProvider has two sets of methods for signature, one for signing pre-hashed data and another for signing raw data. Following pair is used for signing pre-hashed data.
[C#]
public byte[] SignHash(byte[] rgbHash, string str);
public bool VerifyHash(byte[] rgbHash, string str,byte[] rgbSignature);
Following function shows how to sign with SignHash. For full source code please refer the Sign project in the attached source code.
public byte[] Sign(string plaintext)
{
//Compute the hash
byte[] hash = Hash(plaintext);
//Computes the signature for the specified hash value by
//encrypting it with the private key
byte[] sign = _rsa.SignHash( hash, CryptoConfig.MapNameToOID(_hashAlgo));
return sign;
}
Following function shows how to verify the digital signature with VerifyHash
public bool Validate(string plaintext, byte[] sign)
{
//Compute the hash
byte[] hash = Hash(plaintext);
//Verfiy the signature
bool test = _rsa.VerifyHash(hash, CryptoConfig.MapNameToOID(_hashAlgo),sign);
return test;
}
Above functions maps the hash algorithms name to ASN.1 OID in the line CryptoConfig.MapNameToOID(_hashAlgo). ASN.1 is Abstract Syntax Notation number One, a standard for representing information exchanged between applications. For more information on ASN.1 please refer
http://asn1.elibel.tm.fr/biblio/asn1-presentation_fichiers/frame.htm.
Following are the OIDs of some of popular hash algorithms,
- MD5 - 1.2.840.113549.2.5
- SHA-1 - 1.3.14.3.2.26
- SHA256 - 2.16.840.1.101.3.4.1
Following pair is used for signing raw data and verifying the same. These functions have two over loaded pairs, one of which takes stream instead byte array and another takes a specified region of the byte array.
public byte[] SignData(byte[] buffer,object halg);
public bool VerifyData(byte[] buffer,object halg,byte[] signature);
Following snippet shows how to use them
//This is the test that is going to be signed
string plaintext = "Oops! I did it again.....";
//Encode the string into unicode bytes
byte[] plaintextbyte = new UnicodeEncoding().GetBytes(plaintext);
//Computes the hash value of the specified byte array using the
//specified hash algorithm, and signs the resulting hash value.
byte[] sign = _rsa.SignData(plaintextbyte,"MD5");
//Verifies the specified signature data by comparing it to the
//signature computed for the specified data.
bool test = _rsa.VerifyData(plaintextbyte,"MD5",sign);
Digital Signature with DSACryptoServiceProvider
DSACryptoServiceProvider has exactly the same set of functions as the RSA Crypto Service Provider. But in addition it also has one more pair to work with digital signature.
//Creates the DSA signature for the specified data.
public override byte[] CreateSignature(byte[] rgbHash);
//Verifies the DSA signature for the specified data.
public override bool VerifySignature(byte[] rgbHash,byte[] rgbSignature);
For sample please refer Sign project in the attached source code.
Comparing RSA and DSA
- RSA is used for both signature and key exchange. DSA is used for signature only.
- RSA signature is 128 bytes long. DSA Signature is 40 bytes long.
- DSA is faster in creating the signature. RSA is faster in verifying the signature.
- DSA is defined in Digital Signature Standards and it uses SHA-1 exclusively for computing message digests. RSA can be used with SHA-1, MD5 etc.,
Formatter and De-formatter classes
System.Security.Cryptography namespace has helper classes for both signature and key-exchange.
While sender uses classes suffixed with Formatter, receiver uses classes suffixed with Deformatter. In case of digital signature Deformatter verifies the signature created by Formatter. In case of digital envelope, Deformatter decrypts the key exchange data encrypted by Formatter.
Signature
Following code snippet shows how to sign with the Formatter class. For full source code please refer the Formatter Deformatter project in the attached source code.
public byte[] Sign(string message)
{
DSASignatureFormatter dsfm = new DSASignatureFormatter(_alg);
dsfm.SetHashAlgorithm(_hashfn);
Byte[] messagebyte = new UnicodeEncoding().GetBytes(message);
Byte[] hash = HashAlgorithm.Create( _hashfn).ComputeHash(messagebyte);
return dsfm.CreateSignature(hash);
}
Following code snippet shows how to verify sign with the Deformatter class.
public bool Verify(string message, byte[] signature)
{
DSASignatureDeformatter dsdfm = new DSASignatureDeformatter(_alg);
dsdfm.SetHashAlgorithm(_hashfn);
Byte[] messagebyte = new UnicodeEncoding().GetBytes(message);
Byte[] hash = HashAlgorithm.Create( _hashfn).ComputeHash(messagebyte);
return dsdfm.VerifySignature(hash,signature);
}
Key-Exchange
RSAOAEP Key Exchange with OAEP Padding, using RSA Labs, PKCS1 standard. (Public Key Crypto System Standard) http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/index.html
Following code snippet shows how to create key exchange envelope with the Formatter class. For full source code please refer the Formatter Deformatter project in the attached source code.
public byte[] CreateEnvelope(string secretkey)
{
RSAPKCS1KeyExchangeFormatter kefm = new RSAPKCS1KeyExchangeFormatter (_alg);
Byte[] secretkeybyte = new UnicodeEncoding().GetBytes(secretkey);
return kefm.CreateKeyExchange(secretkeybyte);
}
Following code snippet shows how to extract the secret key from envelope
public string GetSecretKey(byte[] envelope)
{
RSAPKCS1KeyExchangeDeformatter kedfm = new RSAPKCS1KeyExchangeDeformatter (_alg);
Byte[] secretkeybyte = kedfm.DecryptKeyExchange(envelope);
return new UnicodeEncoding().GetString(secretkeybyte);
}