/// <summary>
		/// Perform the initial read on an entry which may include 
		/// reading encryption headers and setting up inflation.
		/// </summary>
		/// <param name="destination">The destination to fill with data read.</param>
		/// <param name="offset">The offset to start reading at.</param>
		/// <param name="count">The maximum number of bytes to read.</param>
		/// <returns>The actual number of bytes read.</returns>
		int InitialRead(byte[] destination, int offset, int count)
		{
			if ( !CanDecompressEntry ) {
				throw new ZipException("Library cannot extract this entry. Version required is (" + entry.Version.ToString() + ")");
			}
			
			// Handle encryption if required.
			if (entry.IsCrypted) {
#if NETCF_1_0
				throw new ZipException("Encryption not supported for Compact Framework 1.0");
#else
				if (password == null) {
					throw new ZipException("No password set.");
				}
				
				// Generate and set crypto transform...
				PkzipClassicManaged managed = new PkzipClassicManaged();
				byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
				
				inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);
				
				byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
				inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CryptoHeaderSize);

				if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
					throw new ZipException("Invalid password");
				}

				if (csize >= ZipConstants.CryptoHeaderSize) {
					csize -= ZipConstants.CryptoHeaderSize;
				}
				else if ( (entry.Flags & (int)GeneralBitFlags.Descriptor) == 0 ) {
					throw new ZipException(string.Format("Entry compressed size {0} too small for encryption", csize));
				}
#endif				
			} else {
#if !NETCF_1_0
				inputBuffer.CryptoTransform = null;
#endif				
			}

			if ((csize > 0) || ((flags & (int)GeneralBitFlags.Descriptor) != 0)) {
				if ((method == (int)CompressionMethod.Deflated) && (inputBuffer.Available > 0)) {
					inputBuffer.SetInflaterInput(inf);
				}

				internalReader = new ReadDataHandler(BodyRead);
				return BodyRead(destination, offset, count);
			}
			else {
				internalReader = new ReadDataHandler(ReadingNotAvailable);
				return 0;
			}
		}
Exemple #2
0
		Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
		{
			CryptoStream result = null;

			if ( (entry.Version < ZipConstants.VersionStrongEncryption)
				|| (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
				PkzipClassicManaged classicManaged = new PkzipClassicManaged();

				OnKeysRequired(entry.Name);
				if (HaveKeys == false) {
					throw new ZipException("No password available for encrypted stream");
				}

				result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
				CheckClassicPassword(result, entry);
			}
			else {
#if !NET_1_1 && !NETCF_2_0
				if (entry.Version == ZipConstants.VERSION_AES) {
					//
					OnKeysRequired(entry.Name);
					if (HaveKeys == false) {
						throw new ZipException("No password available for AES encrypted stream");
					}
					int saltLen = entry.AESSaltLen;
					byte[] saltBytes = new byte[saltLen];
					int saltIn = baseStream.Read(saltBytes, 0, saltLen);
					if (saltIn != saltLen)
						throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
					//
					byte[] pwdVerifyRead = new byte[2];
					baseStream.Read(pwdVerifyRead, 0, 2);
					int blockSize = entry.AESKeySize / 8;	// bits to bytes

					ZipAESTransform decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
					byte[] pwdVerifyCalc = decryptor.PwdVerifier;
					if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
						throw new Exception("Invalid password for AES");
					result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
				}
				else
#endif
				{
					throw new ZipException("Decryption method not supported");
				}
			}

			return result;
		}