PageRenderTime 169ms CodeModel.GetById 43ms app.highlight 61ms RepoModel.GetById 59ms app.codeStats 1ms

/Utilities/Compression/ZipEncryption.cs

#
C# | 559 lines | 334 code | 47 blank | 178 comment | 13 complexity | 120a0de7936c02e3db63173eb7bec096 MD5 | raw file
  1// Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
  2// Authors of the original java version: Jochen Hoenicke, John Leuner
  3// See http://www.ISeeSharpCode.com for more information.
  4
  5using System;
  6using System.Security.Cryptography;
  7using Delta.Utilities.Compression.Checksums;
  8
  9namespace Delta.Utilities.Compression
 10{
 11	/// <summary>
 12	/// ZipEncryptionBase provides the low level facilities for encryption
 13	/// and decryption using the ZipEncryption algorithm.
 14	/// </summary>
 15	internal class ZipEncryptionBase
 16	{
 17		#region Private
 18
 19		#region keys (Private)
 20		/// <summary>
 21		/// Keys
 22		/// </summary>
 23		private uint[] keys;
 24		#endregion
 25
 26		#endregion
 27
 28		#region Methods (Private)
 29
 30		#region TransformByte
 31		/// <summary>
 32		/// Transform a single byte 
 33		/// </summary>
 34		/// <returns>
 35		/// The transformed value
 36		/// </returns>
 37		protected byte TransformByte()
 38		{
 39			uint temp = ((keys[2] & 0xFFFF) | 2);
 40			return (byte)((temp * (temp ^ 1)) >> 8);
 41		}
 42		#endregion
 43
 44		// TransformByte()
 45
 46		#region SetKeys
 47		/// <summary>
 48		/// Set keys
 49		/// </summary>
 50		/// <param name="keyData">Key data</param>
 51		protected void SetKeys(byte[] keyData)
 52		{
 53			if (keyData == null)
 54			{
 55				throw new ArgumentNullException("keyData");
 56			} // if (keyData)
 57
 58			if (keyData.Length != 12)
 59			{
 60				throw new InvalidOperationException("Keys not valid");
 61			} // if (keyData.Length)
 62
 63			keys = new uint[3];
 64			keys[0] = (uint)((keyData[3] << 24) |
 65			                 (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
 66			keys[1] = (uint)((keyData[7] << 24) |
 67			                 (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
 68			keys[2] = (uint)((keyData[11] << 24) |
 69			                 (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
 70		}
 71		#endregion
 72
 73		// SetKeys(keyData)
 74
 75		#region UpdateKeys
 76		/// <summary>
 77		/// Update encryption keys 
 78		/// </summary>		
 79		protected void UpdateKeys(byte ch)
 80		{
 81			keys[0] = Crc32.ComputeCrc32(keys[0], ch);
 82			keys[1] = keys[1] + (byte)keys[0];
 83			keys[1] = keys[1] * 134775813 + 1;
 84			keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
 85		}
 86		#endregion
 87
 88		// UpdateKeys()
 89
 90		#region Reset
 91		/// <summary>
 92		/// Reset the internal state.
 93		/// </summary>
 94		protected void Reset()
 95		{
 96			keys[0] = 0;
 97			keys[1] = 0;
 98			keys[2] = 0;
 99		}
100		#endregion
101
102		#endregion
103	}
104
105	/// <summary>
106	/// ZipEncryption CryptoTransform for encryption.
107	/// </summary>
108	internal class ZipEncryptionTransform
109		: ZipEncryptionBase, ICryptoTransform
110	{
111		#region CanReuseTransform (Public)
112		/// <summary>
113		/// Gets a value indicating whether the current transform can be reused.
114		/// </summary>
115		public bool CanReuseTransform
116		{
117			get
118			{
119				return true;
120			} // get
121		}
122		#endregion
123
124		#region InputBlockSize (Public)
125		/// <summary>
126		/// Gets the size of the input data blocks in bytes.
127		/// </summary>
128		public int InputBlockSize
129		{
130			get
131			{
132				return 1;
133			} // get
134		}
135		#endregion
136
137		#region OutputBlockSize (Public)
138		/// <summary>
139		/// Gets the size of the output data blocks in bytes.
140		/// </summary>
141		public int OutputBlockSize
142		{
143			get
144			{
145				return 1;
146			} // get
147		}
148		#endregion
149
150		#region CanTransformMultipleBlocks (Public)
151		/// <summary>
152		/// Gets a value indicating whether multiple blocks can be transformed.
153		/// </summary>
154		public bool CanTransformMultipleBlocks
155		{
156			get
157			{
158				return true;
159			} // get
160		}
161		#endregion
162
163		#region Constructors
164		/// <summary>
165		/// Initialise a new instance of
166		/// <see cref="ZipEncryptionTransform"></see>
167		/// </summary>
168		/// <param name="keyBlock">The key block to use.</param>
169		internal ZipEncryptionTransform(byte[] keyBlock)
170		{
171			SetKeys(keyBlock);
172		}
173		#endregion
174
175		#region ICryptoTransform Members
176		/// <summary>
177		/// Transforms the specified region of the input byte array and copies 
178		/// the resulting transform to the specified region of the output byte
179		/// array.
180		/// </summary>
181		/// <param name="inputBuffer">The input for which to compute the transform.
182		/// </param>
183		/// <param name="inputOffset">The offset into the input byte array from
184		/// which to begin using data.</param>
185		/// <param name="inputCount">The number of bytes in the input byte array to
186		/// use as data.</param>
187		/// <param name="outputBuffer">The output to which to write the transform.
188		/// </param>
189		/// <param name="outputOffset">The offset into the output byte array from
190		/// which to begin writing data.</param>
191		/// <returns>The number of bytes written.</returns>
192		public int TransformBlock(byte[] inputBuffer, int inputOffset,
193			int inputCount, byte[] outputBuffer, int outputOffset)
194		{
195			for (int i = inputOffset; i < inputOffset + inputCount; ++i)
196			{
197				byte oldbyte = inputBuffer[i];
198				outputBuffer[outputOffset++] =
199					(byte)(inputBuffer[i] ^ TransformByte());
200				UpdateKeys(oldbyte);
201			} // for (int)
202			return inputCount;
203		}
204
205		/// <summary>
206		/// Transforms the specified region of the specified byte array.
207		/// </summary>
208		/// <param name="inputBuffer">
209		/// The input for which to compute the transform.
210		/// </param>
211		/// <param name="inputOffset">
212		/// The offset into the byte array from which to begin using data.
213		/// </param>
214		/// <param name="inputCount">
215		/// The number of bytes in the byte array to use as data.
216		/// </param>
217		/// <returns>The computed transform.</returns>
218		public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset,
219			int inputCount)
220		{
221			byte[] result = new byte[inputCount];
222			TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
223			return result;
224		}
225		#endregion
226
227		#region IDisposable Members
228		/// <summary>
229		/// Cleanup internal state.
230		/// </summary>
231		public void Dispose()
232		{
233			Reset();
234		}
235		#endregion
236	}
237
238	/// <summary>
239	/// ZipEncryption CryptoTransform for decryption.
240	/// </summary>
241	internal class ZipDecryptionTransform
242		: ZipEncryptionBase, ICryptoTransform
243	{
244		#region CanReuseTransform (Public)
245		/// <summary>
246		/// Gets a value indicating whether the current transform can be reused.
247		/// </summary>
248		public bool CanReuseTransform
249		{
250			get
251			{
252				return true;
253			} // get
254		}
255		#endregion
256
257		#region InputBlockSize (Public)
258		/// <summary>
259		/// Gets the size of the input data blocks in bytes.
260		/// </summary>
261		public int InputBlockSize
262		{
263			get
264			{
265				return 1;
266			} // get
267		}
268		#endregion
269
270		#region OutputBlockSize (Public)
271		/// <summary>
272		/// Gets the size of the output data blocks in bytes.
273		/// </summary>
274		public int OutputBlockSize
275		{
276			get
277			{
278				return 1;
279			} // get
280		}
281		#endregion
282
283		#region CanTransformMultipleBlocks (Public)
284		/// <summary>
285		/// Gets a value indicating whether multiple blocks can be transformed.
286		/// </summary>
287		public bool CanTransformMultipleBlocks
288		{
289			get
290			{
291				return true;
292			} // get
293		}
294		#endregion
295
296		#region Constructors
297		/// <summary>
298		/// Initialise a new instance of
299		/// <see cref="ZipDecryptionTransform"></see>.
300		/// </summary>
301		/// <param name="keyBlock">The key block to decrypt with.</param>
302		internal ZipDecryptionTransform(byte[] keyBlock)
303		{
304			SetKeys(keyBlock);
305		}
306		#endregion
307
308		#region ICryptoTransform Members
309		/// <summary>
310		/// Transforms the specified region of the input byte array and copies 
311		/// the resulting transform to the specified region of the output byte
312		/// array.
313		/// </summary>
314		/// <param name="inputBuffer">The input for which to compute the transform.
315		/// </param>
316		/// <param name="inputOffset">The offset into the input byte array from
317		/// which to begin using data.</param>
318		/// <param name="inputCount">The number of bytes in the input byte array 
319		/// to use as data.</param>
320		/// <param name="outputBuffer">The output to which to write the transform.
321		/// </param>
322		/// <param name="outputOffset">The offset into the output byte array from
323		/// which to begin writing data.</param>
324		/// <returns>The number of bytes written.</returns>
325		public int TransformBlock(byte[] inputBuffer, int inputOffset,
326			int inputCount, byte[] outputBuffer, int outputOffset)
327		{
328			for (int i = inputOffset; i < inputOffset + inputCount; ++i)
329			{
330				byte newByte = (byte)(inputBuffer[i] ^ TransformByte());
331				outputBuffer[outputOffset++] = newByte;
332				UpdateKeys(newByte);
333			} // for (int)
334			return inputCount;
335		}
336
337		/// <summary>
338		/// Transforms the specified region of the specified byte array.
339		/// </summary>
340		/// <param name="inputBuffer">The input for which to compute the transform.
341		/// </param>
342		/// <param name="inputOffset">The offset into the byte array from which to
343		/// begin using data.</param>
344		/// <param name="inputCount">The number of bytes in the byte array to use
345		/// as data.</param>
346		/// <returns>The computed transform.</returns>
347		public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset,
348			int inputCount)
349		{
350			byte[] result = new byte[inputCount];
351			TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
352			return result;
353		}
354		#endregion
355
356		#region IDisposable Members
357		/// <summary>
358		/// Cleanup internal state.
359		/// </summary>
360		public void Dispose()
361		{
362			Reset();
363		}
364		#endregion
365	}
366
367	/// <summary>
368	/// ZipEncryption embodies the classic or original encryption facilities used
369	/// in Pkzip archives. While it has been superceded by more recent and more
370	/// powerful algorithms, its still in use and is viable for preventing casual
371	/// snooping.
372	/// </summary>
373	public abstract class ZipEncryption : SymmetricAlgorithm
374	{
375		#region GenerateKeys (Static)
376		/// <summary>
377		/// Generates new encryption keys based on given seed
378		/// </summary>
379		public static byte[] GenerateKeys(byte[] seed)
380		{
381			if (seed == null)
382			{
383				throw new ArgumentNullException("seed");
384			} // if (seed)
385
386			if (seed.Length == 0)
387			{
388				throw new ArgumentException("seed");
389			} // if (seed.Length)
390
391			uint[] newKeys = new uint[]
392			{
393				0x12345678,
394				0x23456789,
395				0x34567890
396			};
397
398			for (int i = 0; i < seed.Length; ++i)
399			{
400				newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
401				newKeys[1] = newKeys[1] + (byte)newKeys[0];
402				newKeys[1] = newKeys[1] * 134775813 + 1;
403				newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
404			} // for (int)
405
406			byte[] result = new byte[12];
407			result[0] = (byte)(newKeys[0] & 0xff);
408			result[1] = (byte)((newKeys[0] >> 8) & 0xff);
409			result[2] = (byte)((newKeys[0] >> 16) & 0xff);
410			result[3] = (byte)((newKeys[0] >> 24) & 0xff);
411			result[4] = (byte)(newKeys[1] & 0xff);
412			result[5] = (byte)((newKeys[1] >> 8) & 0xff);
413			result[6] = (byte)((newKeys[1] >> 16) & 0xff);
414			result[7] = (byte)((newKeys[1] >> 24) & 0xff);
415			result[8] = (byte)(newKeys[2] & 0xff);
416			result[9] = (byte)((newKeys[2] >> 8) & 0xff);
417			result[10] = (byte)((newKeys[2] >> 16) & 0xff);
418			result[11] = (byte)((newKeys[2] >> 24) & 0xff);
419			return result;
420		}
421		#endregion
422	}
423
424	/// <summary>
425	/// Defines a wrapper object to access the Pkzip algorithm. 
426	/// This class cannot be inherited.
427	/// </summary>
428	public sealed class ZipEncryptionManaged : ZipEncryption
429	{
430		#region BlockSize (Public)
431		/// <summary>
432		/// Get / set the applicable block size.
433		/// </summary>
434		/// <remarks>The only valid block size is 8.</remarks>
435		public override int BlockSize
436		{
437			get
438			{
439				return 8;
440			} // get
441			set
442			{
443				if (value != 8)
444				{
445					throw new CryptographicException();
446				}
447			} // set
448		}
449		#endregion
450
451		#region LegalKeySizes (Public)
452		/// <summary>
453		/// Get an array of legal <see cref="KeySizes">key sizes.</see>
454		/// </summary>
455		public override KeySizes[] LegalKeySizes
456		{
457			get
458			{
459				KeySizes[] keySizes = new KeySizes[1];
460				keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
461				return keySizes;
462			} // get
463		}
464		#endregion
465
466		#region LegalBlockSizes (Public)
467		/// <summary>
468		/// Get an array of legal <see cref="KeySizes">block sizes</see>.
469		/// </summary>
470		public override KeySizes[] LegalBlockSizes
471		{
472			get
473			{
474				KeySizes[] keySizes = new KeySizes[1];
475				keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
476				return keySizes;
477			} // get
478		}
479		#endregion
480
481		#region Key (Public)
482		/// <summary>
483		/// Get / set the key value applicable.
484		/// </summary>
485		public override byte[] Key
486		{
487			get
488			{
489				return key;
490			} // get
491			set
492			{
493				key = value;
494			} // set
495		}
496		#endregion
497
498		#region Private
499
500		#region key (Private)
501		/// <summary>
502		/// Key
503		/// </summary>
504		private byte[] key;
505		#endregion
506
507		#endregion
508
509		#region GenerateIV (Public)
510		/// <summary>
511		/// Generate an initial vector.
512		/// </summary>
513		public override void GenerateIV()
514		{
515			// Do nothing.
516		}
517		#endregion
518
519		#region GenerateKey (Public)
520		/// <summary>
521		/// Generate a new random key.
522		/// </summary>
523		public override void GenerateKey()
524		{
525			key = new byte[12];
526			Random rnd = new Random();
527			rnd.NextBytes(key);
528		}
529		#endregion
530
531		#region CreateEncryptor (Public)
532		/// <summary>
533		/// Create an encryptor.
534		/// </summary>
535		/// <param name="rgbKey">The key to use for this encryptor.</param>
536		/// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
537		/// <returns>Returns a new ZipEncryption encryptor</returns>
538		public override ICryptoTransform CreateEncryptor(
539			byte[] rgbKey, byte[] rgbIV)
540		{
541			return new ZipEncryptionTransform(rgbKey);
542		}
543		#endregion
544
545		#region CreateDecryptor (Public)
546		/// <summary>
547		/// Create a decryptor.
548		/// </summary>
549		/// <param name="rgbKey">Keys to use for this new decryptor.</param>
550		/// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
551		/// <returns>Returns a new decryptor.</returns>
552		public override ICryptoTransform CreateDecryptor(
553			byte[] rgbKey, byte[] rgbIV)
554		{
555			return new ZipDecryptionTransform(rgbKey);
556		}
557		#endregion
558	}
559}