开发者

Test zip password correctness in vb.net

I want to test if a zip has a particular password in vb.net. How can I create a function like check_if_zip_pass(file, pass) As Boolean?

I can't seem to find anything in the .net framework that does this already, unless I'm missing something incredibly obvious.

This method should NOT extract the files, only return True if the a开发者_StackOverflowttempted pass is valid and False if not.


Use a 3rd party library, like DotNetZip. Keep in mind that passwords in zipfiles are applied to entries, not to the entire zip file. So your test doesn't quite make sense.

One reason WinZip may refuse to unpack the zipfile is that the very first entry is protected with a password. It could be the case that only some entries are protected by password, and some are not. It could be that different passwords are used on different entries. You'll have to decide what you want to do about these possibilities.

One option is to suppose that only one password is used on any entries in the zipfile that are encrypted. (This is not required by the zip specification) In that case, below is some sample code to check the password. There is no way to check a password without doing the decryption. So this code decrypts and extracts into Stream.Null.

public bool CheckZipPassword(string filename, string password)
{
    bool success = false;
    try
    {
        using (ZipFile zip1 = ZipFile.Read(filename))
        {
            var bitBucket = System.IO.Stream.Null;
            foreach (var e in zip1)
            {
                if (!e.IsDirectory && e.UsesEncryption)
                {
                    e.ExtractWithPassword(bitBucket, password);
                }
            }
        }
        success = true;    
    }
    catch(Ionic.Zip.BadPasswordException) { }
    return success;
}

Whoops! I think in C#. In VB.NET this would be:

    Public Function CheckZipPassword(filename As String, password As String) As System.Boolean
        Dim success As System.Boolean = False
        Try
            Using zip1 As ZipFile = ZipFile.Read(filename)
                Dim bitBucket As System.IO.Stream = System.IO.Stream.Null
                Dim e As ZipEntry
                For Each e in zip1
                    If (Not e.IsDirectory) And e.UsesEncryption Then
                        e.ExtractWithPassword(bitBucket, password)
                    End If
                Next
             End Using
             success = True
        Catch ex As Ionic.Zip.BadPasswordException
        End Try
        Return success
    End Function


I use SharpZipLib in .NET to do this, here is a link to their wiki with a helper function for unzipping password protected zip files. Below is a copy of the helper function for VB.NET.

Imports ICSharpCode.SharpZipLib.Core
Imports ICSharpCode.SharpZipLib.Zip

Public Sub ExtractZipFile(archiveFilenameIn As String, password As String, outFolder As String)
    Dim zf As ZipFile = Nothing
    Try
        Dim fs As FileStream = File.OpenRead(archiveFilenameIn)
        zf = New ZipFile(fs)
        If Not [String].IsNullOrEmpty(password) Then    ' AES encrypted entries are handled automatically
            zf.Password = password
        End If
        For Each zipEntry As ZipEntry In zf
            If Not zipEntry.IsFile Then     ' Ignore directories
                Continue For
            End If
            Dim entryFileName As [String] = zipEntry.Name
            ' to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
            ' Optionally match entrynames against a selection list here to skip as desired.
            ' The unpacked length is available in the zipEntry.Size property.

            Dim buffer As Byte() = New Byte(4095) {}    ' 4K is optimum
            Dim zipStream As Stream = zf.GetInputStream(zipEntry)

            ' Manipulate the output filename here as desired.
            Dim fullZipToPath As [String] = Path.Combine(outFolder, entryFileName)
            Dim directoryName As String = Path.GetDirectoryName(fullZipToPath)
            If directoryName.Length > 0 Then
                Directory.CreateDirectory(directoryName)
            End If

            ' Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
            ' of the file, but does not waste memory.
            ' The "Using" will close the stream even if an exception occurs.
            Using streamWriter As FileStream = File.Create(fullZipToPath)
                StreamUtils.Copy(zipStream, streamWriter, buffer)
            End Using
        Next
    Finally
        If zf IsNot Nothing Then
            zf.IsStreamOwner = True     ' Makes close also shut the underlying stream
            ' Ensure we release resources
            zf.Close()
        End If
    End Try
End Sub

To test, you could create a file compare that looks at the file before it's zipped and again after it has been unzipped (size, date, etc...). You could even compare the contents if you wanted to use a simple test file, like a file with the text "TEST" inside. Lots of choices, depends on how much and how far you want to test.


There's not much built into the framework for doing this. Here's a big sloppy mess you could try using the SharpZipLib library:

public static bool CheckIfCorrectZipPassword(string fileName, string tempDirectory, string password)
{
    byte[] buffer= new byte[2048];
    int n;
    bool isValid = true;

    using (var raw = File.Open(fileName, FileMode.Open, FileAccess.Read))
    {
        using (var input = new ZipInputStream(raw))
        {
            ZipEntry e;
            while ((e = input.GetNextEntry()) != null)
            {
                input.Password = password;
                if (e.IsDirectory) continue;
                string outputPath = Path.Combine(tempDirectory, e.FileName);

                try
                {
                    using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
                    {
                        while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            output.Write(buffer, 0, n);
                        }
                    }
                }
                catch (ZipException ze)
                {
                    if (ze.Message == "Invalid Password")
                    {
                        isValid = false;
                    }
                }
                finally
                {
                    if (File.Exists(outputPath))
                    {
                        // careful, this can throw exceptions
                        File.Delete(outputPath);
                    }
                }
                if (!isValid)
                {
                    break;
                }
            }
        }
    }
    return isValid;
}

Apologies for the C#; should be fairly straightforward to convert to VB.NET.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜