root/trunk/Updater/ICSharpCode.SharpZipLib/Encryption/PkzipClassic.cs @ 597

Wersja 597, 14.4 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
1//
2// PkzipClassic encryption
3//
4// Copyright 2004 John Reilly
5//
6// This program is free software; you can redistribute it and/or
7// modify it under the terms of the GNU General Public License
8// as published by the Free Software Foundation; either version 2
9// of the License, or (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19//
20// Linking this library statically or dynamically with other modules is
21// making a combined work based on this library.  Thus, the terms and
22// conditions of the GNU General Public License cover the whole
23// combination.
24//
25// As a special exception, the copyright holders of this library give you
26// permission to link this library with independent modules to produce an
27// executable, regardless of the license terms of these independent
28// modules, and to copy and distribute the resulting executable under
29// terms of your choice, provided that you also meet, for each linked
30// independent module, the terms and conditions of the license of that
31// module.  An independent module is a module which is not derived from
32// or based on this library.  If you modify this library, you may extend
33// this exception to your version of the library, but you are not
34// obligated to do so.  If you do not wish to do so, delete this
35// exception statement from your version.
36//
37
38
39#if !NETCF_1_0
40
41using System;
42using System.Security.Cryptography;
43using ICSharpCode.SharpZipLib.Checksums;
44
45namespace ICSharpCode.SharpZipLib.Encryption
46{
47        /// <summary>
48        /// PkzipClassic embodies the classic or original encryption facilities used in Pkzip archives.
49        /// While it has been superceded by more recent and more powerful algorithms, its still in use and
50        /// is viable for preventing casual snooping
51        /// </summary>
52        public abstract class PkzipClassic : SymmetricAlgorithm
53        {
54                /// <summary>
55                /// Generates new encryption keys based on given seed
56                /// </summary>
57                /// <param name="seed">The seed value to initialise keys with.</param>
58                /// <returns>A new key value.</returns>
59                static public byte[] GenerateKeys(byte[] seed)
60                {
61                        if ( seed == null ) {
62                                throw new ArgumentNullException("seed");
63                        }
64
65                        if ( seed.Length == 0 ) {
66                                throw new ArgumentException("Length is zero", "seed");
67                        }
68
69                        uint[] newKeys = new uint[] {
70                                0x12345678,
71                                0x23456789,
72                                0x34567890
73                         };
74                       
75                        for (int i = 0; i < seed.Length; ++i) {
76                                newKeys[0] = Crc32.ComputeCrc32(newKeys[0], seed[i]);
77                                newKeys[1] = newKeys[1] + (byte)newKeys[0];
78                                newKeys[1] = newKeys[1] * 134775813 + 1;
79                                newKeys[2] = Crc32.ComputeCrc32(newKeys[2], (byte)(newKeys[1] >> 24));
80                        }
81
82                        byte[] result = new byte[12];
83                        result[0] = (byte)(newKeys[0] & 0xff);
84                        result[1] = (byte)((newKeys[0] >> 8) & 0xff);
85                        result[2] = (byte)((newKeys[0] >> 16) & 0xff);
86                        result[3] = (byte)((newKeys[0] >> 24) & 0xff);
87                        result[4] = (byte)(newKeys[1] & 0xff);
88                        result[5] = (byte)((newKeys[1] >> 8) & 0xff);
89                        result[6] = (byte)((newKeys[1] >> 16) & 0xff);
90                        result[7] = (byte)((newKeys[1] >> 24) & 0xff);
91                        result[8] = (byte)(newKeys[2] & 0xff);
92                        result[9] = (byte)((newKeys[2] >> 8) & 0xff);
93                        result[10] = (byte)((newKeys[2] >> 16) & 0xff);
94                        result[11] = (byte)((newKeys[2] >> 24) & 0xff);
95                        return result;
96                }
97        }
98
99        /// <summary>
100        /// PkzipClassicCryptoBase provides the low level facilities for encryption
101        /// and decryption using the PkzipClassic algorithm.
102        /// </summary>
103        class PkzipClassicCryptoBase
104        {
105                /// <summary>
106                /// Transform a single byte
107                /// </summary>
108                /// <returns>
109                /// The transformed value
110                /// </returns>
111                protected byte TransformByte()
112                {
113                        uint temp = ((keys[2] & 0xFFFF) | 2);
114                        return (byte)((temp * (temp ^ 1)) >> 8);
115                }
116
117                /// <summary>
118                /// Set the key schedule for encryption/decryption.
119                /// </summary>
120                /// <param name="keyData">The data use to set the keys from.</param>
121                protected void SetKeys(byte[] keyData)
122                {
123                        if ( keyData == null ) {
124                                throw new ArgumentNullException("keyData");
125                        }
126               
127                        if ( keyData.Length != 12 ) {
128                                throw new InvalidOperationException("Key length is not valid");
129                        }
130                       
131                        keys = new uint[3];
132                        keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]);
133                        keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]);
134                        keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]);
135                }
136
137                /// <summary>
138                /// Update encryption keys
139                /// </summary>         
140                protected void UpdateKeys(byte ch)
141                {
142                        keys[0] = Crc32.ComputeCrc32(keys[0], ch);
143                        keys[1] = keys[1] + (byte)keys[0];
144                        keys[1] = keys[1] * 134775813 + 1;
145                        keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
146                }
147
148                /// <summary>
149                /// Reset the internal state.
150                /// </summary>
151                protected void Reset()
152                {
153                        keys[0] = 0;
154                        keys[1] = 0;
155                        keys[2] = 0;
156                }
157               
158                #region Instance Fields
159                uint[] keys;
160                #endregion
161        }
162
163        /// <summary>
164        /// PkzipClassic CryptoTransform for encryption.
165        /// </summary>
166        class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
167        {
168                /// <summary>
169                /// Initialise a new instance of <see cref="PkzipClassicEncryptCryptoTransform"></see>
170                /// </summary>
171                /// <param name="keyBlock">The key block to use.</param>
172                internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock)
173                {
174                        SetKeys(keyBlock);
175                }
176
177                #region ICryptoTransform Members
178
179                /// <summary>
180                /// Transforms the specified region of the specified byte array.
181                /// </summary>
182                /// <param name="inputBuffer">The input for which to compute the transform.</param>
183                /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
184                /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
185                /// <returns>The computed transform.</returns>
186                public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
187                {
188                        byte[] result = new byte[inputCount];
189                        TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
190                        return result;
191                }
192
193                /// <summary>
194                /// Transforms the specified region of the input byte array and copies
195                /// the resulting transform to the specified region of the output byte array.
196                /// </summary>
197                /// <param name="inputBuffer">The input for which to compute the transform.</param>
198                /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
199                /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
200                /// <param name="outputBuffer">The output to which to write the transform.</param>
201                /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
202                /// <returns>The number of bytes written.</returns>
203                public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
204                {
205                        for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
206                                byte oldbyte = inputBuffer[i];
207                                outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte());
208                                UpdateKeys(oldbyte);
209                        }
210                        return inputCount;
211                }
212
213                /// <summary>
214                /// Gets a value indicating whether the current transform can be reused.
215                /// </summary>
216                public bool CanReuseTransform
217                {
218                        get {
219                                return true;
220                        }
221                }
222
223                /// <summary>
224                /// Gets the size of the input data blocks in bytes.
225                /// </summary>
226                public int InputBlockSize
227                {
228                        get {
229                                return 1;
230                        }
231                }
232
233                /// <summary>
234                /// Gets the size of the output data blocks in bytes.
235                /// </summary>
236                public int OutputBlockSize
237                {
238                        get {
239                                return 1;
240                        }
241                }
242
243                /// <summary>
244                /// Gets a value indicating whether multiple blocks can be transformed.
245                /// </summary>
246                public bool CanTransformMultipleBlocks
247                {
248                        get {
249                                return true;
250                        }
251                }
252
253                #endregion
254
255                #region IDisposable Members
256
257                /// <summary>
258                /// Cleanup internal state.
259                /// </summary>
260                public void Dispose()
261                {
262                        Reset();
263                }
264
265                #endregion
266        }
267
268
269        /// <summary>
270        /// PkzipClassic CryptoTransform for decryption.
271        /// </summary>
272        class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform
273        {
274                /// <summary>
275                /// Initialise a new instance of <see cref="PkzipClassicDecryptCryptoTransform"></see>.
276                /// </summary>
277                /// <param name="keyBlock">The key block to decrypt with.</param>
278                internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock)
279                {
280                        SetKeys(keyBlock);
281                }
282
283                #region ICryptoTransform Members
284
285                /// <summary>
286                /// Transforms the specified region of the specified byte array.
287                /// </summary>
288                /// <param name="inputBuffer">The input for which to compute the transform.</param>
289                /// <param name="inputOffset">The offset into the byte array from which to begin using data.</param>
290                /// <param name="inputCount">The number of bytes in the byte array to use as data.</param>
291                /// <returns>The computed transform.</returns>
292                public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
293                {
294                        byte[] result = new byte[inputCount];
295                        TransformBlock(inputBuffer, inputOffset, inputCount, result, 0);
296                        return result;
297                }
298
299                /// <summary>
300                /// Transforms the specified region of the input byte array and copies
301                /// the resulting transform to the specified region of the output byte array.
302                /// </summary>
303                /// <param name="inputBuffer">The input for which to compute the transform.</param>
304                /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
305                /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
306                /// <param name="outputBuffer">The output to which to write the transform.</param>
307                /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
308                /// <returns>The number of bytes written.</returns>
309                public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
310                {
311                        for (int i = inputOffset; i < inputOffset + inputCount; ++i) {
312                                byte newByte = (byte)(inputBuffer[i] ^ TransformByte());
313                                outputBuffer[outputOffset++] = newByte;
314                                UpdateKeys(newByte);
315                        }
316                        return inputCount;
317                }
318
319                /// <summary>
320                /// Gets a value indicating whether the current transform can be reused.
321                /// </summary>
322                public bool CanReuseTransform
323                {
324                        get {
325                                return true;
326                        }
327                }
328
329                /// <summary>
330                /// Gets the size of the input data blocks in bytes.
331                /// </summary>
332                public int InputBlockSize
333                {
334                        get {
335                                return 1;
336                        }
337                }
338
339                /// <summary>
340                /// Gets the size of the output data blocks in bytes.
341                /// </summary>
342                public int OutputBlockSize
343                {
344                        get {
345                                return 1;
346                        }
347                }
348
349                /// <summary>
350                /// Gets a value indicating whether multiple blocks can be transformed.
351                /// </summary>
352                public bool CanTransformMultipleBlocks
353                {
354                        get {
355                                return true;
356                        }
357                }
358
359                #endregion
360
361                #region IDisposable Members
362
363                /// <summary>
364                /// Cleanup internal state.
365                /// </summary>
366                public void Dispose()
367                {
368                        Reset();
369                }
370
371                #endregion
372        }
373
374        /// <summary>
375        /// Defines a wrapper object to access the Pkzip algorithm.
376        /// This class cannot be inherited.
377        /// </summary>
378        public sealed class PkzipClassicManaged : PkzipClassic
379        {
380                /// <summary>
381                /// Get / set the applicable block size in bits.
382                /// </summary>
383                /// <remarks>The only valid block size is 8.</remarks>
384                public override int BlockSize
385                {
386                        get {
387                                return 8;
388                        }
389
390                        set {
391                                if (value != 8) {
392                                        throw new CryptographicException("Block size is invalid");
393                                }
394                        }
395                }
396
397                /// <summary>
398                /// Get an array of legal <see cref="KeySizes">key sizes.</see>
399                /// </summary>
400                public override KeySizes[] LegalKeySizes
401                {
402                        get {
403                                KeySizes[] keySizes = new KeySizes[1];
404                                keySizes[0] = new KeySizes(12 * 8, 12 * 8, 0);
405                                return keySizes;
406                        }
407                }
408
409                /// <summary>
410                /// Generate an initial vector.
411                /// </summary>
412                public override void GenerateIV()
413                {
414                        // Do nothing.
415                }
416
417                /// <summary>
418                /// Get an array of legal <see cref="KeySizes">block sizes</see>.
419                /// </summary>
420                public override KeySizes[] LegalBlockSizes
421                {
422                        get {
423                                KeySizes[] keySizes = new KeySizes[1];
424                                keySizes[0] = new KeySizes(1 * 8, 1 * 8, 0);
425                                return keySizes;
426                        }
427                }
428
429                /// <summary>
430                /// Get / set the key value applicable.
431                /// </summary>
432                public override byte[] Key
433                {
434                        get {
435                                if ( key_ == null ) {
436                                        GenerateKey();
437                                }
438                               
439                                return (byte[]) key_.Clone();
440                        }
441               
442                        set {
443                                if ( value == null ) {
444                                        throw new ArgumentNullException("value");
445                                }
446                               
447                                if ( value.Length != 12 ) {
448                                        throw new CryptographicException("Key size is illegal");
449                                }
450                               
451                                key_ = (byte[]) value.Clone();
452                        }
453                }
454
455                /// <summary>
456                /// Generate a new random key.
457                /// </summary>
458                public override void GenerateKey()
459                {
460                        key_ = new byte[12];
461                        Random rnd = new Random();
462                        rnd.NextBytes(key_);
463                }
464
465                /// <summary>
466                /// Create an encryptor.
467                /// </summary>
468                /// <param name="rgbKey">The key to use for this encryptor.</param>
469                /// <param name="rgbIV">Initialisation vector for the new encryptor.</param>
470                /// <returns>Returns a new PkzipClassic encryptor</returns>
471                public override ICryptoTransform CreateEncryptor(
472                        byte[] rgbKey,
473                        byte[] rgbIV)
474                {
475                        key_ = rgbKey;
476                        return new PkzipClassicEncryptCryptoTransform(Key);
477                }
478
479                /// <summary>
480                /// Create a decryptor.
481                /// </summary>
482                /// <param name="rgbKey">Keys to use for this new decryptor.</param>
483                /// <param name="rgbIV">Initialisation vector for the new decryptor.</param>
484                /// <returns>Returns a new decryptor.</returns>
485                public override ICryptoTransform CreateDecryptor(
486                        byte[] rgbKey,
487                        byte[] rgbIV)
488                {
489                        key_ = rgbKey;
490                        return new PkzipClassicDecryptCryptoTransform(Key);
491                }
492               
493                #region Instance Fields
494                byte[] key_;
495                #endregion
496        }
497}
498#endif
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.