omicronapps / 7-Zip-JBinding-4Android

Android Java wrapper for 7z archiver engine
GNU Lesser General Public License v2.1
121 stars 24 forks source link

Use SevenZip.openInArchive to decompress a zip file with a password and prompt "Extract archive, completed with: WRONG_PASSWORD" #26

Closed li599020295 closed 2 years ago

li599020295 commented 2 years ago

Hello dear open source authors: I am using SevenZip.openInArchive() to extract a zip file with a password and the console prompts "completed with: WRONG_PASSWORD", but I am sure that the password entered is correct.

Here is my test code: `public class SevenZipUtil { private final static int FILE_BUFFER_SIZE = 4096; public static void unZip(String src,String desc,String passWord) {

}
public SevenZipUtil(){
    testVersion();
}
private static final String TAG = "TestExtract"; 

public void testVersion() {
    SevenZip.Version version = SevenZip.getSevenZipVersion();
    Log.i(TAG, "7-zip version: " + version.major + "." + version.minor + "." + version.build + " (" + version.version + "), " + version.date + version.copyright);
    Log.i(TAG, "7-Zip-JBinding version: " + SevenZip.getSevenZipJBindingVersion());
    Log.i(TAG, "Native library initialized: " + SevenZip.isInitializedSuccessfully());
}

public void testExtract(File file,String passWord) {
    if(SevenZip.isInitializedSuccessfully()){
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            RandomAccessFileInStream inStream = new RandomAccessFileInStream(randomAccessFile);
            //  ArchiveOpenCallback callback = new ArchiveOpenCallback("123");
            IInArchive inArchive = SevenZip.openInArchive(null, inStream,passWord);

            ArchiveExtractCallback extractCallback = new ArchiveExtractCallback();
            inArchive.extract(null, false, extractCallback);

            inArchive.close();
            inStream.close();
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getMessage());
        } catch (SevenZipException e) {
            Log.e(TAG, e.getMessage());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }

}

private class ArchiveOpenCallback implements ICryptoGetTextPassword,IArchiveOpenCallback {
    private String password;

    public ArchiveOpenCallback( String password) {
        this.password = password;
    }

    public String cryptoGetTextPassword() throws SevenZipException {
        return password;
    }
    @Override
    public void setTotal(Long files, Long bytes) {
        Log.i(TAG, "Archive open, total work: " + files + " files, " + bytes + " bytes");
    }

    @Override
    public void setCompleted(Long files, Long bytes) {
        Log.i(TAG, "Archive open, completed: " + files + " files, " + bytes + " bytes");
    }
}

private class ArchiveExtractCallback implements IArchiveExtractCallback {
    @Override
    public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
        Log.i(TAG, "Extract archive, get stream: " + index + " to: " + extractAskMode);
        SequentialOutStream stream = new SequentialOutStream();
        return stream;
    }

    @Override
    public void prepareOperation(ExtractAskMode extractAskMode) throws SevenZipException {
        Log.i(TAG, "Extract archive, prepare to: " + extractAskMode);
    }

    @Override
    public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
        Log.i(TAG, "Extract archive, completed with: " + extractOperationResult);
        if (extractOperationResult != ExtractOperationResult.OK) {
            throw new SevenZipException(extractOperationResult.toString());
        }
    }

    @Override
    public void setTotal(long total) throws SevenZipException {
        Log.i(TAG, "Extract archive, work planned: " + total);
    }

    @Override
    public void setCompleted(long complete) throws SevenZipException {
        Log.i(TAG, "Extract archive, work completed: " + complete);
    }
}

private class SequentialOutStream implements ISequentialOutStream {
    @Override
    public int write(byte[] data) throws SevenZipException {
        if (data == null || data.length == 0) {
            throw new SevenZipException("null data");
        }
        Log.i(TAG, "Data to write: " + data.length);
        return data.length;
    }
}

} `

call code: SevenZipUtil sz = new SevenZipUtil(); sz.testExtract(new File(fileModel.getPath()),"123");

Console output log: 2022-07-24 22:23:36.546 21169-21169/com.example.fileunzip I/TestExtract: 7-zip version: 16.2.0 (16.02), 2016-05-21Igor Pavlov : Public domain 2022-07-24 22:23:36.546 21169-21169/com.example.fileunzip I/TestExtract: 7-Zip-JBinding version: 16.02-2.02 2022-07-24 22:23:36.546 21169-21169/com.example.fileunzip I/TestExtract: Native library initialized: true 2022-07-24 22:23:36.552 21169-21169/com.example.fileunzip I/TestExtract: Extract archive, work planned: 16777216 2022-07-24 22:23:36.552 21169-21169/com.example.fileunzip I/TestExtract: Extract archive, work completed: 0 2022-07-24 22:23:36.552 21169-21169/com.example.fileunzip I/TestExtract: Extract archive, get stream: 0 to: EXTRACT 2022-07-24 22:23:36.553 21169-21169/com.example.fileunzip I/TestExtract: Extract archive, prepare to: EXTRACT 2022-07-24 22:23:36.553 21169-21169/com.example.fileunzip I/TestExtract: Extract archive, completed with: WRONG_PASSWORD 2022-07-24 22:23:36.554 21169-21169/com.example.fileunzip E/TestExtract: HRESULT: 0x1 (FALSE). Error extracting all items

Android test environment: Android version: android 11

code version:7-ZIP-JBinding-4Android [Release-16.02-2.02]

Please help me, thanks a lot.

VoidK2 commented 2 years ago

seem like a bug

li599020295 commented 2 years ago

seem like a bug I refer to the code written by the official document, the compressed file without password can be decompressed normally, but the compressed file with password will prompt "WRONG_PASSWORD" if the correct password is entered. Currently I only found that SevenZip.openInArchive() cannot decompress zip files with passwords, because any correct password entered in the third parameter is invalid. Please help me if you have a solution, thanks a lot.

VoidK2 commented 2 years ago

check this, you are using the wrong stream,https://github.com/omicronapps/7-Zip-JBinding-4Android/issues/13#issuecomment-1190096234

li599020295 commented 2 years ago

check this, you are using the wrong stream,#13 (comment)

The problem with this code is that entering any correct password prompts "WRONG_PASSWORD". This code is copied from the official documentation, and does not contain file stream operations. Can only wait for the developer to help solve it. Thank you very much for your answer

VoidK2 commented 2 years ago

no, the document not right, ArchiveExtractCallback need stream implements ISeekableStream

li599020295 commented 2 years ago

no, the document not right, ArchiveExtractCallback need stream implements ISeekableStream

I don't know how to write this code, please help me, thanks a lot.

VoidK2 commented 2 years ago

sorry, cannot paste the code in there because privacy agreement. you see, the archivecallback return a stream to decide how to read a archive in lib, the other archive type is fine(7z,tar,gz..etc). but zip is different, need implement ISeekableStream, to random access the archive(may be read header data, or because deflate algorithm). notify: this is a lib with many defects and lack of documentation. It takes a lot of time to use this lib correctly.

li599020295 commented 2 years ago

sorry, cannot paste the code in there because privacy agreement. you see, the archivecallback return a stream to decide how to read a archive in lib, the other archive type is fine(7z,tar,gz..etc). but zip is different, need implement ISeekableStream, to random access the archive(may be read header data, or because deflate algorithm). notify: this is a lib with many defects and lack of documentation. It takes a lot of time to use this lib correctly.

OK, thanks a lot for your answer. Wait for the author to help fix this problem.

omicronapps commented 2 years ago

When calling IInArchive.html.extract(), the extractCallback argument must provide an instance that implements both the IArchiveExtractCallback interface and also the ICryptoGetTextPassword interface, in order for SevenZip to be able to acquire the password.

In your sample source code, I modified ArchiveExtractCallback to implement ICryptoGetTextPassword and IArchiveExtractCallback. I verified that it was possible extract a password protected zip-file using this solution.

package com.example.testextract;

import android.util.Log;

import net.sf.sevenzipjbinding.ExtractAskMode;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.IArchiveExtractCallback;
import net.sf.sevenzipjbinding.ICryptoGetTextPassword;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class SevenZipUtil {
    public SevenZipUtil(){
        testVersion();
    }
    private static final String TAG = "TestExtract";

    public void testVersion() {
        SevenZip.Version version = SevenZip.getSevenZipVersion();
        Log.i(TAG, "7-zip version: " + version.major + "." + version.minor + "." + version.build + " (" + version.version + "), " + version.date + version.copyright);
        Log.i(TAG, "7-Zip-JBinding version: " + SevenZip.getSevenZipJBindingVersion());
        Log.i(TAG, "Native library initialized: " + SevenZip.isInitializedSuccessfully());
    }

    public void testExtract(File file, String passWord) {
        if(SevenZip.isInitializedSuccessfully()){
            try {
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
                RandomAccessFileInStream inStream = new RandomAccessFileInStream(randomAccessFile);
                //  ArchiveOpenCallback callback = new ArchiveOpenCallback("123");
                IInArchive inArchive = SevenZip.openInArchive(null, inStream,passWord);

                ArchiveExtractCallback extractCallback = new ArchiveExtractCallback(passWord);
                inArchive.extract(null, false, extractCallback);

                inArchive.close();
                inStream.close();
            } catch (FileNotFoundException e) {
                Log.e(TAG, e.getMessage());
            } catch (SevenZipException e) {
                Log.e(TAG, e.getMessage());
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
            }
        }

    }

    private class ArchiveExtractCallback implements ICryptoGetTextPassword, IArchiveExtractCallback {
        private String password;

        public ArchiveExtractCallback( String password) {
            this.password = password;
        }

        public String cryptoGetTextPassword() throws SevenZipException {
            return password;
        }

        @Override
        public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
            Log.i(TAG, "Extract archive, get stream: " + index + " to: " + extractAskMode);
            SequentialOutStream stream = new SequentialOutStream();
            return stream;
        }

        @Override
        public void prepareOperation(ExtractAskMode extractAskMode) throws SevenZipException {
            Log.i(TAG, "Extract archive, prepare to: " + extractAskMode);
        }

        @Override
        public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
            Log.i(TAG, "Extract archive, completed with: " + extractOperationResult);
            if (extractOperationResult != ExtractOperationResult.OK) {
                throw new SevenZipException(extractOperationResult.toString());
            }
        }

        @Override
        public void setTotal(long total) throws SevenZipException {
            Log.i(TAG, "Extract archive, work planned: " + total);
        }

        @Override
        public void setCompleted(long complete) throws SevenZipException {
            Log.i(TAG, "Extract archive, work completed: " + complete);
        }
    }

    private class SequentialOutStream implements ISequentialOutStream {
        @Override
        public int write(byte[] data) throws SevenZipException {
            if (data == null || data.length == 0) {
                throw new SevenZipException("null data");
            }
            Log.i(TAG, "Data to write: " + data.length);
            return data.length;
        }
    }
}
omicronapps commented 2 years ago

notify: this is a lib with many defects and lack of documentation. It takes a lot of time to use this lib correctly.

Thanks for your feedback.

This library is a direct port of the Java library sevenzipjbinding. The Android version only adds the necessary code to use it on Android. There is no additional Android specific functionality or optimizations. It's basically a pure Java library running on Android, so it may not be optimal in all cases for Android. The documentation is what's available on first_steps and javadoc.

li599020295 commented 2 years ago

When calling IInArchive.html.extract(), the extractCallback argument must provide an instance that implements both the IArchiveExtractCallback interface and also the ICryptoGetTextPassword interface, in order for SevenZip to be able to acquire the password.

In your sample source code, I modified ArchiveExtractCallback to implement ICryptoGetTextPassword and IArchiveExtractCallback. I verified that it was possible extract a password protected zip-file using this solution.

package com.example.testextract;

import android.util.Log;

import net.sf.sevenzipjbinding.ExtractAskMode;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.IArchiveExtractCallback;
import net.sf.sevenzipjbinding.ICryptoGetTextPassword;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class SevenZipUtil {
    public SevenZipUtil(){
        testVersion();
    }
    private static final String TAG = "TestExtract";

    public void testVersion() {
        SevenZip.Version version = SevenZip.getSevenZipVersion();
        Log.i(TAG, "7-zip version: " + version.major + "." + version.minor + "." + version.build + " (" + version.version + "), " + version.date + version.copyright);
        Log.i(TAG, "7-Zip-JBinding version: " + SevenZip.getSevenZipJBindingVersion());
        Log.i(TAG, "Native library initialized: " + SevenZip.isInitializedSuccessfully());
    }

    public void testExtract(File file, String passWord) {
        if(SevenZip.isInitializedSuccessfully()){
            try {
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
                RandomAccessFileInStream inStream = new RandomAccessFileInStream(randomAccessFile);
                //  ArchiveOpenCallback callback = new ArchiveOpenCallback("123");
                IInArchive inArchive = SevenZip.openInArchive(null, inStream,passWord);

                ArchiveExtractCallback extractCallback = new ArchiveExtractCallback(passWord);
                inArchive.extract(null, false, extractCallback);

                inArchive.close();
                inStream.close();
            } catch (FileNotFoundException e) {
                Log.e(TAG, e.getMessage());
            } catch (SevenZipException e) {
                Log.e(TAG, e.getMessage());
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
            }
        }

    }

    private class ArchiveExtractCallback implements ICryptoGetTextPassword, IArchiveExtractCallback {
        private String password;

        public ArchiveExtractCallback( String password) {
            this.password = password;
        }

        public String cryptoGetTextPassword() throws SevenZipException {
            return password;
        }

        @Override
        public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
            Log.i(TAG, "Extract archive, get stream: " + index + " to: " + extractAskMode);
            SequentialOutStream stream = new SequentialOutStream();
            return stream;
        }

        @Override
        public void prepareOperation(ExtractAskMode extractAskMode) throws SevenZipException {
            Log.i(TAG, "Extract archive, prepare to: " + extractAskMode);
        }

        @Override
        public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
            Log.i(TAG, "Extract archive, completed with: " + extractOperationResult);
            if (extractOperationResult != ExtractOperationResult.OK) {
                throw new SevenZipException(extractOperationResult.toString());
            }
        }

        @Override
        public void setTotal(long total) throws SevenZipException {
            Log.i(TAG, "Extract archive, work planned: " + total);
        }

        @Override
        public void setCompleted(long complete) throws SevenZipException {
            Log.i(TAG, "Extract archive, work completed: " + complete);
        }
    }

    private class SequentialOutStream implements ISequentialOutStream {
        @Override
        public int write(byte[] data) throws SevenZipException {
            if (data == null || data.length == 0) {
                throw new SevenZipException("null data");
            }
            Log.i(TAG, "Data to write: " + data.length);
            return data.length;
        }
    }
}

Thank you for your help. It solved my problem. Thanks again.