3 using SharpCompress.Common.Zip.Headers;
4 using SharpCompress.Compressor.Deflate;
6 namespace SharpCompress.Common.Zip
8 internal class PkwareTraditionalEncryptionData
10 private static readonly CRC32 crc32 = new CRC32();
11 private readonly UInt32[] _Keys = {0x12345678, 0x23456789, 0x34567890};
13 private PkwareTraditionalEncryptionData(string password)
18 private byte MagicByte
22 ushort t = (ushort) ((ushort) (_Keys[2] & 0xFFFF) | 2);
23 return (byte) ((t*(t ^ 1)) >> 8);
27 public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header,
28 byte[] encryptionHeader)
30 var encryptor = new PkwareTraditionalEncryptionData(password);
31 byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length);
32 if (plainTextHeader[11] != (byte) ((header.Crc >> 24) & 0xff))
34 if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor))
36 throw new CryptographicException("The password did not match.");
38 if (plainTextHeader[11] != (byte) ((header.LastModifiedTime >> 8) & 0xff))
40 throw new CryptographicException("The password did not match.");
47 public byte[] Decrypt(byte[] cipherText, int length)
49 if (length > cipherText.Length)
50 throw new ArgumentOutOfRangeException("length",
51 "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array.");
53 var plainText = new byte[length];
54 for (int i = 0; i < length; i++)
56 var C = (byte) (cipherText[i] ^ MagicByte);
63 public byte[] Encrypt(byte[] plainText, int length)
65 if (plainText == null)
66 throw new ArgumentNullException("plaintext");
68 if (length > plainText.Length)
69 throw new ArgumentOutOfRangeException("length",
70 "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array.");
72 var cipherText = new byte[length];
73 for (int i = 0; i < length; i++)
75 byte C = plainText[i];
76 cipherText[i] = (byte) (plainText[i] ^ MagicByte);
82 private void Initialize(string password)
84 byte[] p = StringToByteArray(password);
85 for (int i = 0; i < password.Length; i++)
89 internal static byte[] StringToByteArray(string value, Encoding encoding)
91 byte[] a = encoding.GetBytes(value);
95 internal static byte[] StringToByteArray(string value)
97 return StringToByteArray(value, ArchiveEncoding.Password);
100 private void UpdateKeys(byte byteValue)
102 _Keys[0] = (UInt32) crc32.ComputeCrc32((int) _Keys[0], byteValue);
103 _Keys[1] = _Keys[1] + (byte) _Keys[0];
104 _Keys[1] = _Keys[1]*0x08088405 + 1;
105 _Keys[2] = (UInt32) crc32.ComputeCrc32((int) _Keys[2], (byte) (_Keys[1] >> 24));