Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / RsaKeyGen.cs / 1 / RsaKeyGen.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace Microsoft.InfoCards { using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.IO; using System.Text; using System.Diagnostics; using Microsoft.InfoCards.Diagnostics; using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; // // Summary: // Utility class for RSA Key Pair Generation // sealed class RsaKeyGen { ////////////////////////////////////////////////////////////////// // Key pair size (size of the modulus n) is fixed at 2048 bits ////////////////////////////////////////////////////////////////// const int Xpq12Length = 14; const int XpqLength = 128; const int NumberOfSha1Hashes = 16; const int InfoCardKeyLength = 2048; // // Overall approach // Since the msbignum code wants little endian byte order for large integers Xp and Xq // (which are laid out as a sequence of bytes), we want to generate Xp and Xq in little endian. // // The spec says to generate // H4 (big endian) + H5 (big endian) + H6 (big endian) + H0[4 MSB] (big endian) // + H10 (big endian) + H11 (big endian) + H12 (big endian) + H2[4 MSB] (big endian) // // In little endian this equals: // Array.Reverse( H4 (big endian) + H5 (big endian) + H6 (big endian) + H0[4 MSB] (big endian) // + H10 (big endian) + H11 (big endian) + H12 (big endian) + H2[4 MSB] (big endian) ) // // Which is the same as (note the order of H has been reversed): // H2[4 MSB] (little endian) + H12 (little endian) + H11 (little endian) + H10 (little endian) // + H0[4 MSB] (little endian) + H6 (little endian) + H5 (little endian) + H4 (little endian) // // Therefore the approach is to generate each of the H's in little endian, and then // append them in reverse order [H2 H12 H11 H10 H0 H6 H5 H4] compared to the big endian order [H4 H5 H6 H0 H10 H11 H12 H2] // that is detailed in the spec. // static int[ ] hashesToWriteP = new int[ 8 ] { 2, 12, 11, 10, 0, 6, 5, 4 }; static int[ ] numBytesToWriteP = new int[ 8 ] { 4, HnLength, HnLength, HnLength, 4, HnLength, HnLength, HnLength }; static int[] srcIndexBytesToWriteP = new int[ 8 ] { 16, 0, 0, 0, 16, 0, 0, 0 }; static int[ ] hashesToWriteQ = new int[ 8 ] { 3, 15, 14, 13, 1, 9, 8, 7 }; static int[ ] numBytesToWriteQ = numBytesToWriteP; static int[ ] srcIndexBytesToWriteQ = srcIndexBytesToWriteP; //////////////////////////////////////////////////////////////// // Uncomment below if we want asymm key pairs to be 1024 bits. //////////////////////////////////////////////////////////////// // // const int Xpq12Length = 14; // const int XpqLength = 64; // const int NumberOfSha1Hashes = 16; // const int InfoCardKeyLength = 1024; // // static int[ ] hashesToWriteP = new int[ 4 ] { 0, 6, 5, 4 }; // static int[ ] numBytesToWriteP = new int[ 4 ] { 4, HnLength, HnLength, HnLength }; // static int[ ] srcIndexBytesToWriteP = new int[ 4 ] { 16, 0, 0, 0 }; // // static int[ ] hashesToWriteQ = new int[ 4 ] { 1, 9, 8, 7 }; // static int[ ] numBytesToWriteQ = numBytesToWriteP; // static int[ ] srcIndexBytesToWriteQ = srcIndexBytesToWriteP; // //////////////////////////////////////////////////////////////// // Size of a SHA1 hash in bytes const int HnLength = 20; // A recommended public exponent value const int PublicExponentValue = 65537; // The encryption key used when regenerating input params const string Aes128EncryptionKey = "f561e58b-3ebc-4e0c-940d-0a6ddc219dfd"; // // Represents the byte in which 2^100 is located. // const int ByteForHundredthBit = 100/8; // // Set up AES 128 using Electronic Code Book mode // static RijndaelManaged s_rjAes128 = new RijndaelManaged(); // // Summary: // Set up AES 128 using Electronic Code Book mode // static RsaKeyGen() { s_rjAes128.Mode = CipherMode.ECB; s_rjAes128.Padding = PaddingMode.Zeros; s_rjAes128.Key = ( new Guid( Aes128EncryptionKey ) ).ToByteArray(); } // // Summary: // Implementation of the InfoCard RSA Key Gen Algorithm complying to // X9.31 to create a privatekey blob. // // Params: // masterKey - M (infocard masterkey) // TargetId - T (target recipient entropy) // // Return: // The CryptoAPI PRIVATEKEYBLOB // public static byte[ ] CreateRsaKeyPairX931( byte[ ] masterKey, byte[ ] targetId ) { // // Sanity Check: Only 1024 or 2048 bit keys supported! // IDT.Assert( InfoCardKeyLength == InfoCard.KeySize, "Only 2048 bit key sizes supported" ); // // Calculate all the Hn = n + T + M (LITTLE ENDIAN) // i.e. Hn = M + T + n (BIG ENDIAN) // byte[ ][ ] hnArray = CalculateHn( masterKey, targetId ); // Will be populate with the return blob byte[ ] cryptoBlob = null; // // Allocate bytes that will contain the 6 integers. We'll copy these to // native memory and then call the native RSA Key Gen function. // // // Question: Why create the extra copy? // Why not just copy over appropriate number of bytes from Hn to an IntPtr // and pass that to native memory? // // Answer: We create Xp*ByteArray as local variables which comes in useful // when rsakeygen fails and we regenerate input params. So if Xp* // need to be regenerated, they are copied into the original buffer locations // byte[ ] Xp1ByteArray = new byte[ Xpq12Length ]; byte[ ] Xp2ByteArray = new byte[ Xpq12Length ]; byte[ ] Xq1ByteArray = new byte[ Xpq12Length ]; byte[ ] Xq2ByteArray = new byte[ Xpq12Length ]; byte[ ] XpByteArray = new byte[ XpqLength ]; byte[ ] XqByteArray = new byte[ XpqLength ]; // // Init Xp1ByteArray, Xp2ByteArray, Xq1ByteArray, Xq2ByteArray // hnArray = 20 bytes, Xp1ByteArray = 14 bytes // Array.Copy( hnArray[ 0 ], 0, Xp1ByteArray, 0, Xp1ByteArray.Length ); Array.Copy( hnArray[ 1 ], 0, Xp2ByteArray, 0, Xp2ByteArray.Length ); Array.Copy( hnArray[ 2 ], 0, Xq1ByteArray, 0, Xq1ByteArray.Length ); Array.Copy( hnArray[ 3 ], 0, Xq2ByteArray, 0, Xq2ByteArray.Length ); // // Init XpByteArray - H2 H12 H11 H10 H0 H6 H5 H4 (little endian) // // Sanity check: We want H4 as part of MSB. // I.e. stored last in buffer in little endian. // WriteToArray( hashesToWriteP, numBytesToWriteP, srcIndexBytesToWriteP, hnArray, XpByteArray ); // // Init XqByteArray - H3 H15 H14 H13 H1 H9 H8 H7 (little endian) // WriteToArray( hashesToWriteQ, numBytesToWriteQ, srcIndexBytesToWriteQ, hnArray, XqByteArray ); try { KeyGenRestartCodes restartCode = KeyGenRestartCodes.X931RestartNone; // // The chance of failure in each iteration is very rare. // So the likelyhood of 2 iterations failing in a row is // even smaller. So even a while( true ), should suffice. // Plan to run this with lots of input combinations overnight // or determine actual probabilities // to provide a confidence level in termination of algorithm // do { // // The X931KeyGen checks that the seeds will produce a // modulus of the specified length, this means the upper // bits of the most significant byte needs to be set to 0xF0 // so that we get a 2048 bit modulus. Confirmed with // Josh Benaloh on this is Ok. // // Question: Why | with 0xC0 as opposed to 0x1000 ? // Answer: The problem is that 0x80 x 0x80 = 0x4000, // so the high bit of the modulus is not set. Since 0xC0 x 0xC0 = 0x9000, // we guarantee the high bit is set. // XpByteArray[ XpqLength - 1 ] |= ( byte ) 0xC0; XqByteArray[ XpqLength - 1 ] |= ( byte ) 0xC0; // // Make sure Xpq12 are greater than 2^100 as required by X9.31 // The maximum i.e. Xpq12 < 2^120 is automatically met becuase // Xpq12 are only 112 bits long. // Xp1ByteArray[ ByteForHundredthBit ] |= ( byte ) 0x10; Xp2ByteArray[ ByteForHundredthBit ] |= ( byte ) 0x10; Xq1ByteArray[ ByteForHundredthBit ] |= ( byte ) 0x10; Xq2ByteArray[ ByteForHundredthBit ] |= ( byte ) 0x10; cryptoBlob = NativeMcppMethods.X931KeyGenWrapper( Xp1ByteArray, Xp2ByteArray, Xq1ByteArray, Xq2ByteArray, XpByteArray, XqByteArray, PublicExponentValue, ref restartCode ); IDT.TraceDebug( "InfoCardKeyGen: Restart code is : {0}", restartCode ); switch ( restartCode ) { case KeyGenRestartCodes.X931RestartNone: // Success IDT.Assert( null != cryptoBlob, "Cryptoblob should not be null since API succeeded" ); break; // decryexp < 2^bitlen_pq case KeyGenRestartCodes.X931RestartDTooSmall: // As per Josh Benaloh, with e fixed at 65537, // d will be guaranteed to be much larger than 1/2 the length of n IDT.Assert( null == cryptoBlob, "Cryptoblob should be null" ); IDT.Assert( false, "Not expected for d < 2^1024 with e = 65537" ); InfoCardRegenerateParam( Xq1ByteArray ); InfoCardRegenerateParam( Xq2ByteArray ); InfoCardRegenerateParam( XqByteArray ); break; // GCD(p1, p2) > 1 or GCD(q1, q2) > 1 case KeyGenRestartCodes.X931RestartNonTrivialGcd: IDT.Assert( null == cryptoBlob, "Cryptoblob should be null" ); InfoCardRegenerateParam( Xp1ByteArray ); InfoCardRegenerateParam( Xp2ByteArray ); InfoCardRegenerateParam( Xq1ByteArray ); InfoCardRegenerateParam( Xq2ByteArray ); break; // p or q > 2^bitlen_pq case KeyGenRestartCodes.X931RestartPQOverflow: IDT.Assert( null == cryptoBlob, "Cryptoblob should be null" ); InfoCardRegenerateParam( XpByteArray ); InfoCardRegenerateParam( XqByteArray ); break; // p1 or p2 or q1 or q2 > 2^X931_MAXBITS_PQ12 case KeyGenRestartCodes.X931RestartPQ12OverFlow: IDT.Assert( null == cryptoBlob, "Cryptoblob should be null" ); InfoCardRegenerateParam( Xp1ByteArray ); InfoCardRegenerateParam( Xp2ByteArray ); InfoCardRegenerateParam( Xq1ByteArray ); InfoCardRegenerateParam( Xq2ByteArray ); break; // abs(Xp - Xq) too small case KeyGenRestartCodes.X931RestartXpXqClose: IDT.Assert( null == cryptoBlob, "Cryptoblob should be null" ); InfoCardRegenerateParam( XqByteArray ); break; } }while( restartCode != KeyGenRestartCodes.X931RestartNone ); IDT.Assert( null != cryptoBlob, "Cryptoblob should NOT be null outside while loop" ); } finally { // // Clear out all arrays allocated // Array.Clear( Xp1ByteArray, 0, Xp1ByteArray.Length ); Array.Clear( Xp2ByteArray, 0, Xp2ByteArray.Length ); Array.Clear( Xq1ByteArray, 0, Xq1ByteArray.Length ); Array.Clear( Xq2ByteArray, 0, Xq2ByteArray.Length ); Array.Clear( XpByteArray, 0, XpByteArray.Length ); Array.Clear( XqByteArray, 0, XqByteArray.Length ); } return cryptoBlob; } // // Summary: // Utility function to copy appropriate number of bytes to appropriate index // in destArray // // hashesToWrite - represents index in sourceArrayOfHashes that we want to copy // numBytesToWrite - num of bytes to copy // srcIndexBytesToWrite - index of bytes to begin copying from // sourceArrayOfHashes - a 2d array of the SHA1 hashes we created // destArray - the buffer where we'll copy this to // static void WriteToArray( int[ ] hashesToWrite, int[ ] numBytesToWrite, int[ ] srcIndexBytesToWrite, byte[ ][ ] sourceArrayOfHashes, byte[ ] destArray ) { IDT.Assert( hashesToWrite.Length == numBytesToWrite.Length, "Size must be equal" ); IDT.Assert( numBytesToWrite.Length == srcIndexBytesToWrite.Length, "Size must be equal" ); int destIndex = 0; for ( int index = 0; index < hashesToWrite.Length; index++ ) { int indexInHashArray = hashesToWrite[ index ]; Array.Copy( sourceArrayOfHashes[ indexInHashArray ], srcIndexBytesToWrite[ index ], destArray, destIndex, numBytesToWrite[ index ] ); destIndex += numBytesToWrite[ index ]; } } // // Summary: // Create byte array of H(n) for n = 0, 1, 2, ...15 // where H(n) = M + T + C(n) = M + T + n in Big Endian. // // Params: // masterKey - M (infocard masterkey) // subjectEntropy - T (Recipient entropy) // // Remarks: // n - constant represented by C(n), must be in big endian. // M + T - does not really make sense if this means big endian or not becuase we're simply concatenating bytes // // Return: // 16 byte arrays (representing H0, H1, ..., H15) each of length 20 (i.e. 160 bits) // static byte[ ][ ] CalculateHn( byte[ ] masterKey, byte[ ] subjectEntropy ) { byte[ ][ ] hnArray = new byte[ NumberOfSha1Hashes ][ ]; // // Setup array common to all H(n) // int byteArraySize = masterKey.Length + subjectEntropy.Length + sizeof( int ); byte[ ] inputBytes = new byte[ byteArraySize ]; // // Put in M // Array.Copy( masterKey, 0, inputBytes, 0, masterKey.Length ); // // Put in T after M // Array.Copy( subjectEntropy, 0, inputBytes, masterKey.Length, subjectEntropy.Length ); // // Now fill in n for all the Hn's // for ( uint n = 0; n < hnArray.Length; n++ ) { // // Convert n to a byte and fill it in the last element of the array (since we want big-endian n) // (We assert that n does not exceed a byte.) // // POTENTIAL TEST ? // Passing in constant integer 2 (instead of n) means we'd generate identical Xp Xq etc. // which will cause the code the to shutle thru X931RestartXpXqClose, X931RestartNonTrivialGcd, // followed by success // IDT.Assert( n <= 0xFF, "n must fit in a byte." ); IDT.Assert( inputBytes.Length - 1 == masterKey.Length + subjectEntropy.Length + 3, "Index location of n must be last element of array." ); inputBytes[ inputBytes.Length - 1 ] = ( byte ) n; // // SHA digest (an integer) is returned in big endian // hnArray[ n ] = SHA1.Create().ComputeHash( inputBytes ); // // Our code deals with little endian byte order (as detailed at the start of this file), so flip the bytes // Array.Reverse( hnArray[ n ] ); } Array.Clear( inputBytes, 0, inputBytes.Length ); return hnArray; } // // Summary: // Regenerates input params as per infocard key gen algorithm // Copies new data on top of input array // // Params: // prevBytes - the byte array to encrypt // // Return: // Nil, the input array contains the newly generated bytes // static void InfoCardRegenerateParam( byte[ ] prevBytes ) { // // AESEncrypt previous bytes // byte[ ] newBytes = AESEncryptECB( prevBytes ); // // Copy it into old memory // Array.Copy( newBytes, 0, prevBytes, 0, prevBytes.Length ); // // Zero out previous buffer // Array.Clear( newBytes, 0, newBytes.Length ); } // // Summary: // Does AES 128 using Electronic Code Book mode // Encrytion Key = C = f561e58b-3ebc-4e0c-940d-0a6ddc219dfd // Padding = zero-bits such that bit-length is a multiple of 128 // // Params: // plaintextbyte - the byte array to encrypt // static byte[ ] AESEncryptECB( byte[ ] plaintextbyte ) { // // Create a CryptoStream from a memory stream // MemoryStream ciphertextmem = new MemoryStream(); CryptoStream crystm = new CryptoStream( ciphertextmem, s_rjAes128.CreateEncryptor(), CryptoStreamMode.Write ); // // Get the cipher text // crystm.Write( plaintextbyte, 0, plaintextbyte.Length ); crystm.Close(); Byte[ ] ciphertextbyte = ciphertextmem.ToArray(); ciphertextmem.Close(); return ciphertextbyte; } // // Summary: // This class is purely for utility purposes // private RsaKeyGen() { } } } // 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
- RepeaterItemEventArgs.cs
- DecimalConstantAttribute.cs
- XPathBinder.cs
- OdbcException.cs
- ListenerTraceUtility.cs
- BooleanStorage.cs
- VerificationException.cs
- SoapIncludeAttribute.cs
- DataServiceClientException.cs
- DataFieldEditor.cs
- DataBindingExpressionBuilder.cs
- TextEditorMouse.cs
- BatchWriter.cs
- TableLayoutStyle.cs
- AtomParser.cs
- FixedPosition.cs
- HttpModulesSection.cs
- ZoneIdentityPermission.cs
- ObjectConverter.cs
- KeyFrames.cs
- ItemChangedEventArgs.cs
- Inflater.cs
- XsdDuration.cs
- ClientTargetCollection.cs
- WeakRefEnumerator.cs
- IconHelper.cs
- ListViewDataItem.cs
- Vector3DConverter.cs
- AsymmetricSecurityProtocolFactory.cs
- XmlHierarchicalDataSourceView.cs
- DashStyles.cs
- hwndwrapper.cs
- SapiAttributeParser.cs
- storagemappingitemcollection.viewdictionary.cs
- TileModeValidation.cs
- SQLInt32.cs
- SchemaTypeEmitter.cs
- ResourceReader.cs
- DeploymentSection.cs
- HelloOperation11AsyncResult.cs
- CodeValidator.cs
- ExpandedProjectionNode.cs
- PathGradientBrush.cs
- DrawingContextWalker.cs
- PriorityBinding.cs
- StickyNote.cs
- Interop.cs
- DisableDpiAwarenessAttribute.cs
- CubicEase.cs
- SettingsPropertyNotFoundException.cs
- ApplyImportsAction.cs
- BeginCreateSecurityTokenRequest.cs
- EntitySqlException.cs
- ResourceCollectionInfo.cs
- SequentialOutput.cs
- NamedPermissionSet.cs
- DistinctQueryOperator.cs
- _IPv6Address.cs
- LinearGradientBrush.cs
- TextContainerHelper.cs
- RijndaelManaged.cs
- ReadOnlyDataSourceView.cs
- BaseTypeViewSchema.cs
- SecurityHeaderLayout.cs
- Rule.cs
- InkSerializer.cs
- CurrencyManager.cs
- Perspective.cs
- BuildProvider.cs
- StringToken.cs
- BookmarkCallbackWrapper.cs
- FontInfo.cs
- newinstructionaction.cs
- CopyEncoder.cs
- GridItem.cs
- ImageConverter.cs
- UIElementIsland.cs
- CommonRemoteMemoryBlock.cs
- RemotingSurrogateSelector.cs
- XPathNavigator.cs
- TableLayout.cs
- SystemSounds.cs
- GridViewAutomationPeer.cs
- SafeArrayRankMismatchException.cs
- AnnotationAuthorChangedEventArgs.cs
- StrokeCollectionConverter.cs
- SmtpAuthenticationManager.cs
- ZoneLinkButton.cs
- MarkupProperty.cs
- UiaCoreTypesApi.cs
- VersionConverter.cs
- QilInvokeLateBound.cs
- PermissionListSet.cs
- CoTaskMemSafeHandle.cs
- Graph.cs
- ObjectQueryProvider.cs
- mda.cs
- ExpandCollapsePattern.cs
- SystemIPInterfaceProperties.cs
- QueryOpcode.cs