コード例 #1
0
        public static void DeriveKeys(byte[] kdk, ArraySegment <byte> label, ArraySegment <byte> context, Func <byte[], HashAlgorithm> prfFactory, ArraySegment <byte> output)
        {
            // make copies so we can mutate these local vars
            int outputOffset = output.Offset;
            int outputCount  = output.Count;

            using (HashAlgorithm prf = prfFactory(kdk))
            {
                // See SP800-108, Sec. 5.1 for the format of the input to the PRF routine.
                byte[] prfInput = new byte[checked (sizeof(uint) /* [i]_2 */ + label.Count + 1 /* 0x00 */ + context.Count + sizeof(uint) /* [K]_2 */)];

                // Copy [L]_2 to prfInput since it's stable over all iterations
                uint outputSizeInBits = (uint)checked ((int)outputCount * 8);
                prfInput[prfInput.Length - 4] = (byte)(outputSizeInBits >> 24);
                prfInput[prfInput.Length - 3] = (byte)(outputSizeInBits >> 16);
                prfInput[prfInput.Length - 2] = (byte)(outputSizeInBits >> 8);
                prfInput[prfInput.Length - 1] = (byte)(outputSizeInBits);

                // Copy label and context to prfInput since they're stable over all iterations
                Buffer.BlockCopy(label.Array, label.Offset, prfInput, sizeof(uint), label.Count);
                Buffer.BlockCopy(context.Array, context.Offset, prfInput, sizeof(int) + label.Count + 1, context.Count);

                int prfOutputSizeInBytes = prf.GetDigestSizeInBytes();
                for (uint i = 1; outputCount > 0; i++)
                {
                    // Copy [i]_2 to prfInput since it mutates with each iteration
                    prfInput[0] = (byte)(i >> 24);
                    prfInput[1] = (byte)(i >> 16);
                    prfInput[2] = (byte)(i >> 8);
                    prfInput[3] = (byte)(i);

                    // Run the PRF and copy the results to the output buffer
                    byte[] prfOutput = prf.ComputeHash(prfInput);
                    CryptoUtil.Assert(prfOutputSizeInBytes == prfOutput.Length, "prfOutputSizeInBytes == prfOutput.Length");
                    int numBytesToCopyThisIteration = Math.Min(prfOutputSizeInBytes, outputCount);
                    Buffer.BlockCopy(prfOutput, 0, output.Array, outputOffset, numBytesToCopyThisIteration);
                    Array.Clear(prfOutput, 0, prfOutput.Length); // contains key material, so delete it

                    // adjust offsets
                    outputOffset += numBytesToCopyThisIteration;
                    outputCount  -= numBytesToCopyThisIteration;
                }
            }
        }