For any Distributed
Framework or Infrastructure to be successful today it has to have an extensive
support for developing secured solutions. Microsoft .NET is developed from
bottom up with security in mind. It has an eclectic security infrastructure.
Security is a broad
topic and it can be broadly split into
-
Authentication
-
Authorization
-
Privacy or Confidentiality
-
Data Integrity
-
Non-repudiation
While authentication
is about proving one principal's identity to another, authorization is about
controlling access to secured resources based on the identity. Privacy deals
with prevention of eaves dropping of messages sent across the wire. Data
Integrity ensures that the message is not tampered on transit. Non-repudiation
ensures that the author of the message/data cannot disavow responsibility.
Microsoft .NET has
pre-built solutions to all of these in each application domain, viz., ASP. NET,
Web Services, Serviced Component etc. It enables building secured application by
simple configuration as in ASP.NET to full fledged programmable security as in
code access security and Cryptography.
Cryptography
Cryptography is the
art and science of keeping messages secure.
When a message is
transferred from one place to another, it contents are readily available to an
eavesdropper. A simple network-monitoring tool can expose the entire message
sent from one computer to another in a graphical way. For an N-Tier or
distributed application to be secure, all messages sent on the network should be
scrambled in a way that it is computationally impossible for any one to read it.
In cryptography world
the message that needs to be secured is called plaintext or cleartext. The
scrambled form of the message is called ciphertext. The process of converting a
plaintext to ciphertext is called encryption. The process of reconverting the
ciphertext into plaintext is called decryption. Cryptography algorithms
(ciphers) are mathematical functions used for encryption and decryptions.
For cryptography to be
used in practical solutions algorithms used for encryption and decryption should
be made public. This is possible by using a byte stream called Key. For the
algorithm to encipher a plaintext to ciphertext and to decipher it back to
plaintext it needs Key.
Symmetric Key Encryption
Symmetric key
encryption uses same key, called secret key, for both encryption and decryption.
Users exchanging data keep this key to themselves. Message encrypted with a
secret key can be decrypted only with the same secret key.
The algorithm used for
symmetric key encryption is called secret-key algorithm. Since secret-key
algorithms are mostly used for encrypting the content of the message they are
also called content-encryption algorithms.
The major
vulnerability of secret-key algorithm is the need for sharing the secret-key.
One way of solving this is by deriving the same secret key at both ends from a
user supplied text string (password) and the algorithm used for this is called
password-based encryption algorithm. Another solution is to securely send the
secret-key from one end to other end. This is done using another class of
encryption called asymmetric algorithm, which is discussed later.
Strength of the
symmetric key encryption depends on the size of the key used. For the same
algorithm, encrypting using longer key is tougher to break than the one done
using smaller key. Strength of the key is not liner with the length of the key
but doubles with each additional bit.
Following are some of
popular secret-key algorithms and the key size that they use
RC2 - 64 bits
DES - 64 bits
3DES - 192 bits
AES - 256 bits
IDEA - 128 bits
CAST - 128 bits (CAST256 uses 256 bits key)
Algorithm Parameters:
-
Encryption Mode.
There are two types of secret-key ciphers, block ciphers and stream ciphers.
Block Ciphers convert fixed-length block of plain text into cipher text of
the same length. Most of the block ciphers use a block size of 64 bits. When
the message size is more than that of the block size, then the message is
broken into multiple blocks and each block is encrypted separately. There
are different modes in which a Block cipher can encrypt these blocks. Viz.,
Cipher Block Chaining (CBC), Electronic Codebook (ECB) or Cipher Feedback
(CFB). Of these CBC mode is more commonly used. In CBC Mode, each plain text
block is XORed with the previous cipher text block before being encrypted.
Some famous Block ciphers are DES, 3DES, IDEA, SAFER, Blowfish and Skipjack
(used by US National Security Agency).
Stream Ciphers operate on small group of bits, typically applying bitwise
XOR operations to them using the key as a sequence of bits. Some famous
stream ciphers include RC4 and SEAL.
2. Initialization Vector.
Since Block ciphers working on CBC modes XOR each block with the previous
encrypted block, the first block of the message needs a byte array, of same
block size, with which it will be XORed This byte array is called IV or
Initialization Vector.
Following are some block ciphers with their normal block size.
DES - 64 bits
3DES - 64 bits
AES - 128 bits
3. Padding.
Often last block of the message will be smaller that the expected block size
in which case a predetermined string will be repeatedly added to the end of
the block to make it to the expected size. For instance if the block size is
64 bits and the last block has only 40 bits then 24 bits of padding will be
added to it. There were two ways to add the pad, either by adding zeros or
the number of the bytes that needs to be added (in this case it will be 3).
Asymmetric Key Encryption
Asymmetric key
encryption uses different keys for encryption and decryption. These two keys are
mathematically related and they form a key pair. One of these two keys should be
kept private, called private-key, and the other can be made public (it can even
be sent in mail), called public-key. Hence this is also called Public Key
Encryption.
A private key is
typically used for encrypting the message-digest; in such an application
private-key algorithm is called message-digest encryption algorithm. A public
key is typically used for encrypting the secret-key; in such a application
private-key algorithm is called key encryption algorithm.
Popular private-key
algorithms are RSA (invented by Rivest, Shamir and Adlemen) and DSA (Digital
Signature Algorithm). While for an ordinary use of RSA, a key size of 768 can be
used, but for corporate use a key size of 1024 and for extremely valuable
information a key size of 2048 should be used.
Asymmetric key
encryption is much slower than symmetric key encryption and hence they are only
used for key exchanges and digital signatures.
To learn more about
cryptography refer RAS Security site.http://www.rsasecurity.com/rsalabs/faq/3.html
Cryptography in Microsoft .NET
Microsoft.NET has
classes that extend the cryptographic services provided by Windows' CryptoAPI.
System.Security.Cryptography namespace of Common Language runtime provides
classes for
-
Symmetric Key
Encryption
-
Asymmetric Key Encryption
-
Hashing
-
Digital Certificates
-
XML Signatures
Symmetric Key
Encryption and Asymmetric Key Encryption are discussed in this article. Hashing,
Digital Certificates and XML Signatures will be discussed is the subsequent
articles.
Symmetric Key Encryption in .NET:
Symmetric Algorithms
are implemented using a three level inheritance pattern.
The root level abstract class, SymmetricAlgorithm
(System.Security.Cryptography.SymmetricAlgorithm), specifies that it is a
Symmetric algorithm. Intermediate classes are named after particular type of
symmetric algorithm that they implement and are also abstract. The final level
class provides the complete implementation of the Symmetric Algorithms by either
using the Cryptographic Service Providers of the windows' CryptoAPI or by
completely implementing the algorithm in .NET. While the former classes has
"CryptoServiceProvider" suffix the later has "Managed" suffix.
When the concrete
class (RC2CryptoServiceProvider, DESCryptoService Provider,
TrippleDESCryptoService Provider and RijndaelManaged) is instantiated, the
default constructor generates a strong secret-key, initializes the IV, sets
sensible values for padding and mode.
Dim rj As New RijndaelManaged
Console.WriteLine(("AES Mode is : " + rj.Mode))
Console.WriteLine(("AES Padding is : " + rj.Padding))
Console.WriteLine(("AES Key Size : " + rj.KeySize))
This will generate an
output as below
AES Mode is : CBC
AES Padding is : PKCS7
AES Key Size : 256
Asymmetric Key Encryption in .NET:
Similar to Symmetric
key algorithms asymmetric is also implemented using a three level inheritance
pattern.
When the concrete
class ( RSACryptoServiceProvider or DSACryptoService Provider) is instantiated,
the default constructor always generate a random key pair ( strong key values).
Also the asymmetric algorithms can be made to retrieve the existing key pair
from the key container of CSP.
'
Create the CspParameters object
Dim cp As New CspParameters
' Set the
key container name that has the RSA key pair
cp.KeyContainerName = "ApplicationKeyContainer"
' Create
the RSA CSP passing CspParameters object
Dim rsa As New RSACryptoServiceProvider(cp)
Console.WriteLine(("RSA Key Size :" + rsa.KeySize))
Console.WriteLine(("RSA Key is : " + ControlChars.Lf + rsa.ToXmlString(True)))
This will generate an
output as below (edited for brevity)
RSA Key Size :1024
RSA Key is :
<RSAKeyValue>
<Modulus>t9Kue...9bSrE=</Modulus>
<Exponent>AQAB</Exponent>
<P>7AL5v...yAbw==</P>
<Q>x2Qx...A23w==</Q>
<DP>bLO+...qHw==</DP>
<DQ>h6S5...2sQ==</DQ>
<InverseQ>vftt4...iig==</InverseQ>
<D>YBS...d0=</D>
</RSAKeyValue>
CspParameters has the
parameters for identifying a specific Cryptographic Service Provider and a
specific key container for keys.
Dim csp
= New CspParameters
' Set the
key container name that has the RSA key pair
csp.KeyContainerName = "TestMe2"
'Set the
CSP Provider Type PROV_RSA_FULL
csp.ProviderType = 1
'Set the
CSP Provider Name
csp.ProviderName = "Microsoft Base Cryptographic Provider v1.0"
'Create a
DSA cypher and intialaise it with the CspParameters
Dim _cipher As New RSACryptoServiceProvider(csp)
Console.WriteLine(("Cipher :" + _cipher.ToString()))
Console.WriteLine(("Key : " + _cipher.ToXmlString(True)))
Console.WriteLine(("Key Size : " + _cipher.KeySize))
Console.WriteLine(("KeyExchangeAlgorithm : " + _cipher.KeyExchangeAlgorithm))
Console.WriteLine(("SignatureAlgorithm : " + _cipher.SignatureAlgorithm))
This will generate an
output as below
Cipher
:System.Security.Cryptography.RSACryptoServiceProvider
Key :
<RSAKeyValue><Modulus>2FccOXusxV+lstX8frCDvw1z6gpl1VDDnwzoLDVHJ3zWjtyKqc2lObTGDu2a
JHXcTU7RvGodTH1Xdh/woJJbeCYDtEk5zMfF1FOjugEhOnWaCkQm73d4Tr33e4ofn/rlqh983rSJlpSu5L0
CAJKtDZ+WaHQhLsFqtOPQUQL4qH0=</Modulus><Exponent>AQAB</Exponent>
<P>+Sft+l8T0IuaOQL6zMujcJklopLK9pMGeGWyMXJvPqDQwOXh2tBkhuQTSqP7QH8yJ7
AZ03trqZ/h0rFuSSy20Q==</P><Q>3khrfySCAEVHVTTvgXNXvQu1M/xaEuwhxw57j4VXJVANwZ
TCdNtQwprgmoB5q0jLLRRZP/pNCA1LqOy8+2kZ7Q==</Q><DP>+Hm3vS9AhYQTo7OzBrY3Ir24a
K9YNhteIofY87MZ+i1KwnT/jsaw2k1uZ8utcB7pl+bpepzlO960yPgl8lfjYQ==</DP><DQ>x4OpOQ3D
wgps5IYHE+I7tmtz0Z2IG8Pm7YyKS2AbwFoCfubPQ6Q28PWi9AqtKpjEBUpmcY5w5fFJH+6eEetc
YQ==</DQ><InverseQ>5IvEUcDA7UIhx0FU9nY8ZnC/P+GaT/54mR2xe9Hlp1XQsOtToFn1Dzd9Evx
FcTqO6hGntRAPLqNBFle3i5xvRA==</InverseQ><D>j9ib87zADByk2FxgHvzPHOGdCSkQvN2Ot
NqoJXznauIe567MpEsQaWZBqvthWozjhqO54UXNZWaSGQDzxlCKcAefAurJhZJ/HE0Yemm+
9cSqynZcT0UAPRAxzi7KSGuPKTOkn58hyQNtRP7DWHAILuUQ5c75Mu8UXkxxy5bjsgE=</D>
</RSAKeyValue>
Key Size : 1024
KeyExchangeAlgorithm : RSA-PKCS1-KeyEx
SignatureAlgorithm : http://www.w3.org/2000/09/xmldsig#rsa-sha1
Windows 2000
Professional comes with the following CSP.
For more details on CSP
Provider Types refer.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/cryptographic_provider_types.asp
Stream based Programming:
Cryptographic
namespaces uses the same Stream (System.IO.Stream) oriented design that
permeates the .NET framework from networking (System.Net) to XML (System.XML). A
new class called CryptoStream (System.Security.Cryptography.CryptoStream)
derived from System.IO.Stream is used for both encryption and decryption of
data.
Following snippet
shows how to encrypt a string using RijndaelManaged (For full example refer
TextEncrpytion Class).
'Create
a memory stream to which CryptoStream
'will write the cipher text
Dim ciphertextmem As New MemoryStream
'Create a
CryptoStream in Write Mode; initialise with the
'Rijndael's Encryptor ICryptoTransform
Dim crystm As New CryptoStream(ciphertextmem,
_rj.CreateEncryptor(), CryptoStreamMode.Write)
'Encode
the passed plain text string into Unicode byte stream
Dim plaintextbyte As [Byte]()
= New UnicodeEncoding().GetBytes(plaintext)
'Write
the plaintext byte stream to CryptoStream
crystm.Write(plaintextbyte, 0, plaintextbyte.Length)
don() 't
forget to close the stream
crystm.Close()
Extract the ciphertext byte stream and close
the MemoryStream
Dim ciphertextbyte As [Byte]()
= ciphertextmem.ToArray()
ciphertextmem.Close()
Encode the ciphertext byte into Unicode string
Dim ciphertext As String = New UnicodeEncoding().GetString(ciphertextbyte)
Following snippet shows how to
decrypt a string using RijndaelManaged.
Create a memory stream from which CryptoStream will read the cipher text.
Dim ciphertextmem As New MemoryStream(New UnicodeEncoding().GetBytes(ciphertext))
Create a CryptoStream in Read
Mode; initialise withe the Rijndael() 's
Decryptor ICryptoTransform.
Dim crystm As New CryptoStream(ciphertextmem,
_rj.CreateDecryptor(), CryptoStreamMode.Read)
Create a temporary memory
stream to which we will copy the plaintext byte array from CryptoStream.
Dim plaintextmem As New MemoryStream
Do
'Create a
byte array into which we will read the plaintext
'from CryptoStream
Dim buf(100) As [Byte]
'read the
plaintext from CryptoStream
Dim actualbytesread As Integer =
crystm.Read(buf, 0, 100)
'if we
have reached the end of stream quit the loop
If 0
= actualbytesread Then
Exit Do
End If
'copy the plaintext byte array to MemoryStream
plaintextmem.Write(buf, 0, actualbytesread)
Loop While True
'don't forget to close the streams
crystm.Close()
ciphertextmem.Close()
'Extract
the plaintext byte stream and close the MemoryStream
Dim plaintextbyte As [Byte]()
= plaintextmem.ToArray()
plaintextmem.Close()
'Encode
the plaintext byte into Unicode string
Dim plaintext As String = New UnicodeEncoding().GetString(plaintextbyte)
Configuring Cryptography
Cryptographic namespaces uses
the ubiquitous XML based configuration for the algorithms. cryptoNameMapping
provides friendly names for the ciphers ( algorithms), these friendly names can
be used from the Create static methods of the abstract classes
(System.Secyrity.Cryptography.AsymmetricAlgorithm,
System.Secyrity.Cryptography.SymmetricAlgorithm) for creating a specific cipher
class.
For instance the following
configuration file shows two custom symmetric ciphers, MyCryptoClass1 and
MyCryptoClass2 implemented in MyAssembly assembly.
<cryptographySettings>
<cryptoNameMapping>
<cryptoClasses>
<cryptoClass MyCrypto1="MyCryptoClass,
MyAssembly Culture='en',
PublicKeyToken=a5d015c7d5a0b012,Version=1.0.0.0"/>
<cryptoClass MyCrypto2="MyCryptoClass2,
MyAssembly Culture='en',
PublicKeyToken=a5d015c7d5a0b012, Version=1.0.0.0"/>
</cryptoClasses>
<nameEntry name="System.Security.Cryptography.
SymmetricAlgorithm" class="
MyCrypto1"/>
</cryptoNameMapping>
</cryptographySettings>
Of these two classes
MyCryptoClass1 is set as the default class for SymmetricAlgorithm.
'Creates the
default implementation, which is MyCrypto1.
Dim _cipher As SymmetricAlgorithm
= SymmetricAlgorithm.Create()
'Creates
the MyCrypto2 implementation.
Dim _cipher As SymmetricAlgorithm
= SymmetricAlgorithm.Create("MyCrypto2")
By default without any
configuration changes, the default implementation created for SymmetricAlgorithm
is RijndaelManaged and for AsymmetricAlgorithm is RSACryptoServiceProvider.
CryptographySettings should be
inside the <mscorlib> as
<configuration>
<mscorlib>
<cryptographySettings>
..
..
</cryptographySettings>
</mscorlib>
</configuration>
CryptoConfig class
(System.Security.Cryptography.CryptoConfig) is the helper class for accessing
Cryptography Settings.
Dim _cipher As AsymmetricAlgorithm
=CType(CryptoConfig.CreateFromName("System.Security.Cryptography.DSA"),
AsymmetricAlgorithm)Console.WriteLine(("Cipher :" + _cipher.ToString()))
Console.WriteLine(("Key : " + _cipher.ToXmlString(True)))
Console.WriteLine(("Key Size : " + _cipher.KeySize))
Console.WriteLine(("KeyExchangeAlgorithm : " + _cipher.KeyExchangeAlgorithm))
Console.WriteLine(("SignatureAlgorithm : " + _cipher.SignatureAlgorithm))
This will generate an output as
below (edited for brevity)
Cipher : System.Security.Cryptography.DSACryptoServiceProvider
Key : <DSAKeyValue><P>uZP...dyk=</P><Q>+gxc...EM=</Q><G>O+
...R9ws=</G><Y>...k=</Y><J>...w24</J>
<Seed>...TA8=</Seed><PgenCounter>AeA=
</PgenCounter><X>9M...5Bpc=</X></DSAKeyValue>
Key Size : 1024
KeyExchangeAlgorithm :
SignatureAlgorithm: http://www.w3.org/2000/09/xmldsig#dsa-sha1.
DSA does not supports
key-encryption algorithm (KeyExchnage Algorithm) and hence the output has
nothing for "KeyExchangeAlgorithm :". Whereas it supports DSS, hence it hashttp://www.w3.org/2000/09/xmldsig#dsa-sha1 for
"SignatureAlgorithm".