Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / RoamingStoreFileUtility.cs / 1 / RoamingStoreFileUtility.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace Microsoft.InfoCards { using System; using System.IO; using System.Security.Cryptography; using System.Text; using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; sealed class RoamingStoreFileUtility { // // Define the constants used to derive the signing and encryption keys. // static readonly byte[] DerivedKeySignatureEntropy = { 0xc4, 0x01, 0x7b, 0xf1, 0x6b, 0xad, 0x2f, 0x42, 0xaf, 0xf4, 0x97, 0x7d, 0x4, 0x68, 0x3, 0xdb }; static readonly byte[] DerivedKeyEncryptionEntropy = { 0xd9, 0x59, 0x7b, 0x26, 0x1e, 0xd8, 0xb3, 0x44, 0x93, 0x23, 0xb3, 0x96, 0x85, 0xde, 0x95, 0xfc }; const Int32 ENCRYPTIONKEYBUFFERSIZE = 32; const Int32 ENCRYPTIONKEYBITLENGTH = ENCRYPTIONKEYBUFFERSIZE * 8; const Int32 ENCRYPTIONIVBUFFERSIZE = 16; const Int32 ENCRYPTIONIVBITLENGTH = ENCRYPTIONIVBUFFERSIZE * 8; const Int32 ITERATIONCOUNT = 1000; const Int32 SHA256_BUFFERSIZE = 256 / 8; public static int SaltLength { get { return ENCRYPTIONIVBUFFERSIZE; } } private RoamingStoreFileUtility( ) { } // // Summary: // Calculates the size of the buffer needed to hold the encrypted data blob // // Arguments: // decryptedLength: The length of the clear text data. // public static int CalculateEncryptedSize( int decryptedLength ) { int encLength = decryptedLength; // // Round to the nearest next block. // encLength += ENCRYPTIONIVBUFFERSIZE - ( encLength % ENCRYPTIONIVBUFFERSIZE ); // // add the prefix info size // encLength += ENCRYPTIONIVBUFFERSIZE + SHA256_BUFFERSIZE; return encLength; } // // Summary: // Calculates the size of the buffer needed to hold the decrypted data // // Arguments: // encryptedLength: The length of the cipher data blob. // public static int CalculateDecryptedSize( int encryptedLength ) { return encryptedLength - ( ENCRYPTIONIVBUFFERSIZE + SHA256_BUFFERSIZE ); } // // Summary: // Decrypts the source buffer using the specified password and salt. // // Arguments: // source: The source data to decrypt. Stream must be at position // 0, and entire stream will be decrypted. // Data written in the following pattern: // IV + Signature + CipherValue // destination: The desination stream that will recieve the raw text data. // passwordString: The string password to use to encrypt the file with. // salt: The generated random value used to derive the keys. // public static void Decrypt( Stream source, Stream destination, string passwordString, byte[] salt ) { // // Genarate the key pair from the password. // byte[] password = Encoding.Unicode.GetBytes( passwordString ); byte[] encKey; byte[] sigKey; try { CreateKeyPair( password, salt, out encKey, out sigKey ); } finally { Array.Clear( password, 0, password.Length ); } try { // // Read the IV. // byte[] iv = new byte[ ENCRYPTIONIVBUFFERSIZE ]; if( iv.Length != source.Read( iv, 0, iv.Length ) ) { throw IDT.ThrowHelperError( new ImportException( SR.GetString( SR.InvalidImportFile ) ) ); } using( RijndaelManaged algorithm = new RijndaelManaged( ) ) { // // Setup our encryption alg for CBC // algorithm.Padding = PaddingMode.PKCS7; algorithm.Mode = CipherMode.CBC; algorithm.BlockSize = iv.Length * 8; algorithm.KeySize = encKey.Length * 8; using( RijndaelManagedTransform decrypTransform = (RijndaelManagedTransform)algorithm.CreateDecryptor( encKey, iv ) ) { using( SHA256Managed sha256 = new SHA256Managed( ) ) { byte[] block = new byte[ decrypTransform.InputBlockSize ]; byte[] finalBlock = null; byte[] decryptBlock = new byte[ decrypTransform.OutputBlockSize ]; byte[] signature = null; byte[] expectedSignature = new byte[ sha256.HashSize / 8 ]; using( MemoryStream digest = new MemoryStream( new byte[ iv.Length + encKey.Length + decrypTransform.OutputBlockSize ] ) ) { // // Read the expected signature from the file. // if( expectedSignature.Length != source.Read( expectedSignature, 0, expectedSignature.Length ) ) { throw IDT.ThrowHelperError( new ImportException( SR.GetString( SR.InvalidImportFile ) ) ); } // // Capture the iv and derived sig key into the // digest. // digest.Write( iv, 0, iv.Length ); digest.Write( sigKey, 0, sigKey.Length ); int bytesRead = 0; int bytesTansformed = 0; while( source.Position < source.Length - block.Length ) { try { bytesRead = source.Read( block, 0, block.Length ); bytesTansformed = decrypTransform.TransformBlock( block, 0, bytesRead, decryptBlock, 0 ); // // Bytes transformed will be 0 the first time throught, // and the second time through will return the first times data. // and so on, until we get to the final block. // if( bytesTansformed > 0 ) { // // Write the clear text to the destination. // destination.Write( decryptBlock, 0, bytesTansformed ); } } finally { Array.Clear( decryptBlock, 0, decryptBlock.Length ); Array.Clear( block, 0, block.Length ); } } bytesRead = source.Read( block, 0, block.Length ); finalBlock = decrypTransform.TransformFinalBlock( block, 0, bytesRead ); destination.Write( finalBlock, 0, finalBlock.Length ); // // Append the final block of raw text to the digest. // digest.Write( finalBlock, // In case finalBlock is > decrypTransform.OutputBlockSize // the following offset will make sure only decrypTransform.OutputBlockSize // get written to the digest. finalBlock.Length - decrypTransform.OutputBlockSize, decrypTransform.OutputBlockSize ); // // Generate the signature from the computed digest. // digest.Flush( ); digest.Seek( 0, SeekOrigin.Begin ); signature = sha256.ComputeHash( digest ); // // Compare the signatures. // if( !CompareSignature( signature, expectedSignature ) ) { throw IDT.ThrowHelperError( new ImportException( SR.GetString( SR.InvalidImportFile ) ) ); } } } } } } finally { Array.Clear( encKey, 0, encKey.Length ); Array.Clear( sigKey, 0, sigKey.Length ); } } // // Summary: // Encrypts the source buffer using the specified password. // // Arguments: // source: The source data to encrypt. Stream must be at position // 0, and entire stream will be encrypted. // destination: The desination stream that will recieve the encrypted data. // Data written in the following pattern: // IV + Signature + CipherValue // passwordString: The string password to use to encrypt the file with. // salt: The generated random value that must be persisted for decryption. // public static void Encrypt( Stream source, Stream destination, string passwordString, out byte[] salt ) { RandomNumberGenerator generator = new RNGCryptoServiceProvider( ); salt = new byte[ ENCRYPTIONIVBUFFERSIZE ]; // // Rand up the salt we need for pksc5 // generator.GetBytes( salt ); byte[] password = Encoding.Unicode.GetBytes( passwordString ); // // using pkcs5 and sha256, generate a key pair for encryption and signing. // byte[] encKey; byte[] sigKey; try { CreateKeyPair( password, salt, out encKey, out sigKey ); } finally { Array.Clear( password, 0, password.Length ); } try { byte[] iv = new byte[ ENCRYPTIONIVBUFFERSIZE ]; generator.GetBytes( iv ); using( RijndaelManaged algorithm = new RijndaelManaged( ) ) { algorithm.Padding = PaddingMode.PKCS7; algorithm.Mode = CipherMode.CBC; algorithm.BlockSize = iv.Length * 8; algorithm.KeySize = encKey.Length * 8; using( RijndaelManagedTransform encrTransform = (RijndaelManagedTransform)algorithm.CreateEncryptor( encKey, iv ) ) { using( SHA256Managed sha256 = new SHA256Managed( ) ) { byte[] block = new byte[ encrTransform.InputBlockSize ]; byte[] finalBlock = null; byte[] encBlock = new byte[ encrTransform.OutputBlockSize ]; byte[] signature = null; byte[] prefixBuffer = new byte[ iv.Length + ( sha256.HashSize / 8 ) ]; using( MemoryStream digest = new MemoryStream( new byte[ iv.Length + sigKey.Length + encrTransform.InputBlockSize ] ) ) { // // Prepend IV and sigKey // digest.Write( iv, 0, iv.Length ); digest.Write( sigKey, 0, sigKey.Length ); try { // // Write the empty prefixBuffer buffer to seek the stream to the point where // we write the encrypted data. We will seek back once we have captured // the final block of data. // destination.Write( prefixBuffer, 0, prefixBuffer.Length ); // // Encrypt the entire input. // int bytesRead = 0; int targetBytes = 0; // // Until there is only the final block left... // while( source.Position < source.Length - block.Length ) { // // read the block of source to process. // bytesRead = source.Read( block, 0, block.Length ); try { // // decide if this is the final block // targetBytes = encrTransform.TransformBlock( block, 0, block.Length, encBlock, 0 ); destination.Write( encBlock, 0, targetBytes ); } finally { Array.Clear( block, 0, block.Length ); Array.Clear( encBlock, 0, encBlock.Length ); } } // // Read the last block, could be an incomplete block. // bytesRead = source.Read( block, 0, block.Length ); if( bytesRead != block.Length ) { // // Does not line up, lets read last 0x20 bytes from the source for digest. // byte[ ] lastClearBlock = new byte[ block.Length ]; source.Seek( source.Length - block.Length, SeekOrigin.Begin ); int lastClearByteCount = source.Read( lastClearBlock, 0, lastClearBlock.Length ); IDT.Assert( lastClearByteCount == lastClearBlock.Length && lastClearBlock.Length == block.Length, "Should have read exactly 0x20 bytes" ); digest.Write( lastClearBlock, 0, lastClearBlock.Length ); } else { // // The last block is the right size we want, // simply write it to the digest. // digest.Write( block, 0, block.Length ); } finalBlock = encrTransform.TransformFinalBlock( block, 0, bytesRead ); destination.Write( finalBlock, 0, finalBlock.Length ); destination.Flush( ); digest.Flush( ); // // Reset the digest stream now that its full and hash it // digest.Seek( 0, SeekOrigin.Begin ); signature = sha256.ComputeHash( digest ); // // Populate the prefix buffer with the iv and hashed digest // Array.Copy( iv, 0, prefixBuffer, 0, iv.Length ); Array.Copy( signature, 0, prefixBuffer, iv.Length, signature.Length ); // // Seek back to the start, and write the digest value. // destination.Seek( 0, SeekOrigin.Begin ); destination.Write( prefixBuffer, 0, prefixBuffer.Length ); // // Return to the end of the stream. // destination.Flush( ); destination.Seek( 0, SeekOrigin.End ); } finally { // // ensure that the last of the clear text data or keys we have is clear. // Array.Clear( block, 0, block.Length ); Array.Clear( encBlock, 0, encBlock.Length ); Array.Clear( prefixBuffer, 0, prefixBuffer.Length ); if( null != finalBlock ) { Array.Clear( finalBlock, 0, finalBlock.Length ); } } } } } } } finally { Array.Clear( encKey, 0, encKey.Length ); Array.Clear( sigKey, 0, sigKey.Length ); } } // // Summary: // Creates a KeyPair for use in encryption/decryption and signatures // // Summary: // password: The password to use as the basis of the key // salt: The salt used in the PKCS5 impl. // encryptionKey: The key to be used as the symmetric encryption key // signatureKey: The key to be used as part of the digest info. // static void CreateKeyPair( byte[] password, byte[] salt, out byte[] encryptionKey, out byte[] signatureKey ) { byte[] pkcs5Raw = DoPkcs5( password, salt ); using( SHA256Managed sha256 = new SHA256Managed( ) ) { byte[] encKeyBase = new byte[ ENCRYPTIONKEYBUFFERSIZE + DerivedKeyEncryptionEntropy.Length ]; byte[] sigKeyBase = new byte[ ENCRYPTIONKEYBUFFERSIZE + DerivedKeySignatureEntropy.Length ]; Array.Copy( DerivedKeyEncryptionEntropy, 0, encKeyBase, 0, DerivedKeyEncryptionEntropy.Length ); Array.Copy( DerivedKeySignatureEntropy, 0, sigKeyBase, 0, DerivedKeySignatureEntropy.Length ); Array.Copy( pkcs5Raw, 0, encKeyBase, DerivedKeyEncryptionEntropy.Length, ENCRYPTIONKEYBUFFERSIZE ); Array.Copy( pkcs5Raw, 0, sigKeyBase, DerivedKeySignatureEntropy.Length, ENCRYPTIONKEYBUFFERSIZE ); encryptionKey = sha256.ComputeHash( encKeyBase ); signatureKey = sha256.ComputeHash( sigKeyBase ); } } // // Summary: // Derives a PKCS5 key from a password. // static byte[] DoPkcs5( byte[] password, byte[] salt ) { PasswordDeriveBytes pkcs5 = new PasswordDeriveBytes( password, salt, "SHA256", ITERATIONCOUNT ); return pkcs5.GetBytes( ENCRYPTIONKEYBUFFERSIZE ); } // // Summary: // Compares two signatures and return true if they are the same. // internal static bool CompareSignature( byte[] input, byte[] expected ) { if( input.Length == 0 ) { return false; } if( input.Length != expected.Length ) { return false; } for( int i = 0; i < input.Length; i++ ) { if( expected[ i ] != input[ i ] ) { return false; } } return true; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SupportingTokenAuthenticatorSpecification.cs
- QilGenerator.cs
- PageBuildProvider.cs
- Imaging.cs
- BufferedStream2.cs
- Label.cs
- QuaternionValueSerializer.cs
- Activity.cs
- SqlDataSourceConfigureSelectPanel.cs
- _NestedMultipleAsyncResult.cs
- CroppedBitmap.cs
- ellipse.cs
- SecurityManager.cs
- PrinterUnitConvert.cs
- PreloadedPackages.cs
- DataSourceControl.cs
- RijndaelManagedTransform.cs
- OleDbRowUpdatingEvent.cs
- TextElementEnumerator.cs
- XsltArgumentList.cs
- EventToken.cs
- WebPartPersonalization.cs
- CodeMethodReturnStatement.cs
- ImageButton.cs
- ZipIOCentralDirectoryFileHeader.cs
- HashHelper.cs
- BinaryEditor.cs
- EventLogEntry.cs
- PersistChildrenAttribute.cs
- Property.cs
- CompilerGeneratedAttribute.cs
- DataControlField.cs
- SecurityUtils.cs
- GraphicsPathIterator.cs
- UserControlParser.cs
- ChangeConflicts.cs
- EnumerableRowCollection.cs
- SerializationSectionGroup.cs
- PageVisual.cs
- DBCommand.cs
- SplayTreeNode.cs
- CleanUpVirtualizedItemEventArgs.cs
- itemelement.cs
- Rules.cs
- RunWorkerCompletedEventArgs.cs
- MenuItemBindingCollection.cs
- SmtpAuthenticationManager.cs
- HttpCacheVaryByContentEncodings.cs
- CapabilitiesUse.cs
- TextChange.cs
- DataObjectSettingDataEventArgs.cs
- RelationshipDetailsCollection.cs
- Journaling.cs
- PageAsyncTaskManager.cs
- UniformGrid.cs
- KoreanLunisolarCalendar.cs
- XmlRawWriter.cs
- TextServicesManager.cs
- SafeProcessHandle.cs
- InternalPolicyElement.cs
- ListItemsCollectionEditor.cs
- SqlLiftWhereClauses.cs
- TraceXPathNavigator.cs
- CachedBitmap.cs
- TraceHwndHost.cs
- DesignerSelectionListAdapter.cs
- Underline.cs
- RowToParametersTransformer.cs
- UserControlParser.cs
- ParserStreamGeometryContext.cs
- EmbeddedMailObject.cs
- InputMethodStateTypeInfo.cs
- ProcessInputEventArgs.cs
- DynamicPropertyHolder.cs
- TerminatorSinks.cs
- Pkcs9Attribute.cs
- RequestCacheValidator.cs
- HScrollBar.cs
- ArglessEventHandlerProxy.cs
- EditBehavior.cs
- CRYPTPROTECT_PROMPTSTRUCT.cs
- TraceRecord.cs
- NumericExpr.cs
- Lasso.cs
- TypeElementCollection.cs
- TdsValueSetter.cs
- Configuration.cs
- ColumnPropertiesGroup.cs
- ZoneIdentityPermission.cs
- ClickablePoint.cs
- ExpandoClass.cs
- Transactions.cs
- ArithmeticException.cs
- HttpPostedFileWrapper.cs
- DiscoveryReference.cs
- Operator.cs
- FtpWebResponse.cs
- TextElementEnumerator.cs
- MessageSecurityTokenVersion.cs
- QueuePathEditor.cs