View | Details | Raw Unified | Return to bug 60153
Collapse All | Expand All

(-)a/src/ooxml/java/org/apache/poi/openxml4j/util/ZipEntrySource.java (-1 / +3 lines)
Lines 16-21 Link Here
16
==================================================================== */
16
==================================================================== */
17
package org.apache.poi.openxml4j.util;
17
package org.apache.poi.openxml4j.util;
18
18
19
import java.io.Closeable;
19
import java.io.IOException;
20
import java.io.IOException;
20
import java.io.InputStream;
21
import java.io.InputStream;
21
import java.util.Enumeration;
22
import java.util.Enumeration;
Lines 28-34 import java.util.zip.ZipEntry; Link Here
28
 *  needing to worry about ZipFile vs ZipInputStream
29
 *  needing to worry about ZipFile vs ZipInputStream
29
 *  being annoyingly very different.
30
 *  being annoyingly very different.
30
 */
31
 */
31
public interface ZipEntrySource {
32
public interface ZipEntrySource extends Closeable {
32
	/**
33
	/**
33
	 * Returns an Enumeration of all the Entries
34
	 * Returns an Enumeration of all the Entries
34
	 */
35
	 */
Lines 44-49 public interface ZipEntrySource { Link Here
44
	 * Indicates we are done with reading, and 
45
	 * Indicates we are done with reading, and 
45
	 *  resources may be freed
46
	 *  resources may be freed
46
	 */
47
	 */
48
	@Override
47
	public void close() throws IOException;
49
	public void close() throws IOException;
48
	
50
	
49
	/**
51
	/**
(-)a/src/ooxml/testcases/org/apache/poi/poifs/crypt/AesZipFileZipEntrySource.java (-2 / +4 lines)
Lines 69-76 public class AesZipFileZipEntrySource implements ZipEntrySource { Link Here
69
69
70
    @Override
70
    @Override
71
    public void close() throws IOException {
71
    public void close() throws IOException {
72
        zipFile.close();
72
        if(!closed) {
73
        tmpFile.delete();
73
            zipFile.close();
74
            tmpFile.delete();
75
        }
74
        closed = true;
76
        closed = true;
75
    }
77
    }
76
    
78
    
(-)a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFWorkbookWithCustomZipEntrySource.java (-8 / +121 lines)
Lines 19-28 Link Here
19
19
20
package org.apache.poi.xssf.streaming;
20
package org.apache.poi.xssf.streaming;
21
21
22
import static java.nio.charset.StandardCharsets.UTF_8;
22
import static org.junit.Assert.assertEquals;
23
import static org.junit.Assert.assertEquals;
24
import static org.junit.Assert.assertFalse;
25
import static org.junit.Assert.assertTrue;
23
26
24
import java.io.ByteArrayInputStream;
27
import java.io.ByteArrayInputStream;
25
import java.io.ByteArrayOutputStream;
28
import java.io.ByteArrayOutputStream;
29
import java.io.File;
26
import java.io.FileInputStream;
30
import java.io.FileInputStream;
27
import java.io.FileOutputStream;
31
import java.io.FileOutputStream;
28
import java.io.IOException;
32
import java.io.IOException;
Lines 30-48 import java.io.InputStream; Link Here
30
import java.io.OutputStream;
34
import java.io.OutputStream;
31
import java.security.GeneralSecurityException;
35
import java.security.GeneralSecurityException;
32
import java.security.SecureRandom;
36
import java.security.SecureRandom;
37
import java.util.ArrayList;
38
import java.util.List;
33
39
34
import javax.crypto.Cipher;
40
import javax.crypto.Cipher;
35
import javax.crypto.CipherInputStream;
41
import javax.crypto.CipherInputStream;
36
import javax.crypto.CipherOutputStream;
42
import javax.crypto.CipherOutputStream;
37
import javax.crypto.spec.SecretKeySpec;
43
import javax.crypto.spec.SecretKeySpec;
38
44
45
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
46
import org.apache.poi.openxml4j.opc.OPCPackage;
39
import org.apache.poi.openxml4j.util.ZipEntrySource;
47
import org.apache.poi.openxml4j.util.ZipEntrySource;
40
import org.apache.poi.poifs.crypt.AesZipFileZipEntrySource;
48
import org.apache.poi.poifs.crypt.AesZipFileZipEntrySource;
41
import org.apache.poi.poifs.crypt.ChainingMode;
49
import org.apache.poi.poifs.crypt.ChainingMode;
42
import org.apache.poi.poifs.crypt.CipherAlgorithm;
50
import org.apache.poi.poifs.crypt.CipherAlgorithm;
43
import org.apache.poi.poifs.crypt.CryptoFunctions;
51
import org.apache.poi.poifs.crypt.CryptoFunctions;
52
import org.apache.poi.util.IOUtils;
44
import org.apache.poi.util.POILogFactory;
53
import org.apache.poi.util.POILogFactory;
45
import org.apache.poi.util.POILogger;
54
import org.apache.poi.util.POILogger;
55
import org.apache.poi.util.TempFile;
46
import org.apache.poi.xssf.usermodel.XSSFCell;
56
import org.apache.poi.xssf.usermodel.XSSFCell;
47
import org.apache.poi.xssf.usermodel.XSSFRow;
57
import org.apache.poi.xssf.usermodel.XSSFRow;
48
import org.apache.poi.xssf.usermodel.XSSFSheet;
58
import org.apache.poi.xssf.usermodel.XSSFSheet;
Lines 54-64 import org.junit.Test; Link Here
54
 * is encrypted, but the final saved workbook is not encrypted
64
 * is encrypted, but the final saved workbook is not encrypted
55
 */
65
 */
56
public final class TestSXSSFWorkbookWithCustomZipEntrySource {
66
public final class TestSXSSFWorkbookWithCustomZipEntrySource {
57
67
    
68
    final String sheetName = "TestSheet1";
69
    final String cellValue = "customZipEntrySource";
70
    
58
    @Test
71
    @Test
59
    public void customZipEntrySource() throws IOException, GeneralSecurityException {
72
    public void customZipEntrySource() throws IOException {
60
        final String sheetName = "TestSheet1";
61
        final String cellValue = "customZipEntrySource";
62
        SXSSFWorkbookWithCustomZipEntrySource workbook = new SXSSFWorkbookWithCustomZipEntrySource();
73
        SXSSFWorkbookWithCustomZipEntrySource workbook = new SXSSFWorkbookWithCustomZipEntrySource();
63
        SXSSFSheet sheet1 = workbook.createSheet(sheetName);
74
        SXSSFSheet sheet1 = workbook.createSheet(sheetName);
64
        SXSSFRow row1 = sheet1.createRow(1);
75
        SXSSFRow row1 = sheet1.createRow(1);
Lines 77-82 public final class TestSXSSFWorkbookWithCustomZipEntrySource { Link Here
77
        xwb.close();
88
        xwb.close();
78
    }
89
    }
79
    
90
    
91
    @Test
92
    public void customZipEntrySourceForWriteAndRead() throws IOException, GeneralSecurityException, InvalidFormatException {
93
        SXSSFWorkbookWithCustomZipEntrySource workbook = new SXSSFWorkbookWithCustomZipEntrySource();
94
        SXSSFSheet sheet1 = workbook.createSheet(sheetName);
95
        SXSSFRow row1 = sheet1.createRow(1);
96
        SXSSFCell cell1 = row1.createCell(1);
97
        cell1.setCellValue(cellValue);
98
        EncryptedTempData tempData = new EncryptedTempData();
99
        workbook.write(tempData.getOutputStream());
100
        workbook.close();
101
        workbook.dispose();
102
        ZipEntrySource zipEntrySource = AesZipFileZipEntrySource.createZipEntrySource(tempData.getInputStream());
103
        tempData.dispose();
104
        OPCPackage opc = OPCPackage.open(zipEntrySource);
105
        XSSFWorkbook xwb = new XSSFWorkbook(opc);
106
        zipEntrySource.close();
107
        XSSFSheet xs1 = xwb.getSheetAt(0);
108
        assertEquals(sheetName, xs1.getSheetName());
109
        XSSFRow xr1 = xs1.getRow(1);
110
        XSSFCell xc1 = xr1.getCell(1);
111
        assertEquals(cellValue, xc1.getStringCellValue());
112
        xwb.close();
113
        opc.close();
114
    }
115
    
116
    @Test
117
    public void validateTempFilesAreEncrypted() throws IOException {
118
        TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource workbook = new TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource();
119
        SXSSFSheet sheet1 = workbook.createSheet(sheetName);
120
        SXSSFRow row1 = sheet1.createRow(1);
121
        SXSSFCell cell1 = row1.createCell(1);
122
        cell1.setCellValue(cellValue);
123
        ByteArrayOutputStream os = new ByteArrayOutputStream(8192);
124
        workbook.write(os);
125
        workbook.close();
126
        List<File> tempFiles = workbook.getTempFiles();
127
        assertEquals(1, tempFiles.size());
128
        File tempFile = tempFiles.get(0);
129
        assertTrue("tempFile exists?", tempFile.exists());
130
        byte[] data = IOUtils.toByteArray(new FileInputStream(tempFile));
131
        String text = new String(data, UTF_8);
132
        assertFalse(text.contains(sheetName));
133
        assertFalse(text.contains(cellValue));
134
        workbook.dispose();
135
        assertFalse("tempFile deleted after dispose?", tempFile.exists());
136
    }
137
    
80
    static class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook {
138
    static class SXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbook {
81
139
82
        private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class);
140
        private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbookWithCustomZipEntrySource.class);
Lines 84-100 public final class TestSXSSFWorkbookWithCustomZipEntrySource { Link Here
84
        @Override
142
        @Override
85
        public void write(OutputStream stream) throws IOException {
143
        public void write(OutputStream stream) throws IOException {
86
            flushSheets();
144
            flushSheets();
87
            ByteArrayOutputStream os = new ByteArrayOutputStream();
145
            EncryptedTempData tempData = new EncryptedTempData();
146
            OutputStream os = tempData.getOutputStream();
88
            getXSSFWorkbook().write(os);
147
            getXSSFWorkbook().write(os);
148
            os.close();
89
            ZipEntrySource source = null;
149
            ZipEntrySource source = null;
90
            try {
150
            try {
91
                // provide ZipEntrySource to poi which decrypts on the fly
151
                // provide ZipEntrySource to poi which decrypts on the fly
92
                source = AesZipFileZipEntrySource.createZipEntrySource(new ByteArrayInputStream(os.toByteArray()));
152
                source = AesZipFileZipEntrySource.createZipEntrySource(tempData.getInputStream());
93
                injectData(source, stream);
153
                injectData(source, stream);
94
            } catch (GeneralSecurityException e) {
154
            } catch (GeneralSecurityException e) {
95
                throw new IOException(e);
155
                throw new IOException(e);
96
            } finally {
156
            } finally {
97
                source.close();
157
                IOUtils.closeQuietly(source);
98
            }
158
            }
99
        }
159
        }
100
160
Lines 141-144 public final class TestSXSSFWorkbookWithCustomZipEntrySource { Link Here
141
        }
201
        }
142
        
202
        
143
    }
203
    }
204
    
205
    static class TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource extends SXSSFWorkbookWithCustomZipEntrySource {
206
207
        private final List<File> tempFiles = new ArrayList<File>();
208
209
        List<File> getTempFiles() {
210
            return new ArrayList<File>(tempFiles);
211
        }
212
        
213
        @Override
214
        protected SheetDataWriter createSheetDataWriter() throws IOException {
215
            return new TempFileRecordingSheetDataWriterWithDecorator();
216
        }
217
218
        class TempFileRecordingSheetDataWriterWithDecorator extends SheetDataWriterWithDecorator {
219
220
            TempFileRecordingSheetDataWriterWithDecorator() throws IOException {
221
                super();
222
                tempFiles.add(getTempFile());
223
            }
224
        }
225
    }
226
    
227
    static class EncryptedTempData {
228
        final static CipherAlgorithm cipherAlgorithm = CipherAlgorithm.aes128;
229
        final SecretKeySpec skeySpec;
230
        final byte[] ivBytes;
231
        final File tempFile;
232
        
233
        EncryptedTempData() throws IOException {
234
            SecureRandom sr = new SecureRandom();
235
            ivBytes = new byte[16];
236
            byte[] keyBytes = new byte[16];
237
            sr.nextBytes(ivBytes);
238
            sr.nextBytes(keyBytes);
239
            skeySpec = new SecretKeySpec(keyBytes, cipherAlgorithm.jceId);
240
            tempFile = TempFile.createTempFile("poi-temp-data", ".tmp");
241
        }
242
243
        OutputStream getOutputStream() throws IOException {
244
            Cipher ciEnc = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.ENCRYPT_MODE, null);
245
            return new CipherOutputStream(new FileOutputStream(tempFile), ciEnc);
246
        }
247
248
        InputStream getInputStream() throws IOException {
249
            Cipher ciDec = CryptoFunctions.getCipher(skeySpec, cipherAlgorithm, ChainingMode.cbc, ivBytes, Cipher.DECRYPT_MODE, null);
250
            return new CipherInputStream(new FileInputStream(tempFile), ciDec);
251
        }
252
        
253
        void dispose() {
254
            tempFile.delete();
255
        }
256
    }
257
    
144
}
258
}
145
- 

Return to bug 60153