Zip4J -> java.security.ProviderException: 无法构建 MacSpi 实例

Zip4J -> java.security.ProviderException: Could not construct MacSpi instance

我正在尝试使用 lingala zip4j 来归档 X509Certificate 个文件。

但是,只有在使用 Junit 进行单元测试时,我才会遇到这个奇怪的异常。

如果我 运行 我的应用程序作为产品(这是一个 spring 网络应用程序)- 它工作正常,没有例外,我能够正确地归档和取消归档文件,没有问题。

net.lingala.zip4j.exception.ZipException: java.security.ProviderException: Could not construct MacSpi instance

    at net.lingala.zip4j.crypto.AESEncrpyter.deriveKey(AESEncrpyter.java:116)
    at net.lingala.zip4j.crypto.AESEncrpyter.init(AESEncrpyter.java:89)
    at net.lingala.zip4j.crypto.AESEncrpyter.<init>(AESEncrpyter.java:69)
    at net.lingala.zip4j.io.CipherOutputStream.initEncrypter(CipherOutputStream.java:173)
    at net.lingala.zip4j.io.CipherOutputStream.putNextEntry(CipherOutputStream.java:133)
    at net.lingala.zip4j.io.DeflaterOutputStream.putNextEntry(DeflaterOutputStream.java:45)
    ...

Caused by: java.security.ProviderException: Could not construct MacSpi instance
    at javax.crypto.Mac.chooseFirstProvider(Mac.java:316)
    at javax.crypto.Mac.getMacLength(Mac.java:398)
    at net.lingala.zip4j.crypto.PBKDF2.MacBasedPRF.<init>(MacBasedPRF.java:45)
    at net.lingala.zip4j.crypto.PBKDF2.PBKDF2Engine.assertPRF(PBKDF2Engine.java:103)
    at net.lingala.zip4j.crypto.PBKDF2.PBKDF2Engine.deriveKey(PBKDF2Engine.java:66)
    at net.lingala.zip4j.crypto.AESEncrpyter.deriveKey(AESEncrpyter.java:113)
    ... 

这是我的 Utils 代码,它存档了我使用过的证书:

import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.UUID;

public class ZipTestUtils {

    public static byte[] archive(List<X509Certificate> certificateList, String password)
            throws IOException, CertificateEncodingException, ZipException {

        byte[] bytes = null;

        // --------Encryption zipParameters (for password protection)--------
        ZipParameters zipParameters = getZipParameters(password);

        // -------------------- CREATE ZIP file --------------------
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream outputZipStream = new ZipOutputStream(outputStream);

        // Create ZIP file
        for (X509Certificate certificate : certificateList) {
            if (certificate == null) {
                // skip invalid entries.
                continue;
            }

            File file = File.createTempFile(UUID.randomUUID().toString(), ".cer");
            file.deleteOnExit();

            outputZipStream.putNextEntry(file, zipParameters);
            outputZipStream.write(CertificateTestUtils.encodeCertificate(certificate));
            outputZipStream.closeEntry();
        }

        //finish up
        outputZipStream.finish();

        bytes = outputStream.toByteArray();


        return bytes;
    }

    private static ZipParameters getZipParameters(String password) {
        // Create ZipParameters
        ZipParameters zipParameters = new ZipParameters();

        // Set how you want to encrypt files
        zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

        // Set encryption of files to true
        zipParameters.setEncryptFiles(true);

        // Set encryption method
        zipParameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
        // Set key strength
        zipParameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);

        // Set password
        zipParameters.setPassword(password);
        return zipParameters;
    }
}

我正在使用 Java 1.6

我也试过使用 1.8,但我遇到了同样的错误。

注意:这仅在我 运行 使用 Junit 时发生...

我发现 运行 PowerMockRunner.class 的测试导致了这个问题的发生。

我不确定为什么会这样。我能够通过反射创建我的模拟来克服这个问题,而不必使用 PowerMock.

我已经解决了眼前的问题,但这是一个非常奇怪的问题,如果有人知道为什么会这样,我仍然想知道。

添加这个会有所帮助 - @PowerMockIgnore({"javax.crypto.*" })

更多信息请参考这里 - https://github.com/powermock/powermock/issues/294