PinProtectionHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / PinProtectionHelper.cs / 1 / PinProtectionHelper.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace Microsoft.InfoCards 
{
    using System; 
    using System.IO; 
    using System.Security;
    using System.Security.Cryptography; 

    using Microsoft.InfoCards.Diagnostics;
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace;
 
    //
    // Summary: 
    //  Structure for carrying details of the PKCS5 algorithm used 
    //  to produce a key.
    // 
    internal class PinProtectionHelper
    {
        //
        // Number of PKCS5 iterations to perform when generating the encryption key 
        //
        const int InfoCardPKCS5IterationCount = 1000; 
 
        //
        // Size of InfoCard Salt in bytes 
        //
        public const int SaltSize = 16;

        // 
        // Size of AES block length in bytes
        // 
        const int AESBlockByteLength = 16; 

        // 
        // Size of AES key length in bytes
        //
        const int AESKeyByteLength = 32;
 
        //
        // Version for pin protection scheme 
        // 
        const byte EncryptForPinProtectionVersion = 2;
 
        //
        // PKCS5 implementation
        // NOTE: Need to use Rfc2898DeriveBytes
        // 
        PasswordDeriveBytes m_pkcs5;
 
        byte[]          m_key; 
        RijndaelManaged m_aes = new RijndaelManaged();
 
        //
        // Summary
        //   Generates a key and associated details from a pin using random salt a IV.
        // 
        // Parameters
        //  pin - User passphrase used to generate the key using PKCS5 
        // 
        public PinProtectionHelper( string pin )
        { 
            RNGCryptoServiceProvider prov = new RNGCryptoServiceProvider();
            byte[] salt = new byte[ SaltSize ];
            prov.GetBytes( salt );
 
            //
            // Generate the key using PKCS5 
            // 
            m_pkcs5 = new PasswordDeriveBytes( pin, salt, "SHA256", (int) InfoCardPKCS5IterationCount );
            m_key = m_pkcs5.GetBytes( AESKeyByteLength ); 

            //
            // Setup the AES algorithm
            // 
            m_aes.Padding = PaddingMode.PKCS7;
            m_aes.Mode = CipherMode.CBC; 
            m_aes.BlockSize = AESBlockByteLength * 8; 
            m_aes.KeySize = m_key.Length * 8;
            m_aes.GenerateIV(); 
        }

        //
        // Summary 
        //   Generates a key and associated details from a pin and the serialized parameters.
        // 
        // Parameters 
        //  pin - User passphrase used to generate the key using PKCS5
        //  serializedParameters - Information about how the key was generated 
        //
        // Remarks
        // Reads the serialized form below to constur
        // Version | Salt | Interations | IV | Encrypted Data 
        // 0         1      17            21   37
        // Version    :  1 byte 
        // Salt       : 16 bytes 
        // Iterations :  4 bytes
        // IV         : 16 bytes 
        // EncData    : ?? bytes of unicode encrypted using AES256
        //
        private const int VersionOffset = 0;
        private const int SaltOffset = 1; 
        private const int IterationsOffset = 17;
        private const int IVOffset = 21; 
        private const int EncryptedDataOffset = 37; 

        public PinProtectionHelper( string pin, byte[] serializedParameters ) 
        {
            if( EncryptForPinProtectionVersion != serializedParameters[ 0 ] )
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.ServiceCardDecryptionFailed ) ) ); 
            }
 
            // 
            // Generate the key using PKCS5
            // 
            byte[] salt = new byte[ SaltSize ];
            Array.Copy( serializedParameters, SaltOffset, salt, 0, SaltSize );
            UInt32 iterations = BitConverter.ToUInt32( serializedParameters, IterationsOffset );
 
            m_pkcs5 = new PasswordDeriveBytes( pin, salt, "SHA256", (int) iterations );
            m_key = m_pkcs5.GetBytes( AESKeyByteLength ); 
 
            //
            // Setup the AES algorithm 
            //
            m_aes.Padding = PaddingMode.PKCS7;
            m_aes.Mode = CipherMode.CBC;
            m_aes.BlockSize = AESBlockByteLength * 8; 
            m_aes.KeySize = m_key.Length * 8;
 
            byte[] iv = new byte[ AESBlockByteLength ]; 

            // 
            // Extract the IV from the byte array
            //
            Array.Copy( serializedParameters, IVOffset, iv, 0, iv.Length );
            m_aes.IV = iv; 
        }
 
        // 
        // Summary
        //   Encrypts an array of bytes using the pin protection scheme and AES 
        //
        // Parameters
        //  toEncrypt - bytes to be encrypted
        //  pkcs5 - Information about how the key was generated 
        //
        // Remarks 
        // Encrypt each block to look like: 
        // Version | Salt | Interations | IV | Encrypted Data
        // 0         1      17            21   37 
        // Version    :  1 byte
        // Salt       : 16 bytes
        // Iterations :  4 bytes
        // IV         : 16 bytes 
        // EncData    : 48 bytes of unicode encrypted using AES256
        // The size of the encrypted data can be computed by the following 
        // 
        // CipherText = PlainText(bytes) + BlockSize(bytes) - (PlainText MOD BlockSize )
        // 
        // So, In this case EncData = 32(MasterKeySize) + 16(BlockSize) - ( 32 MOD 16 ) = 48
        //
        // NOTE: Change the EncryotedMasterKeySize method if the logic in this function changes
        // 
        public byte[] EncryptMasterKey( byte[] toEncrypt )
        { 
            byte[] encryptedKey = Encrypt( toEncrypt ); 

            using( MemoryStream digest = new MemoryStream() ) 
            {
                digest.WriteByte( EncryptForPinProtectionVersion );
                digest.Write( m_pkcs5.Salt, 0, m_pkcs5.Salt.Length );
                digest.Write( System.BitConverter.GetBytes( (UInt32) m_pkcs5.IterationCount ), 0, 4 ); 
                digest.Write( m_aes.IV, 0, m_aes.IV.Length );
                digest.Write( encryptedKey, 0, encryptedKey.Length ); 
 
                return digest.ToArray();
            } 
        }


        // 
        // Summary
        // Returns the size of the encrypted master key 
        // 
        // Remarks
        // EncryptedMasterKeySize = 1(Version)+ 16(Salt)+4(Iterations)+16(IV)+48(EncData) 
        // NOTE: the algorithm changes if the algorithm to create the digest in EncryptMasterKey changes
        public static int EncryptedMasterKeySize
        {
            get 
            {
                return ( 1 + SaltSize + 4 + 
                         AESBlockByteLength + 
                         InfoCard.MasterKeySize +
                         AESBlockByteLength - 
                         ( InfoCard.MasterKeySize % AESBlockByteLength  ) );

            }
 
        }
 
        // 
        // Summary
        //   Encrypts an array of bytes using the pin protection scheme and AES 
        //
        // Parameters
        //  toEncrypt - bytes to be encrypted
        //  pkcs5 - Information about how the key was generated 
        //
        // Remarks 
        // 
        public byte[] Encrypt( byte[] toEncrypt )
        { 
            using( ICryptoTransform encryptor = m_aes.CreateEncryptor( m_key, m_aes.IV ) )
            {
                using( MemoryStream digest = new MemoryStream() )
                { 
                    try
                    { 
                        using( CryptoStream cs = new CryptoStream( digest, encryptor, CryptoStreamMode.Write ) ) 
                        {
                            // 
                            // Encrypt the claim value
                            //
                            cs.Write( toEncrypt, 0, toEncrypt.Length );
                            cs.FlushFinalBlock(); 

                            return digest.ToArray(); 
                        } 
                    }
                    catch( CryptographicException e ) 
                    {
                        throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.ServiceCardEncryptionFailed ), e ) );
                    }
                } 
            }
        } 
 
        //
        // Summary 
        //   Encrypts an array of bytes using the pin protection scheme and AES
        //
        // Parameters
        //  toEncrypt - bytes to be encrypted 
        //  pkcs5 - Information about how the key was generated
        // 
        // Remarks 
        // Each block looks like the following:
        // 
        public byte[] DecryptMasterKey( byte[] toDecrypt )
        {
            byte[] encrypted = new byte[ toDecrypt.Length - EncryptedDataOffset ];
            Array.Copy( toDecrypt, EncryptedDataOffset, encrypted, 0, toDecrypt.Length - EncryptedDataOffset ); 

            return Decrypt( encrypted ); 
        } 

        // 
        // Summary
        //   Encrypts an array of bytes using the pin protection scheme and AES
        //
        // Parameters 
        //  encrypted - bytes to be decrypted
        // 
        public byte[] Decrypt( byte[] encrypted ) 
        {
            using( ICryptoTransform decryptor = m_aes.CreateDecryptor( m_key, m_aes.IV ) ) 
            {
                using( MemoryStream digest = new MemoryStream( encrypted ) )
                {
                    try 
                    {
                        using( CryptoStream cs = new CryptoStream( digest, decryptor, CryptoStreamMode.Read ) ) 
                        { 
                            byte[] decrypted = new byte[ encrypted.Length ];
                            int count = cs.Read( decrypted, 0, decrypted.Length ); 

                            //
                            // Truncate to the subarray containing the plain text
                            // 
                            byte[] result = new byte[ count ];
                            Array.Copy( decrypted, result, count ); 
 
                            return result;
                        } 
                    }
                    catch( CryptographicException e )
                    {
                        throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.ServiceCardDecryptionFailed ), e ) ); 
                    }
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK