public static bool IsZip64(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); if (endOfCentralDirectoryRecord.NumberOfThisDisk != endOfCentralDirectoryRecord.NumberOfTheDiskWithTheStartOfTheCentralDirectory) { return(false); } var offset = endOfCentralDirectoryRecord.OffsetFromStart - Zip64EndOfCentralDirectoryLocator.SizeInBytes; if (offset >= 0) { reader.BaseStream.Seek(offset, SeekOrigin.Begin); if (Zip64EndOfCentralDirectoryLocator.Exists(reader)) { return(true); } } reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); CentralDirectoryHeader centralDirectoryHeader; while (CentralDirectoryHeader.TryRead(reader, out centralDirectoryHeader)) { if (HasZip64ExtendedInformationExtraField(centralDirectoryHeader)) { return(true); } if (centralDirectoryHeader.DiskNumberStart != endOfCentralDirectoryRecord.NumberOfThisDisk) { continue; } var savedPosition = reader.BaseStream.Position; reader.BaseStream.Position = centralDirectoryHeader.RelativeOffsetOfLocalHeader; LocalFileHeader localFileHeader; if (LocalFileHeader.TryRead(reader, out localFileHeader) && HasZip64ExtendedInformationExtraField(localFileHeader)) { return(true); } reader.BaseStream.Position = savedPosition; } return(false); }
/// <summary> /// Read ZIP's offsets and positions of offsets. /// </summary> /// <param name="reader">binary reader to zip archive</param> /// <returns>metadata with offsets and positions for entries</returns> public static SignedPackageArchiveMetadata ReadSignedArchiveMetadata(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var metadata = new SignedPackageArchiveMetadata() { StartOfFileHeaders = reader.BaseStream.Length }; var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); metadata.EndOfCentralDirectoryRecordPosition = endOfCentralDirectoryRecord.OffsetFromStart; reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); // Read central directory records var centralDirectoryRecords = new List <CentralDirectoryHeaderMetadata>(); CentralDirectoryHeader header; while (CentralDirectoryHeader.TryRead(reader, out header)) { if (header.RelativeOffsetOfLocalHeader < metadata.StartOfFileHeaders) { metadata.StartOfFileHeaders = header.RelativeOffsetOfLocalHeader; } var isPackageSignatureFile = SignedPackageArchiveUtility.IsPackageSignatureFileEntry( header.FileName, header.GeneralPurposeBitFlag); var centralDirectoryMetadata = new CentralDirectoryHeaderMetadata() { IsPackageSignatureFile = isPackageSignatureFile, HeaderSize = header.GetSizeInBytes(), OffsetToFileHeader = header.RelativeOffsetOfLocalHeader, Position = header.OffsetFromStart }; centralDirectoryRecords.Add(centralDirectoryMetadata); } if (centralDirectoryRecords.Count == 0) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } var lastCentralDirectoryRecord = centralDirectoryRecords.Last(); metadata.EndOfCentralDirectory = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; metadata.CentralDirectoryHeaders = centralDirectoryRecords; UpdateSignedPackageArchiveMetadata(reader, metadata); return(metadata); }
private static bool HasZip64ExtendedInformationExtraField(CentralDirectoryHeader header) { IReadOnlyList <ExtraField> extraFields; if (ExtraField.TryRead(header, out extraFields)) { return(extraFields.Any(extraField => extraField is Zip64ExtendedInformationExtraField)); } return(false); }
/// <summary> /// Utility method to know if a zip archive is signed. /// </summary> /// <param name="reader">Binary reader pointing to a zip archive.</param> /// <returns>true if the given archive is signed</returns> public static bool IsSigned(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } try { var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); // Look for signature central directory record reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); CentralDirectoryHeader centralDirectoryHeader; while (CentralDirectoryHeader.TryRead(reader, out centralDirectoryHeader)) { if (IsPackageSignatureFileEntry( centralDirectoryHeader.FileName, centralDirectoryHeader.GeneralPurposeBitFlag)) { // Go to local file header reader.BaseStream.Seek(centralDirectoryHeader.RelativeOffsetOfLocalHeader, SeekOrigin.Begin); // Make sure local file header exists LocalFileHeader localFileHeader; if (!LocalFileHeader.TryRead(reader, out localFileHeader)) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } return(IsPackageSignatureFileEntry( localFileHeader.FileName, localFileHeader.GeneralPurposeBitFlag)); } } } // Ignore any exception. If something is thrown it means the archive is either not valid or not signed catch { } return(false); }
private static UnsignedPackageArchiveMetadata ReadUnsignedArchiveMetadata(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); var endOfCentralDirectoryRecordPosition = endOfCentralDirectoryRecord.OffsetFromStart; reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); var centralDirectoryRecords = new List <CentralDirectoryHeaderMetadata>(); CentralDirectoryHeader header; while (CentralDirectoryHeader.TryRead(reader, out header)) { var centralDirectoryMetadata = new CentralDirectoryHeaderMetadata() { Position = header.OffsetFromStart, OffsetToLocalFileHeader = header.RelativeOffsetOfLocalHeader, HeaderSize = header.GetSizeInBytes(), }; centralDirectoryRecords.Add(centralDirectoryMetadata); } if (centralDirectoryRecords.Count == 0) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } var lastCentralDirectoryRecord = centralDirectoryRecords.Last(); var endOfCentralDirectoryPosition = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; var endOfLocalFileHeadersPosition = centralDirectoryRecords.Min(record => record.Position); UpdateLocalFileHeadersTotalSize(centralDirectoryRecords, endOfLocalFileHeadersPosition); return(new UnsignedPackageArchiveMetadata(endOfLocalFileHeadersPosition, endOfCentralDirectoryPosition)); }
internal static bool TryRead(BinaryReader reader, out CentralDirectoryHeader header) { header = null; var signature = reader.ReadUInt32(); if (signature != Signature) { reader.BaseStream.Seek(offset: -sizeof(uint), origin: SeekOrigin.Current); return(false); } header = new CentralDirectoryHeader(); header.OffsetFromStart = reader.BaseStream.Position - sizeof(uint); header.VersionMadeBy = reader.ReadUInt16(); header.VersionNeededToExtract = reader.ReadUInt16(); header.GeneralPurposeBitFlag = reader.ReadUInt16(); header.CompressionMethod = reader.ReadUInt16(); header.LastModFileTime = reader.ReadUInt16(); header.LastModFileDate = reader.ReadUInt16(); header.Crc32 = reader.ReadUInt32(); header.CompressedSize = reader.ReadUInt32(); header.UncompressedSize = reader.ReadUInt32(); header.FileNameLength = reader.ReadUInt16(); header.ExtraFieldLength = reader.ReadUInt16(); header.FileCommentLength = reader.ReadUInt16(); header.DiskNumberStart = reader.ReadUInt16(); header.InternalFileAttributes = reader.ReadUInt16(); header.ExternalFileAttributes = reader.ReadUInt32(); header.RelativeOffsetOfLocalHeader = reader.ReadUInt32(); header.FileName = reader.ReadBytes(header.FileNameLength); header.ExtraField = reader.ReadBytes(header.ExtraFieldLength); header.FileComment = reader.ReadBytes(header.FileCommentLength); return(true); }
internal static bool TryRead(CentralDirectoryHeader header, out IReadOnlyList <ExtraField> extraFields) { extraFields = null; if (header.ExtraFieldLength == 0) { return(false); } var readUncompressedFileSize = header.UncompressedSize == ZipConstants.Mask32Bit; var readCompressedFileSize = header.CompressedSize == ZipConstants.Mask32Bit; var readRelativeOffsetOfLocalHeader = header.RelativeOffsetOfLocalHeader == ZipConstants.Mask32Bit; var readDiskNumberStart = header.DiskNumberStart == ZipConstants.Mask16Bit; return(TryRead( header.ExtraField, readUncompressedFileSize, readCompressedFileSize, readRelativeOffsetOfLocalHeader, readDiskNumberStart, out extraFields)); }
/// <summary> /// Utility method to know if a zip archive is signed. /// </summary> /// <param name="reader">Binary reader pointing to a zip archive.</param> /// <returns>true if the given archive is signed</returns> private static bool IsSigned(BinaryReader reader) { try { var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); // Look for signature central directory record reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); CentralDirectoryHeader header; while (CentralDirectoryHeader.TryRead(reader, out header)) { var isUtf8 = IsUtf8(header.GeneralPurposeBitFlag); var fileName = GetString(header.FileName, isUtf8); if (string.Equals(fileName, _signingSpecification.SignaturePath, StringComparison.Ordinal)) { // Go to local file header reader.BaseStream.Seek(header.RelativeOffsetOfLocalHeader, SeekOrigin.Begin); // Make sure file header exists there var fileHeaderSignature = reader.ReadUInt32(); if (fileHeaderSignature != LocalFileHeader.Signature) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } return(true); } } } // Ignore any exception. If something is thrown it means the archive is either not valid or not signed catch { } return(false); }
/// <summary> /// Read ZIP's offsets and positions of offsets. /// </summary> /// <param name="reader">binary reader to zip archive</param> /// <returns>metadata with offsets and positions for entries</returns> public static SignedPackageArchiveMetadata ReadSignedArchiveMetadata(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var metadata = new SignedPackageArchiveMetadata() { StartOfLocalFileHeaders = reader.BaseStream.Length }; var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); var endOfCentralDirectoryRecordPosition = endOfCentralDirectoryRecord.OffsetFromStart; reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); var centralDirectoryRecords = new List <CentralDirectoryHeaderMetadata>(); var packageSignatureFileMetadataIndex = -1; var index = 0; while (CentralDirectoryHeader.TryRead(reader, out var header)) { metadata.StartOfLocalFileHeaders = Math.Min(metadata.StartOfLocalFileHeaders, header.RelativeOffsetOfLocalHeader); var isPackageSignatureFile = SignedPackageArchiveUtility.IsPackageSignatureFileEntry( header.FileName, header.GeneralPurposeBitFlag); if (isPackageSignatureFile) { if (packageSignatureFileMetadataIndex != -1) { throw new SignatureException(NuGetLogCode.NU3005, Strings.MultiplePackageSignatureFiles); } packageSignatureFileMetadataIndex = index; } var centralDirectoryMetadata = new CentralDirectoryHeaderMetadata() { Position = header.OffsetFromStart, OffsetToLocalFileHeader = header.RelativeOffsetOfLocalHeader, IsPackageSignatureFile = isPackageSignatureFile, HeaderSize = header.GetSizeInBytes(), IndexInHeaders = index }; centralDirectoryRecords.Add(centralDirectoryMetadata); ++index; } if (centralDirectoryRecords.Count == 0) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } if (packageSignatureFileMetadataIndex == -1) { throw new SignatureException(NuGetLogCode.NU3005, Strings.NoPackageSignatureFile); } var lastCentralDirectoryRecord = centralDirectoryRecords.Last(); var endOfCentralDirectoryPosition = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; var endOfLocalFileHeadersPosition = GetEndOfLocalFileHeadersPosition(reader, centralDirectoryRecords); metadata.EndOfCentralDirectory = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; metadata.CentralDirectoryHeaders = centralDirectoryRecords; metadata.EndOfLocalFileHeaders = endOfLocalFileHeadersPosition; metadata.SignatureCentralDirectoryHeaderIndex = packageSignatureFileMetadataIndex; AssertSignatureEntryMetadata(reader, metadata); return(metadata); }