예제 #1
0
파일: ZipEntry.cs 프로젝트: hiling/WebZip
        private void _WriteFileData(ZipCrypto cipher, System.IO.Stream s)
        {
            // Read in the data from the input stream (often a file in the filesystem),
            // and write it to the output stream, calculating a CRC on it as we go.
            // We will also deflate and encrypt as necessary.

            Stream input = null;
            CrcCalculatorStream input1 = null;
            CountingStream counter = null;
            try {
            // s.Position may fail on some write-only streams, eg stdout or System.Web.HttpResponseStream
            // We swallow that exception, because we don't care!
            this.__FileDataPosition = s.Position;
            } catch{}

            try
            {
                // get the original stream:
                if (_sourceStream != null)
                {
                    _sourceStream.Position = 0;
                    input = _sourceStream;
                }
                else
                {
                    input = System.IO.File.OpenRead(LocalFileName);
                }

                // wrap a CRC Calculator Stream around the raw input stream.
                input1 = new CrcCalculatorStream(input);

                // wrap a counting stream around the raw output stream:
                counter = new CountingStream(s);

                // maybe wrap an encrypting stream around that:
                Stream output1 = (Encryption == EncryptionAlgorithm.PkzipWeak) ?
                    (Stream)(new ZipCipherStream(counter, cipher, CryptoMode.Encrypt)) : counter;

                // maybe wrap a DeflateStream around that
                Stream output2 = null;
                bool mustCloseDeflateStream = false;
                if (CompressionMethod == 0x08)
                {
                    output2 = new DeflateStream(output1, CompressionMode.Compress, true);
                    mustCloseDeflateStream = true;
                }
                else
                    output2 = output1;

                // as we emit the file, we maybe deflate, then maybe encrypt, then write the bytes.
                byte[] buffer = new byte[READBLOCK_SIZE];

                int n = input1.Read(buffer, 0, READBLOCK_SIZE);
                while (n > 0)
                {
                    output2.Write(buffer, 0, n);
                    n = input1.Read(buffer, 0, READBLOCK_SIZE);
                }

                // by calling Close() on the deflate stream, we write the footer bytes, as necessary.
                if (mustCloseDeflateStream)
                    output2.Close();

            }
            finally
            {
                if (_sourceStream == null && input != null)
                {
                    input.Close();
                    input.Dispose();
                }

            }

            _UncompressedSize = input1.TotalBytesSlurped;
            _CompressedSize = counter.BytesWritten;

            _Crc32 = input1.Crc32;

            if ((_Password != null) && (Encryption == EncryptionAlgorithm.PkzipWeak))
            {
                _CompressedSize += 12; // 12 extra bytes for the encryption header
            }

            int i = 8;
            _EntryHeader[i++] = (byte)(CompressionMethod & 0x00FF);
            _EntryHeader[i++] = (byte)((CompressionMethod & 0xFF00) >> 8);

            i = 14;
            // CRC - the correct value now
            _EntryHeader[i++] = (byte)(_Crc32 & 0x000000FF);
            _EntryHeader[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
            _EntryHeader[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
            _EntryHeader[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);

            // CompressedSize - the correct value now
            _EntryHeader[i++] = (byte)(_CompressedSize & 0x000000FF);
            _EntryHeader[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
            _EntryHeader[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
            _EntryHeader[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);

            // UncompressedSize - the correct value now
            _EntryHeader[i++] = (byte)(_UncompressedSize & 0x000000FF);
            _EntryHeader[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
            _EntryHeader[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
            _EntryHeader[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);

            // workitem 6414
            if (s.CanSeek)
            {
                // seek in the raw output stream, to the beginning of the header for this entry.
                s.Seek(this._RelativeOffsetOfHeader, System.IO.SeekOrigin.Begin);

                // finally, write the updated header to the output stream
                s.Write(_EntryHeader, 0, _EntryHeader.Length);

                // adjust the count on the CountingStream as necessary
                var s1 = s as CountingStream;
                if (s1 != null) s1.Adjust(_EntryHeader.Length);

                // seek in the raw output stream, to the end of the file data for this entry
                s.Seek(_CompressedSize, System.IO.SeekOrigin.Current);
            }
            else
            {
                // eg, ASP.NET Response.OutputStream, or stdout

                if ((_BitField & 0x0008) != 0x0008)
                    throw new ZipException("Logic error.");

                byte[] Descriptor = new byte[16];
                i = 0;
                // signature
                int sig = ZipConstants.ZipEntryDataDescriptorSignature;
                Descriptor[i++] = (byte)(sig & 0x000000FF);
                Descriptor[i++] = (byte)((sig & 0x0000FF00) >> 8);
                Descriptor[i++] = (byte)((sig & 0x00FF0000) >> 16);
                Descriptor[i++] = (byte)((sig & 0xFF000000) >> 24);

                // CRC - the correct value now
                Descriptor[i++] = (byte)(_Crc32 & 0x000000FF);
                Descriptor[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
                Descriptor[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
                Descriptor[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);

                // CompressedSize - the correct value now
                Descriptor[i++] = (byte)(_CompressedSize & 0x000000FF);
                Descriptor[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
                Descriptor[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
                Descriptor[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);

                // UncompressedSize - the correct value now
                Descriptor[i++] = (byte)(_UncompressedSize & 0x000000FF);
                Descriptor[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
                Descriptor[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
                Descriptor[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);

                // finally, write the updated header to the output stream
                s.Write(Descriptor, 0, Descriptor.Length);
            }
        }
예제 #2
0
파일: ZipEntry.cs 프로젝트: hiling/WebZip
        private Int32 _ExtractOne(System.IO.Stream output, ZipCrypto cipher)
        {
            System.IO.Stream input = this.ArchiveStream;

            // seek to the beginning of the file data in the stream
            input.Seek(this.__FileDataPosition, System.IO.SeekOrigin.Begin);

            // to validate the CRC.
            Int32 CrcResult = 0;

            byte[] bytes = new byte[READBLOCK_SIZE];

            // The extraction process varies depending on how the entry was stored.
            // It could have been encrypted, and it coould have been compressed, or both, or
            // neither. So we need to check both the encryption flag and the compression flag,
            // and take the proper action in all cases.

            int LeftToRead = (CompressionMethod == 0x08) ? this.UncompressedSize : this._CompressedFileDataSize;

            // get a stream that either decrypts or not.
            Stream input2 = (Encryption == EncryptionAlgorithm.PkzipWeak)
                ? new ZipCipherStream(input, cipher, CryptoMode.Decrypt)
                : input;

            // using the above, now we get a stream that either decompresses or not.
            Stream input3 = (CompressionMethod == 0x08)
                ? new DeflateStream(input2, CompressionMode.Decompress, true)
                : input2;

            //var out2 = new CrcCalculatorStream(output, LeftToRead);

            // as we read, we maybe decrypt, and then we maybe decompress. Then we write.
            using (var s1 = new CrcCalculatorStream(input3))
            {
                while (LeftToRead > 0)
                {
                    int len = (LeftToRead > bytes.Length) ? bytes.Length : LeftToRead;
                    int n = s1.Read(bytes, 0, len);
                    _CheckRead(n);
                    output.Write(bytes, 0, n);
                    LeftToRead -= n;
                }

                CrcResult = s1.Crc32;
            }

            return CrcResult;
        }
예제 #3
0
파일: ZipEntry.cs 프로젝트: hiling/WebZip
        private ZipCrypto SetupCipher(string password)
        {
            ZipCrypto cipher = null;
            // decrypt the file header data here if necessary.
            if (Encryption == EncryptionAlgorithm.PkzipWeak)
            {
                if (password == null)
                    throw new BadPasswordException("This entry requires a password.");

                cipher = new ZipCrypto();
                cipher.InitCipher(password);

                // Decrypt the header.  This has a side effect of "further initializing the
                // encryption keys" in the traditional zip encryption.
                byte[] DecryptedHeader = cipher.DecryptMessage(_WeakEncryptionHeader, _WeakEncryptionHeader.Length);

                // CRC check
                // According to the pkzip spec, the final byte in the decrypted header
                // is the highest-order byte in the CRC. We check it here.
                if (DecryptedHeader[11] != (byte)((_Crc32 >> 24) & 0xff))
                {
                    // In the case that bit 3 of the general purpose bit flag is set to indicate
                    // the presence of an 'Extended File Header', the last byte of the decrypted
                    // header is sometimes compared with the high-order byte of the lastmodified
                    // time, and not the CRC, to verify the password.
                    //
                    // This is not documented in the PKWare Appnote.txt.
                    // This was discovered this by analysis of the Crypt.c source file in the InfoZip library
                    // http://www.info-zip.org/pub/infozip/

                    if ((_BitField & 0x0008) != 0x0008)
                    {
                        throw new BadPasswordException("The password did not match.");
                    }
                    else if (DecryptedHeader[11] != (byte)((_TimeBlob >> 8) & 0xff))
                    {
                        throw new BadPasswordException("The password did not match.");
                    }
                }

                // We have a good password.
            }

            return cipher;
        }
예제 #4
0
파일: ZipEntry.cs 프로젝트: hiling/WebZip
        private void _EmitOne(System.IO.Stream outstream, out ZipCrypto cipher)
        {
            // If PKZip (weak) encryption is in use, then the entry data is preceded by
            // 12-byte "encryption header" for the entry.
            byte[] encryptionHeader = null;
            cipher = null;
            if (_Password != null && Encryption == EncryptionAlgorithm.PkzipWeak)
            {
                cipher = new ZipCrypto();
                // apply the password to the keys
                cipher.InitCipher(_Password);

                // generate the random 12-byte header:
                var rnd = new System.Random();
                encryptionHeader = new byte[12];
                rnd.NextBytes(encryptionHeader);

                // Here, it is important to encrypt the random header, INCLUDING the final byte
                // which is the high-order byte of the CRC32.  We must do this before
                // we encrypt the file data.  This step changes the state of the cipher, or in the
                // words of the PKZIP spec, it "further initializes" the cipher keys.

                // No way around this: must read the stream to compute the actual CRC
                FigureCrc32();
                encryptionHeader[11] = (byte)((this._Crc32 >> 24) & 0xff);

                byte[] cipherText = cipher.EncryptMessage(encryptionHeader, encryptionHeader.Length);

                // Write the ciphered bonafide encryption header.
                outstream.Write(cipherText, 0, cipherText.Length);
            }

            // write the (potentially compressed, potentially encrypted) file data
            _WriteFileData(cipher, outstream);

            _TotalEntrySize = _LengthOfHeader + _CompressedSize;
        }
예제 #5
0
파일: ZipCrypto.cs 프로젝트: hiling/WebZip
 /// <summary>
 /// The  constructor.
 /// </summary>
 /// <param name="s">The underlying stream</param>
 /// <param name="mode">To either encrypt or decrypt.</param>
 /// <param name="cipher">The pre-initialized ZipCrypto object.</param>
 public ZipCipherStream(System.IO.Stream s, ZipCrypto cipher, CryptoMode mode)
     : base()
 {
     _cipher = cipher;
     _s = s;
     _mode = mode;
 }