527 lines
25 KiB
Java
527 lines
25 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==================================================================== */
|
|
package org.apache.poi.poifs.crypt;
|
|
|
|
import static org.junit.Assert.assertArrayEquals;
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.assertNull;
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.Iterator;
|
|
|
|
import javax.crypto.Cipher;
|
|
|
|
import org.apache.poi.POIDataSamples;
|
|
import org.apache.poi.openxml4j.opc.ContentTypes;
|
|
import org.apache.poi.openxml4j.opc.OPCPackage;
|
|
import org.apache.poi.poifs.crypt.agile.AgileDecryptor;
|
|
import org.apache.poi.poifs.crypt.agile.AgileEncryptionHeader;
|
|
import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier;
|
|
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
|
import org.apache.poi.poifs.filesystem.DocumentNode;
|
|
import org.apache.poi.poifs.filesystem.Entry;
|
|
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
|
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
|
import org.apache.poi.util.BoundedInputStream;
|
|
import org.apache.poi.util.IOUtils;
|
|
import org.apache.poi.util.TempFile;
|
|
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
|
import org.junit.Assume;
|
|
import org.junit.Ignore;
|
|
import org.junit.Test;
|
|
|
|
public class TestEncryptor {
|
|
@Test
|
|
public void binaryRC4Encryption() throws Exception {
|
|
// please contribute a real sample file, which is binary rc4 encrypted
|
|
// ... at least the output can be opened in Excel Viewer
|
|
String password = "pass";
|
|
|
|
InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleMultiCell.xlsx");
|
|
ByteArrayOutputStream payloadExpected = new ByteArrayOutputStream();
|
|
IOUtils.copy(is, payloadExpected);
|
|
is.close();
|
|
|
|
POIFSFileSystem fs = new POIFSFileSystem();
|
|
EncryptionInfo ei = new EncryptionInfo(EncryptionMode.binaryRC4);
|
|
Encryptor enc = ei.getEncryptor();
|
|
enc.confirmPassword(password);
|
|
|
|
OutputStream os = enc.getDataStream(fs.getRoot());
|
|
payloadExpected.writeTo(os);
|
|
os.close();
|
|
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
fs.writeFilesystem(bos);
|
|
|
|
fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
|
|
ei = new EncryptionInfo(fs);
|
|
Decryptor dec = ei.getDecryptor();
|
|
boolean b = dec.verifyPassword(password);
|
|
assertTrue(b);
|
|
|
|
ByteArrayOutputStream payloadActual = new ByteArrayOutputStream();
|
|
is = dec.getDataStream(fs.getRoot());
|
|
IOUtils.copy(is,payloadActual);
|
|
is.close();
|
|
|
|
assertArrayEquals(payloadExpected.toByteArray(), payloadActual.toByteArray());
|
|
}
|
|
|
|
@Test
|
|
public void agileEncryption() throws Exception {
|
|
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
|
|
Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
|
|
|
|
File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-pass.docx");
|
|
String pass = "pass";
|
|
NPOIFSFileSystem nfs = new NPOIFSFileSystem(file);
|
|
|
|
// Check the encryption details
|
|
EncryptionInfo infoExpected = new EncryptionInfo(nfs);
|
|
Decryptor decExpected = Decryptor.getInstance(infoExpected);
|
|
boolean passed = decExpected.verifyPassword(pass);
|
|
assertTrue("Unable to process: document is encrypted", passed);
|
|
|
|
// extract the payload
|
|
InputStream is = decExpected.getDataStream(nfs);
|
|
byte payloadExpected[] = IOUtils.toByteArray(is);
|
|
is.close();
|
|
|
|
long decPackLenExpected = decExpected.getLength();
|
|
assertEquals(decPackLenExpected, payloadExpected.length);
|
|
|
|
is = nfs.getRoot().createDocumentInputStream(Decryptor.DEFAULT_POIFS_ENTRY);
|
|
is = new BoundedInputStream(is, is.available()-16); // ignore padding block
|
|
byte encPackExpected[] = IOUtils.toByteArray(is);
|
|
is.close();
|
|
|
|
// listDir(nfs.getRoot(), "orig", "");
|
|
|
|
nfs.close();
|
|
|
|
// check that same verifier/salt lead to same hashes
|
|
byte verifierSaltExpected[] = infoExpected.getVerifier().getSalt();
|
|
byte verifierExpected[] = decExpected.getVerifier();
|
|
byte keySalt[] = infoExpected.getHeader().getKeySalt();
|
|
byte keySpec[] = decExpected.getSecretKey().getEncoded();
|
|
byte integritySalt[] = decExpected.getIntegrityHmacKey();
|
|
// the hmacs of the file always differ, as we use PKCS5-padding to pad the bytes
|
|
// whereas office just uses random bytes
|
|
// byte integrityHash[] = d.getIntegrityHmacValue();
|
|
|
|
POIFSFileSystem fs = new POIFSFileSystem();
|
|
EncryptionInfo infoActual = new EncryptionInfo(
|
|
EncryptionMode.agile
|
|
, infoExpected.getVerifier().getCipherAlgorithm()
|
|
, infoExpected.getVerifier().getHashAlgorithm()
|
|
, infoExpected.getHeader().getKeySize()
|
|
, infoExpected.getHeader().getBlockSize()
|
|
, infoExpected.getVerifier().getChainingMode()
|
|
);
|
|
|
|
Encryptor e = Encryptor.getInstance(infoActual);
|
|
e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, integritySalt);
|
|
|
|
OutputStream os = e.getDataStream(fs);
|
|
IOUtils.copy(new ByteArrayInputStream(payloadExpected), os);
|
|
os.close();
|
|
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
fs.writeFilesystem(bos);
|
|
|
|
nfs = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
|
|
infoActual = new EncryptionInfo(nfs.getRoot());
|
|
Decryptor decActual = Decryptor.getInstance(infoActual);
|
|
passed = decActual.verifyPassword(pass);
|
|
assertTrue("Unable to process: document is encrypted", passed);
|
|
|
|
// extract the payload
|
|
is = decActual.getDataStream(nfs);
|
|
byte payloadActual[] = IOUtils.toByteArray(is);
|
|
is.close();
|
|
|
|
long decPackLenActual = decActual.getLength();
|
|
|
|
is = nfs.getRoot().createDocumentInputStream(Decryptor.DEFAULT_POIFS_ENTRY);
|
|
is = new BoundedInputStream(is, is.available()-16); // ignore padding block
|
|
byte encPackActual[] = IOUtils.toByteArray(is);
|
|
is.close();
|
|
|
|
// listDir(nfs.getRoot(), "copy", "");
|
|
|
|
nfs.close();
|
|
|
|
AgileEncryptionHeader aehExpected = (AgileEncryptionHeader)infoExpected.getHeader();
|
|
AgileEncryptionHeader aehActual = (AgileEncryptionHeader)infoActual.getHeader();
|
|
assertArrayEquals(aehExpected.getEncryptedHmacKey(), aehActual.getEncryptedHmacKey());
|
|
assertEquals(decPackLenExpected, decPackLenActual);
|
|
assertArrayEquals(payloadExpected, payloadActual);
|
|
assertArrayEquals(encPackExpected, encPackActual);
|
|
}
|
|
|
|
@Test
|
|
public void standardEncryption() throws Exception {
|
|
File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-solrcell.docx");
|
|
String pass = "solrcell";
|
|
|
|
NPOIFSFileSystem nfs = new NPOIFSFileSystem(file);
|
|
|
|
// Check the encryption details
|
|
EncryptionInfo infoExpected = new EncryptionInfo(nfs);
|
|
Decryptor d = Decryptor.getInstance(infoExpected);
|
|
boolean passed = d.verifyPassword(pass);
|
|
assertTrue("Unable to process: document is encrypted", passed);
|
|
|
|
// extract the payload
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
InputStream is = d.getDataStream(nfs);
|
|
IOUtils.copy(is, bos);
|
|
is.close();
|
|
nfs.close();
|
|
byte payloadExpected[] = bos.toByteArray();
|
|
|
|
// check that same verifier/salt lead to same hashes
|
|
byte verifierSaltExpected[] = infoExpected.getVerifier().getSalt();
|
|
byte verifierExpected[] = d.getVerifier();
|
|
byte keySpec[] = d.getSecretKey().getEncoded();
|
|
byte keySalt[] = infoExpected.getHeader().getKeySalt();
|
|
|
|
|
|
EncryptionInfo infoActual = new EncryptionInfo(
|
|
EncryptionMode.standard
|
|
, infoExpected.getVerifier().getCipherAlgorithm()
|
|
, infoExpected.getVerifier().getHashAlgorithm()
|
|
, infoExpected.getHeader().getKeySize()
|
|
, infoExpected.getHeader().getBlockSize()
|
|
, infoExpected.getVerifier().getChainingMode()
|
|
);
|
|
|
|
Encryptor e = Encryptor.getInstance(infoActual);
|
|
e.confirmPassword(pass, keySpec, keySalt, verifierExpected, verifierSaltExpected, null);
|
|
|
|
assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifier(), infoActual.getVerifier().getEncryptedVerifier());
|
|
assertArrayEquals(infoExpected.getVerifier().getEncryptedVerifierHash(), infoActual.getVerifier().getEncryptedVerifierHash());
|
|
|
|
// now we use a newly generated salt/verifier and check
|
|
// if the file content is still the same
|
|
|
|
infoActual = new EncryptionInfo(
|
|
EncryptionMode.standard
|
|
, infoExpected.getVerifier().getCipherAlgorithm()
|
|
, infoExpected.getVerifier().getHashAlgorithm()
|
|
, infoExpected.getHeader().getKeySize()
|
|
, infoExpected.getHeader().getBlockSize()
|
|
, infoExpected.getVerifier().getChainingMode()
|
|
);
|
|
|
|
e = Encryptor.getInstance(infoActual);
|
|
e.confirmPassword(pass);
|
|
|
|
POIFSFileSystem fs = new POIFSFileSystem();
|
|
OutputStream os = e.getDataStream(fs);
|
|
IOUtils.copy(new ByteArrayInputStream(payloadExpected), os);
|
|
os.close();
|
|
|
|
bos.reset();
|
|
fs.writeFilesystem(bos);
|
|
|
|
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
|
|
|
// FileOutputStream fos = new FileOutputStream("encrypted.docx");
|
|
// IOUtils.copy(bis, fos);
|
|
// fos.close();
|
|
// bis.reset();
|
|
|
|
nfs = new NPOIFSFileSystem(bis);
|
|
infoExpected = new EncryptionInfo(nfs);
|
|
d = Decryptor.getInstance(infoExpected);
|
|
passed = d.verifyPassword(pass);
|
|
assertTrue("Unable to process: document is encrypted", passed);
|
|
|
|
bos.reset();
|
|
is = d.getDataStream(nfs);
|
|
IOUtils.copy(is, bos);
|
|
is.close();
|
|
nfs.close();
|
|
byte payloadActual[] = bos.toByteArray();
|
|
|
|
assertArrayEquals(payloadExpected, payloadActual);
|
|
}
|
|
|
|
/**
|
|
* Ensure we can encrypt a package that is missing the Core
|
|
* Properties, eg one from dodgy versions of Jasper Reports
|
|
* See https://github.com/nestoru/xlsxenc/ and
|
|
* http://stackoverflow.com/questions/28593223
|
|
*/
|
|
@Test
|
|
public void encryptPackageWithoutCoreProperties() throws Exception {
|
|
// Open our file without core properties
|
|
File inp = POIDataSamples.getOpenXML4JInstance().getFile("OPCCompliance_NoCoreProperties.xlsx");
|
|
OPCPackage pkg = OPCPackage.open(inp.getPath());
|
|
|
|
// It doesn't have any core properties yet
|
|
assertEquals(0, pkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
|
|
assertNotNull(pkg.getPackageProperties());
|
|
assertNotNull(pkg.getPackageProperties().getLanguageProperty());
|
|
assertNull(pkg.getPackageProperties().getLanguageProperty().getValue());
|
|
|
|
// Encrypt it
|
|
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
|
|
NPOIFSFileSystem fs = new NPOIFSFileSystem();
|
|
|
|
Encryptor enc = info.getEncryptor();
|
|
enc.confirmPassword("password");
|
|
OutputStream os = enc.getDataStream(fs);
|
|
pkg.save(os);
|
|
pkg.revert();
|
|
|
|
// Save the resulting OLE2 document, and re-open it
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
fs.writeFilesystem(baos);
|
|
|
|
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
|
NPOIFSFileSystem inpFS = new NPOIFSFileSystem(bais);
|
|
|
|
// Check we can decrypt it
|
|
info = new EncryptionInfo(inpFS);
|
|
Decryptor d = Decryptor.getInstance(info);
|
|
assertEquals(true, d.verifyPassword("password"));
|
|
|
|
OPCPackage inpPkg = OPCPackage.open(d.getDataStream(inpFS));
|
|
|
|
// Check it now has empty core properties
|
|
assertEquals(1, inpPkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
|
|
assertNotNull(inpPkg.getPackageProperties());
|
|
assertNotNull(inpPkg.getPackageProperties().getLanguageProperty());
|
|
assertNull(inpPkg.getPackageProperties().getLanguageProperty().getValue());
|
|
}
|
|
|
|
@Test
|
|
@Ignore
|
|
public void inPlaceRewrite() throws Exception {
|
|
File f = TempFile.createTempFile("protected_agile", ".docx");
|
|
// File f = new File("protected_agile.docx");
|
|
FileOutputStream fos = new FileOutputStream(f);
|
|
InputStream fis = POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_agile.docx");
|
|
IOUtils.copy(fis, fos);
|
|
fis.close();
|
|
fos.close();
|
|
|
|
NPOIFSFileSystem fs = new NPOIFSFileSystem(f, false);
|
|
|
|
// decrypt the protected file - in this case it was encrypted with the default password
|
|
EncryptionInfo encInfo = new EncryptionInfo(fs);
|
|
Decryptor d = encInfo.getDecryptor();
|
|
boolean b = d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
|
|
assertTrue(b);
|
|
|
|
// do some strange things with it ;)
|
|
XWPFDocument docx = new XWPFDocument(d.getDataStream(fs));
|
|
docx.getParagraphArray(0).insertNewRun(0).setText("POI was here! All your base are belong to us!");
|
|
docx.getParagraphArray(0).insertNewRun(1).addBreak();
|
|
|
|
// and encrypt it again
|
|
Encryptor e = encInfo.getEncryptor();
|
|
e.confirmPassword("AYBABTU");
|
|
docx.write(e.getDataStream(fs));
|
|
|
|
docx.close();
|
|
fs.close();
|
|
}
|
|
|
|
|
|
private void listEntry(DocumentNode de, String ext, String path) throws IOException {
|
|
path += "\\" + de.getName().replaceAll("[\\p{Cntrl}]", "_");
|
|
System.out.println(ext+": "+path+" ("+de.getSize()+" bytes)");
|
|
|
|
String name = de.getName().replaceAll("[\\p{Cntrl}]", "_");
|
|
|
|
InputStream is = ((DirectoryNode)de.getParent()).createDocumentInputStream(de);
|
|
FileOutputStream fos = new FileOutputStream("solr."+name+"."+ext);
|
|
IOUtils.copy(is, fos);
|
|
fos.close();
|
|
is.close();
|
|
}
|
|
|
|
@SuppressWarnings("unused")
|
|
private void listDir(DirectoryNode dn, String ext, String path) throws IOException {
|
|
path += "\\" + dn.getName().replace('\u0006', '_');
|
|
System.out.println(ext+": "+path+" ("+dn.getStorageClsid()+")");
|
|
|
|
Iterator<Entry> iter = dn.getEntries();
|
|
while (iter.hasNext()) {
|
|
Entry ent = iter.next();
|
|
if (ent instanceof DirectoryNode) {
|
|
listDir((DirectoryNode)ent, ext, path);
|
|
} else {
|
|
listEntry((DocumentNode)ent, ext, path);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* this test simulates the generation of bugs 60320 sample file
|
|
* as the padding bytes of the EncryptedPackage stream are random or in POIs case PKCS5-padded
|
|
* one would need to mock those bytes to get the same hmacValues - see diff below
|
|
*
|
|
* this use-case is experimental - for the time being the setters of the encryption classes
|
|
* are spreaded between two packages and are protected - so you would need to violate
|
|
* the packages rules and provide a helper class in the *poifs.crypt package-namespace.
|
|
* the default way of defining the encryption settings is via the EncryptionInfo class
|
|
*/
|
|
@Test
|
|
public void bug60320CustomEncrypt() throws Exception {
|
|
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
|
|
Assume.assumeTrue("Please install JCE Unlimited Strength Jurisdiction Policy files for AES 256", maxKeyLen == 2147483647);
|
|
|
|
// --- src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java (revision 1766745)
|
|
// +++ src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java (working copy)
|
|
// @@ -208,6 +208,13 @@
|
|
// protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException {
|
|
// byte plain[] = (_plainByteFlags.isEmpty()) ? null : _chunk.clone();
|
|
//
|
|
// + if (posInChunk < 4096) {
|
|
// + _cipher.update(_chunk, 0, posInChunk, _chunk);
|
|
// + byte bla[] = { (byte)0x7A,(byte)0x0F,(byte)0x27,(byte)0xF0,(byte)0x17,(byte)0x6E,(byte)0x77,(byte)0x05,(byte)0xB9,(byte)0xDA,(byte)0x49,(byte)0xF9,(byte)0xD7,(byte)0x8E,(byte)0x03,(byte)0x1D };
|
|
// + System.arraycopy(bla, 0, _chunk, posInChunk-2, bla.length);
|
|
// + return posInChunk-2+bla.length;
|
|
// + }
|
|
// +
|
|
// int ciLen = (doFinal)
|
|
// ? _cipher.doFinal(_chunk, 0, posInChunk, _chunk)
|
|
// : _cipher.update(_chunk, 0, posInChunk, _chunk);
|
|
//
|
|
// --- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (revision 1766745)
|
|
// +++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (working copy)
|
|
//
|
|
// @@ -300,7 +297,7 @@
|
|
// protected static Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int encryptionMode)
|
|
// throws GeneralSecurityException {
|
|
// EncryptionHeader header = encryptionInfo.getHeader();
|
|
// - String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
|
|
// + String padding = "NoPadding"; // (lastChunk ? "PKCS5Padding" : "NoPadding");
|
|
// if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
|
|
// existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
|
|
// }
|
|
|
|
InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
|
|
POIFSFileSystem fsOrig = new POIFSFileSystem(is);
|
|
is.close();
|
|
EncryptionInfo infoOrig = new EncryptionInfo(fsOrig);
|
|
Decryptor decOrig = infoOrig.getDecryptor();
|
|
boolean b = decOrig.verifyPassword("Test001!!");
|
|
assertTrue(b);
|
|
InputStream decIn = decOrig.getDataStream(fsOrig);
|
|
byte[] zipInput = IOUtils.toByteArray(decIn);
|
|
decIn.close();
|
|
|
|
InputStream epOrig = fsOrig.getRoot().createDocumentInputStream("EncryptedPackage");
|
|
// ignore the 16 padding bytes
|
|
byte[] epOrigBytes = IOUtils.toByteArray(epOrig, 9400);
|
|
epOrig.close();
|
|
|
|
EncryptionInfo eiNew = new EncryptionInfo(EncryptionMode.agile);
|
|
AgileEncryptionHeader aehHeader = (AgileEncryptionHeader)eiNew.getHeader();
|
|
aehHeader.setCipherAlgorithm(CipherAlgorithm.aes128);
|
|
aehHeader.setHashAlgorithm(HashAlgorithm.sha1);
|
|
AgileEncryptionVerifier aehVerifier = (AgileEncryptionVerifier)eiNew.getVerifier();
|
|
|
|
// this cast might look strange - if the setters would be public, it will become obsolete
|
|
// see http://stackoverflow.com/questions/5637650/overriding-protected-methods-in-java
|
|
((EncryptionVerifier)aehVerifier).setCipherAlgorithm(CipherAlgorithm.aes256);
|
|
aehVerifier.setHashAlgorithm(HashAlgorithm.sha512);
|
|
|
|
Encryptor enc = eiNew.getEncryptor();
|
|
enc.confirmPassword("Test001!!",
|
|
infoOrig.getDecryptor().getSecretKey().getEncoded(),
|
|
infoOrig.getHeader().getKeySalt(),
|
|
infoOrig.getDecryptor().getVerifier(),
|
|
infoOrig.getVerifier().getSalt(),
|
|
infoOrig.getDecryptor().getIntegrityHmacKey()
|
|
);
|
|
NPOIFSFileSystem fsNew = new NPOIFSFileSystem();
|
|
OutputStream os = enc.getDataStream(fsNew);
|
|
os.write(zipInput);
|
|
os.close();
|
|
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
fsNew.writeFilesystem(bos);
|
|
fsNew.close();
|
|
|
|
NPOIFSFileSystem fsReload = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
|
|
InputStream epReload = fsReload.getRoot().createDocumentInputStream("EncryptedPackage");
|
|
byte[] epNewBytes = IOUtils.toByteArray(epReload, 9400);
|
|
epReload.close();
|
|
|
|
assertArrayEquals(epOrigBytes, epNewBytes);
|
|
|
|
EncryptionInfo infoReload = new EncryptionInfo(fsOrig);
|
|
Decryptor decReload = infoReload.getDecryptor();
|
|
b = decReload.verifyPassword("Test001!!");
|
|
assertTrue(b);
|
|
|
|
AgileEncryptionHeader aehOrig = (AgileEncryptionHeader)infoOrig.getHeader();
|
|
AgileEncryptionHeader aehReload = (AgileEncryptionHeader)infoReload.getHeader();
|
|
assertEquals(aehOrig.getBlockSize(), aehReload.getBlockSize());
|
|
assertEquals(aehOrig.getChainingMode(), aehReload.getChainingMode());
|
|
assertEquals(aehOrig.getCipherAlgorithm(), aehReload.getCipherAlgorithm());
|
|
assertEquals(aehOrig.getCipherProvider(), aehReload.getCipherProvider());
|
|
assertEquals(aehOrig.getCspName(), aehReload.getCspName());
|
|
assertArrayEquals(aehOrig.getEncryptedHmacKey(), aehReload.getEncryptedHmacKey());
|
|
// this only works, when the paddings are mocked to be the same ...
|
|
// assertArrayEquals(aehOrig.getEncryptedHmacValue(), aehReload.getEncryptedHmacValue());
|
|
assertEquals(aehOrig.getFlags(), aehReload.getFlags());
|
|
assertEquals(aehOrig.getHashAlgorithm(), aehReload.getHashAlgorithm());
|
|
assertArrayEquals(aehOrig.getKeySalt(), aehReload.getKeySalt());
|
|
assertEquals(aehOrig.getKeySize(), aehReload.getKeySize());
|
|
|
|
AgileEncryptionVerifier aevOrig = (AgileEncryptionVerifier)infoOrig.getVerifier();
|
|
AgileEncryptionVerifier aevReload = (AgileEncryptionVerifier)infoReload.getVerifier();
|
|
assertEquals(aevOrig.getBlockSize(), aevReload.getBlockSize());
|
|
assertEquals(aevOrig.getChainingMode(), aevReload.getChainingMode());
|
|
assertEquals(aevOrig.getCipherAlgorithm(), aevReload.getCipherAlgorithm());
|
|
assertArrayEquals(aevOrig.getEncryptedKey(), aevReload.getEncryptedKey());
|
|
assertArrayEquals(aevOrig.getEncryptedVerifier(), aevReload.getEncryptedVerifier());
|
|
assertArrayEquals(aevOrig.getEncryptedVerifierHash(), aevReload.getEncryptedVerifierHash());
|
|
assertEquals(aevOrig.getHashAlgorithm(), aevReload.getHashAlgorithm());
|
|
assertEquals(aevOrig.getKeySize(), aevReload.getKeySize());
|
|
assertArrayEquals(aevOrig.getSalt(), aevReload.getSalt());
|
|
assertEquals(aevOrig.getSpinCount(), aevReload.getSpinCount());
|
|
|
|
AgileDecryptor adOrig = (AgileDecryptor)infoOrig.getDecryptor();
|
|
AgileDecryptor adReload = (AgileDecryptor)infoReload.getDecryptor();
|
|
|
|
assertArrayEquals(adOrig.getIntegrityHmacKey(), adReload.getIntegrityHmacKey());
|
|
// doesn't work without mocking ... see above
|
|
// assertArrayEquals(adOrig.getIntegrityHmacValue(), adReload.getIntegrityHmacValue());
|
|
assertArrayEquals(adOrig.getSecretKey().getEncoded(), adReload.getSecretKey().getEncoded());
|
|
assertArrayEquals(adOrig.getVerifier(), adReload.getVerifier());
|
|
|
|
fsReload.close();
|
|
}
|
|
}
|