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
- Dynamic.cs
- BuiltInExpr.cs
- LinearGradientBrush.cs
- HelloOperationAsyncResult.cs
- NoneExcludedImageIndexConverter.cs
- HttpModulesSection.cs
- TextRenderer.cs
- UserNameSecurityTokenParameters.cs
- SoapSchemaExporter.cs
- RenameRuleObjectDialog.Designer.cs
- HorizontalAlignConverter.cs
- SecurityDocument.cs
- validation.cs
- Block.cs
- HybridDictionary.cs
- ChildrenQuery.cs
- MaterializeFromAtom.cs
- EditorPartChrome.cs
- EdgeProfileValidation.cs
- ModelFunctionTypeElement.cs
- CacheForPrimitiveTypes.cs
- SocketElement.cs
- ADMembershipUser.cs
- RowUpdatingEventArgs.cs
- ConfigurationValidatorAttribute.cs
- RawContentTypeMapper.cs
- ChildDocumentBlock.cs
- AdornerLayer.cs
- TabletDevice.cs
- HasActivatableWorkflowEvent.cs
- FlowDocumentPage.cs
- DoubleAnimationClockResource.cs
- SevenBitStream.cs
- PathSegmentCollection.cs
- StreamWithDictionary.cs
- KeyGestureConverter.cs
- MetadataItemEmitter.cs
- Line.cs
- AssemblyGen.cs
- EventLogPermission.cs
- Soap.cs
- ContainerActivationHelper.cs
- XmlReader.cs
- DocumentOrderQuery.cs
- SynchronizedDispatch.cs
- PreloadedPackages.cs
- CultureInfo.cs
- Tile.cs
- ChineseLunisolarCalendar.cs
- MobileControlPersister.cs
- RowToParametersTransformer.cs
- DateTime.cs
- DataPagerFieldCollection.cs
- XmlWellformedWriter.cs
- ClientTargetCollection.cs
- StorageEndPropertyMapping.cs
- PointAnimation.cs
- StringSource.cs
- MetadataArtifactLoaderFile.cs
- ModifierKeysValueSerializer.cs
- StatusBar.cs
- Collection.cs
- FrugalList.cs
- IndividualDeviceConfig.cs
- SafeWaitHandle.cs
- RSACryptoServiceProvider.cs
- MenuItem.cs
- TdsParser.cs
- XmlSchemaChoice.cs
- LogicalCallContext.cs
- TextTreeTextBlock.cs
- UnsafeNativeMethods.cs
- Figure.cs
- DbMetaDataColumnNames.cs
- NativeWindow.cs
- Simplifier.cs
- CriticalExceptions.cs
- TreeNodeCollectionEditor.cs
- QueryPrefixOp.cs
- SystemUdpStatistics.cs
- storepermissionattribute.cs
- CapabilitiesUse.cs
- IdentifierService.cs
- ComEventsMethod.cs
- ProxyWebPart.cs
- XmlSequenceWriter.cs
- SerializationUtilities.cs
- ErrorRuntimeConfig.cs
- ImageClickEventArgs.cs
- LocatorBase.cs
- CacheModeConverter.cs
- DataBoundControl.cs
- TextElement.cs
- BuildDependencySet.cs
- SystemIcmpV6Statistics.cs
- LineProperties.cs
- XmlSerializableServices.cs
- MessageDroppedTraceRecord.cs
- Subtree.cs
- SuppressMergeCheckAttribute.cs