PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Compression/ZipEncryption.cs

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