File: PkwareTraditionalEncryptionData.cs

package info (click to toggle)
mono-reference-assemblies 3.12.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 604,240 kB
  • ctags: 625,505
  • sloc: cs: 3,967,741; xml: 2,793,081; ansic: 418,042; java: 60,435; sh: 14,833; makefile: 11,576; sql: 7,956; perl: 1,467; cpp: 1,446; yacc: 1,203; python: 598; asm: 422; sed: 16; php: 1
file content (108 lines) | stat: -rw-r--r-- 3,908 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
using System;
using System.Text;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressor.Deflate;

namespace SharpCompress.Common.Zip
{
    internal class PkwareTraditionalEncryptionData
    {
        private static readonly CRC32 crc32 = new CRC32();
        private readonly UInt32[] _Keys = {0x12345678, 0x23456789, 0x34567890};

        private PkwareTraditionalEncryptionData(string password)
        {
            Initialize(password);
        }

        private byte MagicByte
        {
            get
            {
                ushort t = (ushort) ((ushort) (_Keys[2] & 0xFFFF) | 2);
                return (byte) ((t*(t ^ 1)) >> 8);
            }
        }

        public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header,
                                                              byte[] encryptionHeader)
        {
            var encryptor = new PkwareTraditionalEncryptionData(password);
            byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length);
            if (plainTextHeader[11] != (byte) ((header.Crc >> 24) & 0xff))
            {
                if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor))
                {
                    throw new CryptographicException("The password did not match.");
                }
                if (plainTextHeader[11] != (byte) ((header.LastModifiedTime >> 8) & 0xff))
                {
                    throw new CryptographicException("The password did not match.");
                }
            }
            return encryptor;
        }


        public byte[] Decrypt(byte[] cipherText, int length)
        {
            if (length > cipherText.Length)
                throw new ArgumentOutOfRangeException("length",
                                                      "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array.");

            var plainText = new byte[length];
            for (int i = 0; i < length; i++)
            {
                var C = (byte) (cipherText[i] ^ MagicByte);
                UpdateKeys(C);
                plainText[i] = C;
            }
            return plainText;
        }

        public byte[] Encrypt(byte[] plainText, int length)
        {
            if (plainText == null)
                throw new ArgumentNullException("plaintext");

            if (length > plainText.Length)
                throw new ArgumentOutOfRangeException("length",
                                                      "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array.");

            var cipherText = new byte[length];
            for (int i = 0; i < length; i++)
            {
                byte C = plainText[i];
                cipherText[i] = (byte) (plainText[i] ^ MagicByte);
                UpdateKeys(C);
            }
            return cipherText;
        }

        private void Initialize(string password)
        {
            byte[] p = StringToByteArray(password);
            for (int i = 0; i < password.Length; i++)
                UpdateKeys(p[i]);
        }

        internal static byte[] StringToByteArray(string value, Encoding encoding)
        {
            byte[] a = encoding.GetBytes(value);
            return a;
        }

        internal static byte[] StringToByteArray(string value)
        {
            return StringToByteArray(value, ArchiveEncoding.Password);
        }

        private void UpdateKeys(byte byteValue)
        {
            _Keys[0] = (UInt32) crc32.ComputeCrc32((int) _Keys[0], byteValue);
            _Keys[1] = _Keys[1] + (byte) _Keys[0];
            _Keys[1] = _Keys[1]*0x08088405 + 1;
            _Keys[2] = (UInt32) crc32.ComputeCrc32((int) _Keys[2], (byte) (_Keys[1] >> 24));
        }
    }
}