| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 | 
							- using System;
 
- using System.Security.Cryptography;
 
- namespace ICSharpCode.SharpZipLib.Encryption
 
- {
 
- 	/// <summary>
 
- 	/// Transforms stream using AES in CTR mode
 
- 	/// </summary>
 
- 	internal class ZipAESTransform : ICryptoTransform
 
- 	{
 
- 		class IncrementalHash : HMACSHA1
 
- 		{
 
- 			bool _finalised;
 
- 			public IncrementalHash(byte[] key) : base(key) { }
 
- 			public static IncrementalHash CreateHMAC(string n, byte[] key)
 
- 			{
 
- 				return new IncrementalHash(key);
 
- 			}
 
- 			public void AppendData(byte[] buffer, int offset, int count)
 
- 			{
 
- 				TransformBlock(buffer, offset, count, buffer, offset);
 
- 			}
 
- 			public byte[] GetHashAndReset()
 
- 			{
 
- 				if (!_finalised)
 
- 				{
 
- 					byte[] dummy = new byte[0];
 
- 					TransformFinalBlock(dummy, 0, 0);
 
- 					_finalised = true;
 
- 				}
 
- 				return Hash;
 
- 			}
 
- 		}
 
- 		static class HashAlgorithmName
 
- 		{
 
- 			public static string SHA1 = null;
 
- 		}
 
- 		private const int PWD_VER_LENGTH = 2;
 
- 		// WinZip use iteration count of 1000 for PBKDF2 key generation
 
- 		private const int KEY_ROUNDS = 1000;
 
- 		// For 128-bit AES (16 bytes) the encryption is implemented as expected.
 
- 		// For 256-bit AES (32 bytes) WinZip do full 256 bit AES of the nonce to create the encryption
 
- 		// block but use only the first 16 bytes of it, and discard the second half.
 
- 		private const int ENCRYPT_BLOCK = 16;
 
- 		private int _blockSize;
 
- 		private readonly ICryptoTransform _encryptor;
 
- 		private readonly byte[] _counterNonce;
 
- 		private byte[] _encryptBuffer;
 
- 		private int _encrPos;
 
- 		private byte[] _pwdVerifier;
 
- 		private IncrementalHash _hmacsha1;
 
- 		private byte[] _authCode = null;
 
- 		private bool _writeMode;
 
- 		/// <summary>
 
- 		/// Constructor.
 
- 		/// </summary>
 
- 		/// <param name="key">Password string</param>
 
- 		/// <param name="saltBytes">Random bytes, length depends on encryption strength.
 
- 		/// 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.</param>
 
- 		/// <param name="blockSize">The encryption strength, in bytes eg 16 for 128 bits.</param>
 
- 		/// <param name="writeMode">True when creating a zip, false when reading. For the AuthCode.</param>
 
- 		///
 
- 		public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode)
 
- 		{
 
- 			if (blockSize != 16 && blockSize != 32) // 24 valid for AES but not supported by Winzip
 
- 				throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32.");
 
- 			if (saltBytes.Length != blockSize / 2)
 
- 				throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);
 
- 			// initialise the encryption buffer and buffer pos
 
- 			_blockSize = blockSize;
 
- 			_encryptBuffer = new byte[_blockSize];
 
- 			_encrPos = ENCRYPT_BLOCK;
 
- 			// Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c
 
- 			var pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS);
 
-             var rm = Aes.Create();
 
- 			rm.Mode = CipherMode.ECB;           // No feedback from cipher for CTR mode
 
- 			_counterNonce = new byte[_blockSize];
 
- 			byte[] byteKey1 = pdb.GetBytes(_blockSize);
 
- 			byte[] byteKey2 = pdb.GetBytes(_blockSize);
 
- 			_encryptor = rm.CreateEncryptor(byteKey1, byteKey2);
 
- 			_pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);
 
- 			//
 
- 			_hmacsha1 = IncrementalHash.CreateHMAC(HashAlgorithmName.SHA1, byteKey2);
 
- 			_writeMode = writeMode;
 
- 		}
 
- 		/// <summary>
 
- 		/// Implement the ICryptoTransform method.
 
- 		/// </summary>
 
- 		public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
 
- 		{
 
- 			// Pass the data stream to the hash algorithm for generating the Auth Code.
 
- 			// This does not change the inputBuffer. Do this before decryption for read mode.
 
- 			if (!_writeMode) {
 
- 				_hmacsha1.AppendData(inputBuffer, inputOffset, inputCount);
 
- 			}
 
- 			// Encrypt with AES in CTR mode. Regards to Dr Brian Gladman for this.
 
- 			int ix = 0;
 
- 			while (ix < inputCount) {
 
- 				if (_encrPos == ENCRYPT_BLOCK) {
 
- 					/* increment encryption nonce   */
 
- 					int j = 0;
 
- 					while (++_counterNonce[j] == 0) {
 
- 						++j;
 
- 					}
 
- 					/* encrypt the nonce to form next xor buffer    */
 
- 					_encryptor.TransformBlock(_counterNonce, 0, _blockSize, _encryptBuffer, 0);
 
- 					_encrPos = 0;
 
- 				}
 
- 				outputBuffer[ix + outputOffset] = (byte)(inputBuffer[ix + inputOffset] ^ _encryptBuffer[_encrPos++]);
 
- 				//
 
- 				ix++;
 
- 			}
 
- 			if (_writeMode) {
 
- 				// This does not change the buffer.
 
- 				_hmacsha1.AppendData(outputBuffer, outputOffset, inputCount);
 
- 			}
 
- 			return inputCount;
 
- 		}
 
- 		/// <summary>
 
- 		/// Returns the 2 byte password verifier
 
- 		/// </summary>
 
- 		public byte[] PwdVerifier {
 
- 			get {
 
- 				return _pwdVerifier;
 
- 			}
 
- 		}
 
- 		/// <summary>
 
- 		/// Returns the 10 byte AUTH CODE to be checked or appended immediately following the AES data stream.
 
- 		/// </summary>
 
- 		public byte[] GetAuthCode()
 
- 		{
 
- 			if (_authCode == null)
 
- 			{
 
- 				_authCode = _hmacsha1.GetHashAndReset();
 
- 			}
 
- 			return _authCode;
 
- 		}
 
- #region ICryptoTransform Members
 
- 		/// <summary>
 
- 		/// Not implemented.
 
- 		/// </summary>
 
- 		public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 
- 		{
 
- 			throw new NotImplementedException("ZipAESTransform.TransformFinalBlock");
 
- 		}
 
- 		/// <summary>
 
- 		/// Gets the size of the input data blocks in bytes.
 
- 		/// </summary>
 
- 		public int InputBlockSize {
 
- 			get {
 
- 				return _blockSize;
 
- 			}
 
- 		}
 
- 		/// <summary>
 
- 		/// Gets the size of the output data blocks in bytes.
 
- 		/// </summary>
 
- 		public int OutputBlockSize {
 
- 			get {
 
- 				return _blockSize;
 
- 			}
 
- 		}
 
- 		/// <summary>
 
- 		/// Gets a value indicating whether multiple blocks can be transformed.
 
- 		/// </summary>
 
- 		public bool CanTransformMultipleBlocks {
 
- 			get {
 
- 				return true;
 
- 			}
 
- 		}
 
- 		/// <summary>
 
- 		/// Gets a value indicating whether the current transform can be reused.
 
- 		/// </summary>
 
- 		public bool CanReuseTransform {
 
- 			get {
 
- 				return true;
 
- 			}
 
- 		}
 
- 		/// <summary>
 
- 		/// Cleanup internal state.
 
- 		/// </summary>
 
- 		public void Dispose()
 
- 		{
 
- 			_encryptor.Dispose();
 
- 		}
 
- #endregion
 
- 	}
 
- }
 
 
  |