// 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; int index; // Process all of the blocks in the input. while (inputCount >= blockSize) { // XOR the plaintext with the IV. for (index = blockSize - 1; index >= 0; --index) { iv[index] ^= inputBuffer[inputOffset + index]; } // Encrypt the IV to get the ciphertext and the next IV. CryptoMethods.Encrypt(state, iv, 0, iv, 0); Array.Copy(iv, 0, outputBuffer, offset, blockSize); // Advance to the next block. inputOffset += blockSize; inputCount -= blockSize; offset += blockSize; } // Finished. return(offset - outputOffset); }
// 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) { // XOR the plaintext with the IV. for (index = blockSize - 1; index >= 0; --index) { iv[index] ^= tempBuffer[index]; } // Encrypt the IV to get the ciphertext and the next IV. CryptoMethods.Encrypt(state, iv, 0, iv, 0); Array.Copy(iv, 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, tempBuffer, 0, blockSize); tempSize -= blockSize; } // Copy the next block into the temporary buffer. Array.Copy(inputBuffer, inputOffset, tempBuffer, tempSize, blockSize); inputOffset += blockSize; inputCount -= blockSize; tempSize += blockSize; } transform.tempSize = tempSize; // Finished. return(offset - outputOffset); }
// 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; int feedbackSize = transform.feedbackBlockSize; byte[] iv = transform.iv; IntPtr state = transform.state; int offset = outputOffset; byte[] tempBuffer = transform.tempBuffer; int tempSize = transform.tempSize; // Process all of the bytes in the input. while (inputCount > 0) { // Encrypt the queue if we need more keystream data. if (tempSize >= feedbackSize) { CryptoMethods.Encrypt(state, tempBuffer, feedbackSize, tempBuffer, 0); tempSize = 0; } // XOR the plaintext byte with the next keystream byte. outputBuffer[offset++] = (byte)(tempBuffer[tempSize] ^ inputBuffer[inputOffset++]); --inputCount; // Feed the keystream byte back into the queue. tempBuffer[tempSize + blockSize] = tempBuffer[tempSize]; ++tempSize; } transform.tempSize = tempSize; // Finished. return(offset - outputOffset); }
// 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; IntPtr state = transform.state; int offset = outputOffset; // Process all of the blocks in the input. while (inputCount >= blockSize) { CryptoMethods.Encrypt(state, inputBuffer, inputOffset, outputBuffer, offset); inputOffset += blockSize; inputCount -= blockSize; offset += blockSize; } // Finished. return(offset - outputOffset); }
// 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); }
// 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; int offset = 0; int size, index, pad; byte[] outputBuffer; // Allocate space for the final block. if (transform.padding == PaddingMode.PKCS7) { size = inputCount + blockSize - (inputCount % blockSize); } else { size = inputCount; if ((size % blockSize) != 0) { size += blockSize - (inputCount % blockSize); } } outputBuffer = new byte [size]; // Process full blocks in the input. while (inputCount >= blockSize) { CryptoMethods.Encrypt(state, inputBuffer, inputOffset, outputBuffer, offset); inputOffset += blockSize; inputCount -= blockSize; offset += blockSize; } // Format and encrypt the final partial block. if (transform.padding == PaddingMode.PKCS7) { // Pad the block according to PKCS #7. for (index = 0; index < inputCount; ++index) { outputBuffer[offset + index] = inputBuffer[inputOffset + index]; } pad = blockSize - (inputCount % blockSize); while (index < blockSize) { outputBuffer[offset + index] = (byte)pad; ++index; } // Encrypt the block. CryptoMethods.Encrypt(state, outputBuffer, offset + index - blockSize, outputBuffer, offset + index - blockSize); } else if (inputCount > 0) { // Pad the block with zero bytes. for (index = 0; index < inputCount; ++index) { outputBuffer[offset + index] = inputBuffer[inputOffset + index]; } while (index < blockSize) { outputBuffer[offset + index] = (byte)0x00; ++index; } // Encrypt the block. CryptoMethods.Encrypt(state, outputBuffer, offset + index - blockSize, outputBuffer, offset + index - blockSize); } // Finished. return(outputBuffer); }
// 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 = 0; int size, pad, index; byte[] outputBuffer; // Allocate space for the final block. if (transform.padding == PaddingMode.PKCS7) { size = inputCount + blockSize - (inputCount % blockSize); } else { size = inputCount; if ((size % blockSize) != 0) { size += blockSize - (inputCount % blockSize); } } outputBuffer = new byte [size]; // Process full blocks in the input. while (inputCount >= blockSize) { // XOR the plaintext with the IV. for (index = blockSize - 1; index >= 0; --index) { iv[index] ^= inputBuffer[inputOffset + index]; } // Encrypt the IV to get the ciphertext and the next IV. CryptoMethods.Encrypt(state, iv, 0, iv, 0); Array.Copy(iv, 0, outputBuffer, offset, blockSize); // Advance to the next block. inputOffset += blockSize; inputCount -= blockSize; offset += blockSize; } // Format and encrypt the final partial block. if (transform.padding == PaddingMode.PKCS7) { // Pad the block according to PKCS #7 and XOR with the IV. for (index = 0; index < inputCount; ++index) { iv[index] ^= inputBuffer[inputOffset + index]; } pad = blockSize - (inputCount % blockSize); while (index < blockSize) { iv[index] ^= (byte)pad; ++index; } // Encrypt the IV to get the ciphertext and the next IV. CryptoMethods.Encrypt(state, iv, 0, iv, 0); Array.Copy(iv, 0, outputBuffer, offset, blockSize); } else if (inputCount > 0) { // Pad the block with zero bytes and XOR with the IV. // The zero padding is implicit. for (index = 0; index < inputCount; ++index) { iv[index] ^= inputBuffer[inputOffset + index]; } // Encrypt the IV to get the ciphertext and the next IV. CryptoMethods.Encrypt(state, iv, 0, iv, 0); Array.Copy(iv, 0, outputBuffer, offset, blockSize); } // Finished. return(outputBuffer); }