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; }
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; }