Unzipping encrypted items that use 'compatible' encryption
In This Topic
When decrypting data using Compatible encryption, the password verification isn't 100% accurate.
It is possible that an invalid password will not be detected. In that case, decryption will process but the decrypted data will be garbage. This is an unfortunate design flaw of the encryption algorithm.
This behavior only applies to items encrypted with the Compatible encryption method.
In the context of unzipping, this will always result in a decompression failure or a checksum failure so no incorrect data will ever be delivered. However, special care needs to be taken when handling exceptions.
This example shows how this situation can be handled. It examines the exceptions thrown by decompression as well as what kind of items being processed to distinguish between an actual data error and a probable invalid password.
If all the encrypted items in an archive use the same password, this example is not absolutely necessary as any error can be treated in the same way. For example, many third party Zip tools will say something like: "Data error in item 'X'. Wrong password?".
using System;
using Xceed.FileSystem;
using Xceed.Zip;
namespace DocumentationExamples.Zip
{
class CompatibleEncryption
{
privatevoid OnItemProgression( object sender, ItemProgressionEventArgs e )
{
/* We're about to process a new item */// Reset the password index
this.m_passwordIndex = 0;
}
privatevoid OnItemException( object sender, ItemExceptionEventArgs e )
{
bool badPassword = false;
// Get the archive object we passed through the user data
ZipArchive zip = ( ZipArchive ) e.UserData;
/* We will try to ascertain if we have an invalid password */
InvalidDecryptionPasswordException invalidDecryptionPasswordException;
FileSystemIOException fileSystemIOException;
invalidDecryptionPasswordException = e.Exception as InvalidDecryptionPasswordException;
fileSystemIOException = e.Exception as FileSystemIOException;
// If the exception says that a bad password was supplied
if( invalidDecryptionPasswordException != null )
{
badPassword = true;
}
// If we had an I/O error during decryption
elseif( fileSystemIOException != null )
{
ZippedFile zippedFile = e.CurrentItem as ZippedFile;
// If we were reading from a zipped file encrypted in the 'compatible' method
if( zippedFile != null && zippedFile.Encrypted &&
zippedFile.EncryptionMethod.Equals( EncryptionMethod.Compatible ) )
{
/* It's possible the I/O error occurred because the password is invalid.
The way the 'compatible' encryption is designed doesn't provide for 100%
accurate bad password detection, unfortunately. */
badPassword = true;
}
}
// If we had a bad password
if( badPassword )
{
// If we haven't gone through our password list
if( this.m_passwordIndex < this.m_passwords.Length )
{
// Set the current password and move the index to the next password
zip.DefaultDecryptionPassword = this.m_passwords[ this.m_passwordIndex++ ];
// Retry unzipping the file
e.Action = ItemExceptionAction.Retry;
}
else
{
// Skip the file
e.Action = ItemExceptionAction.Ignore;
}
}
}
publicvoid Example()
{
AbstractFile zipFile = new DiskFile( @"ZipFileWithEncryptedItems.zip" );
AbstractFolder destinationFolder = new DiskFolder( @"Output" );
ZipArchive zip = new ZipArchive( zipFile );
// Set up the list of password possible for the items in this archive
this.m_passwords = newstring[]
{
"wrong password",
"fkEI-969=6kei$[BbZ \"6Iq- =[",
"}8{)zM#$k//O?t~=iG'Si{AF\"S~\'/8@1n",
};
ZipEvents events = new ZipEvents();
// Subscribe to the events that will allow us to handle invalid passwords
events.ItemProgression += new ItemProgressionEventHandler( OnItemProgression );
events.ItemException += new ItemExceptionEventHandler( OnItemException );
// Unzip the contents of the archive using the events object we set up
zip.CopyFilesTo( events, zip, destinationFolder, true, true );
}
privatestring[] m_passwords;
privateint m_passwordIndex;
}
}
Imports Microsoft.VisualBasic
Imports System
Imports Xceed.FileSystem
Imports Xceed.Zip
Namespace DocumentationExamples.Zip
FriendClass CompatibleEncryption
PrivateSub OnItemProgression(ByVal sender AsObject, ByVal e As ItemProgressionEventArgs)
' We're about to process a new item
' Reset the password index
Me.m_passwordIndex = 0
End SubPrivateSub OnItemException(ByVal sender AsObject, ByVal e As ItemExceptionEventArgs)
Dim badPassword AsBoolean = False' Get the archive object we passed through the user data
Dim zip As ZipArchive = CType(e.UserData, ZipArchive)
' We will try to ascertain if we have an invalid password
Dim invalidDecryptionPasswordException As InvalidDecryptionPasswordException
Dim fileSystemIOException As FileSystemIOException
invalidDecryptionPasswordException = TryCast(e.Exception, InvalidDecryptionPasswordException)
fileSystemIOException = TryCast(e.Exception, FileSystemIOException)
' If the exception says that a bad password was supplied
If invalidDecryptionPasswordException IsNotNothingThen
badPassword = True' If we had an I/O error during decryption
ElseIf fileSystemIOException IsNotNothingThenDim zippedFile As ZippedFile = TryCast(e.CurrentItem, ZippedFile)
' If we were reading from a zipped file encrypted in the 'compatible' method
If zippedFile IsNotNothingAndAlso zippedFile.Encrypted AndAlso zippedFile.EncryptionMethod.Equals(EncryptionMethod.Compatible) Then' It's possible the I/O error occurred because the password is invalid.
' The way the 'compatible' encryption is designed doesn't provide for 100%
' accurate bad password detection, unfortunately.
badPassword = TrueEndIfEndIf' If we had a bad password
If badPassword Then' If we haven't gone through our password list
IfMe.m_passwordIndex < Me.m_passwords.Length Then' Set the current password and move the index to the next password
zip.DefaultDecryptionPassword = Me.m_passwords(Me.m_passwordIndex)
Me.m_passwordIndex += 1
' Retry unzipping the file
e.Action = ItemExceptionAction.Retry
Else' Skip the file
e.Action = ItemExceptionAction.Ignore
EndIfEndIfEnd SubPublicSub Example()
Dim zipFile As AbstractFile = New DiskFile("ZipFileWithEncryptedItems.zip")
Dim destinationFolder As AbstractFolder = New DiskFolder("Output")
Dim zip AsNew ZipArchive(zipFile)
' Set up the list of password possible for the items in this archive
Me.m_passwords = NewString() { "wrong password", "fkEI-969=6kei$[BbZ ""6Iq- =[", "}8{)zM#$k//O?t~=iG'Si{AF""S~'/8@1n" }
Dim events AsNew ZipEvents()
' Subscribe to the events that will allow us to handle invalid passwords
AddHandler events.ItemProgression, AddressOf OnItemProgression
AddHandler events.ItemException, AddressOf OnItemException
' Unzip the contents of the archive using the events object we set up
zip.CopyFilesTo(events, zip, destinationFolder, True, True)
End SubPrivate m_passwords() AsStringPrivate m_passwordIndex AsIntegerEnd ClassEnd Namespace