Esempio n. 1
0
 // For AES the method in the entry is 99, and the real compression method is in the extradata
 //
 private void ProcessAESExtraData(ZipExtraData extraData)
 {
     if (extraData.Find(0x9901))
     {
         // Set version and flag for Zipfile.CreateAndInitDecryptionStream
         this.versionToExtract = ZipConstants.VERSION_AES;                            // Ver 5.1 = AES see "Version" getter
         // Set StrongEncryption flag for ZipFile.CreateAndInitDecryptionStream
         this.Flags = this.Flags | (int)GeneralBitFlags.StrongEncryption;
         //
         // Unpack AES extra data field see http://www.winzip.com/aes_info.htm
         int length = extraData.ValueLength;                         // Data size currently 7
         if (length < 7)
         {
             throw new ZipException("AES Extra Data Length " + length + " invalid.");
         }
         int ver            = extraData.ReadShort();                 // Version number (1=AE-1 2=AE-2)
         int vendorId       = extraData.ReadShort();                 // 2-character vendor ID 0x4541 = "AE"
         int encrStrength   = extraData.ReadByte();                  // encryption strength 1 = 128 2 = 192 3 = 256
         int actualCompress = extraData.ReadShort();                 // The actual compression method used to compress the file
         this._aesVer = ver;
         this._aesEncryptionStrength = encrStrength;
         this.method = (CompressionMethod)actualCompress;
     }
     else
     {
         throw new ZipException("AES Extra Data missing");
     }
 }
        // Write the local file header
        // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
        private void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
        {
            CompressionMethod method = entry.CompressionMethod;
            bool headerInfoAvailable = true;             // How to get this?
            bool patchEntryHeader    = false;

            this.WriteLEInt(ZipConstants.LocalHeaderSignature);

            this.WriteLEShort(entry.Version);
            this.WriteLEShort(entry.Flags);
            this.WriteLEShort((byte)method);
            this.WriteLEInt((int)entry.DosTime);

            if (headerInfoAvailable == true)
            {
                this.WriteLEInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    this.WriteLEInt(-1);
                    this.WriteLEInt(-1);
                }
                else
                {
                    this.WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
                    this.WriteLEInt((int)entry.Size);
                }
            }
            else
            {
                if (patchData != null)
                {
                    patchData.CrcPatchOffset = this.stream_.Position;
                }
                this.WriteLEInt(0);                  // Crc

                if (patchData != null)
                {
                    patchData.SizePatchOffset = this.stream_.Position;
                }

                // For local header both sizes appear in Zip64 Extended Information
                if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
                {
                    this.WriteLEInt(-1);
                    this.WriteLEInt(-1);
                }
                else
                {
                    this.WriteLEInt(0);                      // Compressed size
                    this.WriteLEInt(0);                      // Uncompressed size
                }
            }

            byte[] name = ZipStrings.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new ZipException("Entry name too long.");
            }

            var ed = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader))
            {
                ed.StartNewEntry();
                if (headerInfoAvailable)
                {
                    ed.AddLeLong(entry.Size);
                    ed.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    ed.AddLeLong(-1);
                    ed.AddLeLong(-1);
                }
                ed.AddNewEntry(1);

                if (!ed.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }

                if (patchData != null)
                {
                    patchData.SizePatchOffset = ed.CurrentReadIndex;
                }
            }
            else
            {
                ed.Delete(1);
            }

            byte[] extra = ed.GetEntryData();

            this.WriteLEShort(name.Length);
            this.WriteLEShort(extra.Length);

            if (name.Length > 0)
            {
                this.stream_.Write(name, 0, name.Length);
            }

            if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
            {
                patchData.SizePatchOffset += this.stream_.Position;
            }

            if (extra.Length > 0)
            {
                this.stream_.Write(extra, 0, extra.Length);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Process extra data fields updating the entry based on the contents.
        /// </summary>
        /// <param name="localHeader">True if the extra data fields should be handled
        /// for a local header, rather than for a central header.
        /// </param>
        internal void ProcessExtraData(bool localHeader)
        {
            var extraData = new ZipExtraData(this.extra);

            if (extraData.Find(0x0001))
            {
                // Version required to extract is ignored here as some archivers dont set it correctly
                // in theory it should be version 45 or higher

                // The recorded size will change but remember that this is zip64.
                this.forceZip64_ = true;

                if (extraData.ValueLength < 4)
                {
                    throw new ZipException("Extra data extended Zip64 information length is invalid");
                }

                // (localHeader ||) was deleted, because actually there is no specific difference with reading sizes between local header & central directory
                // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
                // ...
                // 4.4  Explanation of fields
                // ...
                //	4.4.8 compressed size: (4 bytes)
                //	4.4.9 uncompressed size: (4 bytes)
                //
                //		The size of the file compressed (4.4.8) and uncompressed,
                //		(4.4.9) respectively.  When a decryption header is present it
                //		will be placed in front of the file data and the value of the
                //		compressed file size will include the bytes of the decryption
                //		header.  If bit 3 of the general purpose bit flag is set,
                //		these fields are set to zero in the local header and the
                //		correct values are put in the data descriptor and
                //		in the central directory.  If an archive is in ZIP64 format
                //		and the value in this field is 0xFFFFFFFF, the size will be
                //		in the corresponding 8 byte ZIP64 extended information
                //		extra field.  When encrypting the central directory, if the
                //		local header is not in ZIP64 format and general purpose bit
                //		flag 13 is set indicating masking, the value stored for the
                //		uncompressed size in the Local Header will be zero.
                //
                // Othewise there is problem with minizip implementation
                if (this.size == uint.MaxValue)
                {
                    this.size = (ulong)extraData.ReadLong();
                }

                if (this.compressedSize == uint.MaxValue)
                {
                    this.compressedSize = (ulong)extraData.ReadLong();
                }

                if (!localHeader && (this.offset == uint.MaxValue))
                {
                    this.offset = extraData.ReadLong();
                }

                // Disk number on which file starts is ignored
            }
            else
            {
                if (
                    ((this.versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
                    ((this.size == uint.MaxValue) || (this.compressedSize == uint.MaxValue))
                    )
                {
                    throw new ZipException("Zip64 Extended information required but is missing.");
                }
            }

            this.DateTime = this.GetDateTime(extraData);
            if (this.method == CompressionMethod.WinZipAES)
            {
                this.ProcessAESExtraData(extraData);
            }
        }