Example #1
0
        // Transform an input block into an output block.
        public static int TransformBlock(CryptoAPITransform transform,
                                         byte[] inputBuffer, int inputOffset,
                                         int inputCount, byte[] outputBuffer,
                                         int outputOffset)
        {
            int blockSize = transform.blockSize;

            byte[] iv     = transform.iv;
            IntPtr state  = transform.state;
            int    offset = outputOffset;

            byte[] tempBuffer = transform.tempBuffer;
            int    tempSize   = transform.tempSize;
            int    index;

            // Process all of the data in the input.  We need to keep
            // the last two blocks for the finalization process.
            while (inputCount >= blockSize)
            {
                // If the temporary buffer is full, then flush a block
                // through the cipher in CBC mode.
                if (tempSize > blockSize)
                {
                    // Decrypt the ciphertext block and XOR with the IV.
                    CryptoMethods.Decrypt(state, tempBuffer, blockSize,
                                          tempBuffer, 0);
                    for (index = blockSize - 1; index >= 0; --index)
                    {
                        tempBuffer[index] ^= iv[index];
                    }

                    // Copy the original ciphertext to the IV.
                    Array.Copy(tempBuffer, blockSize, iv, 0, blockSize);

                    // Copy the plaintext into place.
                    Array.Copy(tempBuffer, 0, outputBuffer,
                               offset, blockSize);

                    // Advance to the next output block.
                    offset += blockSize;

                    // Shift the second block down to the first position.
                    Array.Copy(tempBuffer, blockSize * 2,
                               tempBuffer, blockSize, blockSize);
                    tempSize -= blockSize;
                }

                // Copy the next block into the temporary buffer.
                Array.Copy(inputBuffer, inputOffset,
                           tempBuffer, tempSize + blockSize, blockSize);
                inputOffset += blockSize;
                inputCount  -= blockSize;
                tempSize    += blockSize;
            }
            transform.tempSize = tempSize;

            // Finished.
            return(offset - outputOffset);
        }
Example #2
0
        // Transform an input block into an output block.
        public static int TransformBlock(CryptoAPITransform transform,
                                         byte[] inputBuffer, int inputOffset,
                                         int inputCount, byte[] outputBuffer,
                                         int outputOffset)
        {
            int blockSize = transform.blockSize;

            byte[] iv    = transform.iv;
            IntPtr state = transform.state;

            byte[] tempBuffer = transform.tempBuffer;
            int    offset     = outputOffset;
            int    index;
            bool   needPadding = (transform.padding != PaddingMode.None);

            // Process a left-over block from last time.
            if (transform.tempSize > 0 && inputCount > 0)
            {
                // Decrypt the ciphertext to get the plaintext.
                CryptoMethods.Decrypt(state, tempBuffer, 0,
                                      outputBuffer, offset);

                // Advance to the next block and clear the temporary block.
                offset            += blockSize;
                transform.tempSize = 0;
                for (index = blockSize - 1; index >= 0; --index)
                {
                    tempBuffer[index] = (byte)0x00;
                }
            }

            // Process all of the blocks in the input, minus one.
            // If we don't need padding, then process all of the blocks.
            while ((needPadding && inputCount > blockSize) ||
                   (!needPadding && inputCount >= blockSize))
            {
                // Decrypt the ciphertext to get the plaintext.
                CryptoMethods.Decrypt(state, inputBuffer, inputOffset,
                                      outputBuffer, offset);

                // Advance to the next block.
                inputOffset += blockSize;
                inputCount  -= blockSize;
                offset      += blockSize;
            }

            // Save the last block for next time.
            if (needPadding && inputCount > 0)
            {
                Array.Copy(inputBuffer, inputOffset,
                           tempBuffer, 0, inputCount);
                transform.tempSize = inputCount;
            }

            // Finished.
            return(offset - outputOffset);
        }
Example #3
0
        // Transform the final input block.
        public static byte[] TransformFinalBlock(CryptoAPITransform transform,
                                                 byte[] inputBuffer,
                                                 int inputOffset,
                                                 int inputCount)
        {
            int blockSize = transform.blockSize;

            byte[] iv    = transform.iv;
            IntPtr state = transform.state;
            int    offset;

            byte[] tempBuffer = transform.tempBuffer;
            byte[] outputBuffer;
            int    tempSize;
            int    index;

            // Allocate the output buffer.
            outputBuffer = new byte [inputCount + transform.tempSize];

            // Process as many full blocks as possible.
            index  = inputCount - (inputCount % blockSize);
            offset = TransformBlock(transform, inputBuffer,
                                    inputOffset, index,
                                    outputBuffer, 0);
            inputOffset += index;
            inputCount  -= index;

            // Flush the first block if we need the extra space.
            tempSize = transform.tempSize;
            if (tempSize > blockSize && inputCount > 0)
            {
                // Decrypt the ciphertext block and XOR with the IV.
                CryptoMethods.Decrypt(state, tempBuffer, blockSize,
                                      tempBuffer, 0);
                for (index = blockSize - 1; index >= 0; --index)
                {
                    tempBuffer[index] ^= iv[index];
                }

                // Copy the original ciphertext to the IV.
                Array.Copy(tempBuffer, blockSize, iv, 0, blockSize);

                // Copy the plaintext into place.
                Array.Copy(tempBuffer, 0, outputBuffer,
                           offset, blockSize);

                // Advance to the next output block.
                offset += blockSize;

                // Shift the second block down to the first position.
                Array.Copy(tempBuffer, blockSize * 2,
                           tempBuffer, blockSize, blockSize);
                tempSize -= blockSize;
            }

            // Copy the remainder of the data into the temporary buffer.
            Array.Copy(inputBuffer, inputOffset,
                       tempBuffer, tempSize + blockSize, inputCount);
            tempSize += inputCount;

            // "Applied Cryptography" describes Cipher Text Stealing
            // as taking two blocks to generate the short end-point.
            // If we less than one block, then use CFB instead.
            if (tempSize < blockSize)
            {
                // Decrypt the single block in CFB mode.
                CryptoMethods.Encrypt(transform.state2, iv, 0, iv, 0);
                for (index = 0; index < tempSize; ++index)
                {
                    outputBuffer[offset + index] =
                        (byte)(iv[index] ^ tempBuffer[index + blockSize]);
                }
            }
            else
            {
                // Decrypt the second last ciphertext block.
                CryptoMethods.Decrypt(state, tempBuffer, blockSize,
                                      tempBuffer, blockSize);

                // Rebuild the ciphertext for the last block.
                for (index = inputCount; index < blockSize; ++index)
                {
                    tempBuffer[blockSize * 2 + index] =
                        tempBuffer[blockSize + index];
                }

                // Get the last plaintext block from the second
                // last ciphertext block.
                for (index = inputCount - 1; index >= 0; --index)
                {
                    outputBuffer[offset + blockSize + index] =
                        (byte)(tempBuffer[blockSize + index] ^
                               tempBuffer[blockSize * 2 + index]);
                }

                // Decrypt the last ciphertext block that we rebuilt.
                CryptoMethods.Decrypt(state, tempBuffer, blockSize * 2,
                                      tempBuffer, 0);

                // XOR the block with the IV to get the second
                // last plaintext block.
                for (index = blockSize - 1; index >= 0; --index)
                {
                    outputBuffer[offset + index] =
                        (byte)(iv[index] ^ tempBuffer[index]);
                }
            }

            // Finished.
            return(outputBuffer);
        }
Example #4
0
        // Transform the final input block.
        public static byte[] TransformFinalBlock(CryptoAPITransform transform,
                                                 byte[] inputBuffer,
                                                 int inputOffset,
                                                 int inputCount)
        {
            int    blockSize = transform.blockSize;
            IntPtr state     = transform.state;

            byte[] tempBuffer = transform.tempBuffer;
            byte[] outputBuffer;
            int    offset, index, pad;

            // Allocate a temporary output buffer.
            outputBuffer = new byte [inputCount + blockSize];

            // Push the remaining bytes through the decryptor.  The
            // final block will end up in "transform.tempBuffer".
            offset = TransformBlock(transform, inputBuffer, inputOffset,
                                    inputCount, outputBuffer, 0);

            // Decrypt the final block in "tempBuffer".
            if (transform.tempSize > 0)
            {
                // Decrypt the ciphertext to get the plaintext.
                CryptoMethods.Decrypt(state, tempBuffer, 0,
                                      tempBuffer, 0);

                // Remove padding.
                if (transform.padding == PaddingMode.PKCS7)
                {
                    // Use PKCS #7 padding.
                    pad = tempBuffer[blockSize - 1];
                    if (pad == 0 || pad > blockSize)
                    {
                        pad = blockSize;
                    }
                    Array.Copy(tempBuffer, 0, outputBuffer,
                               offset, blockSize - pad);
                    offset += blockSize - pad;
                    pad     = 0;
                }
                else if (transform.padding == PaddingMode.Zeros)
                {
                    // Strip zeroes from the end of the block.
                    index = blockSize;
                    while (index > 0 && tempBuffer[index - 1] == 0)
                    {
                        --index;
                    }
                    Array.Copy(tempBuffer, 0, outputBuffer,
                               offset, index);
                    offset += index;
                }
                else
                {
                    // No padding, so return the whole block.
                    Array.Copy(tempBuffer, 0, outputBuffer,
                               offset, blockSize);
                    offset += blockSize;
                }
            }

            // Reduce the output buffer size to the final length.
            if (offset != outputBuffer.Length)
            {
                byte[] newout = new byte [offset];
                if (offset != 0)
                {
                    Array.Copy(outputBuffer, 0, newout, 0, offset);
                }
                Array.Clear(outputBuffer, 0, outputBuffer.Length);
                outputBuffer = newout;
            }

            // Finished.
            return(outputBuffer);
        }
Example #5
0
        // Transform an input block into an output block.
        public static int TransformBlock(CryptoAPITransform transform,
                                         byte[] inputBuffer, int inputOffset,
                                         int inputCount, byte[] outputBuffer,
                                         int outputOffset)
        {
            int blockSize = transform.blockSize;

            byte[] iv    = transform.iv;
            IntPtr state = transform.state;

            byte[] tempBuffer = transform.tempBuffer;
            int    offset     = outputOffset;
            int    index;

            // Process a left-over block from last time.
            if (transform.tempSize > 0 && inputCount > 0)
            {
                // Decrypt the ciphertext to get the plaintext
                // xor'ed with the IV.
                CryptoMethods.Decrypt(state, tempBuffer, blockSize,
                                      tempBuffer, 0);

                // XOR the IV with the temporary buffer to get plaintext.
                for (index = blockSize - 1; index >= 0; --index)
                {
                    outputBuffer[offset + index] =
                        (byte)(iv[index] ^ tempBuffer[index]);
                }

                // Copy the original ciphertext to the IV.
                Array.Copy(tempBuffer, blockSize, iv, 0, blockSize);

                // Advance to the next block and clear the temporary block.
                offset            += blockSize;
                transform.tempSize = 0;
                for (index = 2 * blockSize - 1; index >= blockSize; --index)
                {
                    tempBuffer[index] = (byte)0x00;
                }
            }

            // Process all of the blocks in the input, minus one.
            while (inputCount > blockSize)
            {
                // Decrypt the ciphertext to get the plaintext
                // xor'ed with the IV.
                CryptoMethods.Decrypt(state, inputBuffer, inputOffset,
                                      tempBuffer, 0);

                // XOR the IV with the temporary buffer to get plaintext.
                for (index = blockSize - 1; index >= 0; --index)
                {
                    outputBuffer[offset + index] =
                        (byte)(iv[index] ^ tempBuffer[index]);
                }

                // Copy the original ciphertext to the IV.
                Array.Copy(inputBuffer, inputOffset, iv, 0, blockSize);

                // Advance to the next block.
                inputOffset += blockSize;
                inputCount  -= blockSize;
                offset      += blockSize;
            }

            // Save the last block for next time.
            if (inputCount > 0)
            {
                Array.Copy(inputBuffer, inputOffset,
                           tempBuffer, blockSize, inputCount);
                transform.tempSize = inputCount;
            }

            // Clear the temporary buffer to protect sensitive data.
            for (index = blockSize - 1; index >= 0; --index)
            {
                tempBuffer[index] = (byte)0x00;
            }

            // Finished.
            return(offset - outputOffset);
        }