| /* ==================================================================== |
| 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.hssf.record; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| |
| import java.io.ByteArrayInputStream; |
| |
| import org.apache.poi.EncryptedDocumentException; |
| import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; |
| import org.apache.poi.util.HexRead; |
| import org.junit.After; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.ExpectedException; |
| |
| /** |
| * Tests for {@link RecordFactoryInputStream} |
| * |
| * @author Josh Micich |
| */ |
| public final class TestRecordFactoryInputStream { |
| // to not affect other tests running in the same JVM |
| @After |
| public void resetPassword() { |
| Biff8EncryptionKey.setCurrentUserPassword(null); |
| } |
| |
| /** |
| * Hex dump of a BOF record and most of a FILEPASS record. |
| * A 16 byte saltHash should be added to complete the second record |
| */ |
| private static final String COMMON_HEX_DATA = "" |
| // BOF |
| + "09 08 10 00" |
| + "00 06 05 00 D3 10 CC 07 01 00 00 00 00 06 00 00" |
| // FILEPASS |
| + "2F 00 36 00" |
| + "01 00 01 00 01 00" |
| + "BAADF00D BAADF00D BAADF00D BAADF00D" // docId |
| + "DEADBEEF DEADBEEF DEADBEEF DEADBEEF" // saltData |
| ; |
| |
| /** |
| * Hex dump of a sample WINDOW1 record |
| */ |
| private static final String SAMPLE_WINDOW1 = "3D 00 12 00" |
| + "00 00 00 00 40 38 55 23 38 00 00 00 00 00 01 00 58 02"; |
| |
| @Rule |
| public ExpectedException expectedEx = ExpectedException.none(); |
| |
| |
| /** |
| * Makes sure that a default password mismatch condition is represented with {@link EncryptedDocumentException} |
| */ |
| @Test |
| public void defaultPasswordWrong() { |
| // This encodng depends on docId, password and stream position |
| final String SAMPLE_WINDOW1_ENCR1 = "3D 00 12 00" |
| + "C4, 9B, 02, 50, 86, E0, DF, 34, FB, 57, 0E, 8C, CE, 25, 45, E3, 80, 01"; |
| |
| byte[] dataWrongDefault = HexRead.readFromString("" |
| + COMMON_HEX_DATA |
| + "00000000 00000000 00000000 00000001" |
| + SAMPLE_WINDOW1_ENCR1 |
| ); |
| |
| Biff8EncryptionKey.setCurrentUserPassword(null); |
| expectedEx.expect(EncryptedDocumentException.class); |
| expectedEx.expectMessage("Default password is invalid for salt/verifier/verifierHash"); |
| createRFIS(dataWrongDefault); |
| } |
| |
| @Test |
| public void defaultPasswordOK() { |
| // This encodng depends on docId, password and stream position |
| final String SAMPLE_WINDOW1_ENCR1 = "3D 00 12 00" |
| + "C4, 9B, 02, 50, 86, E0, DF, 34, FB, 57, 0E, 8C, CE, 25, 45, E3, 80, 01"; |
| |
| byte[] dataCorrectDefault = HexRead.readFromString("" |
| + COMMON_HEX_DATA |
| + "137BEF04 969A200B 306329DE 52254005" // correct saltHash for default password (and docId/saltHash) |
| + SAMPLE_WINDOW1_ENCR1 |
| ); |
| |
| Biff8EncryptionKey.setCurrentUserPassword(null); |
| RecordFactoryInputStream rfis = createRFIS(dataCorrectDefault); |
| confirmReadInitialRecords(rfis); |
| } |
| |
| |
| /** |
| * Makes sure that an incorrect user supplied password condition is represented with {@link EncryptedDocumentException} |
| */ |
| @Test |
| public void suppliedPasswordWrong() { |
| // This encoding depends on docId, password and stream position |
| final String SAMPLE_WINDOW1_ENCR2 = "3D 00 12 00" |
| + "45, B9, 90, FE, B6, C6, EC, 73, EE, 3F, 52, 45, 97, DB, E3, C1, D6, FE"; |
| |
| byte[] dataWrongDefault = HexRead.readFromString("" |
| + COMMON_HEX_DATA |
| + "00000000 00000000 00000000 00000000" |
| + SAMPLE_WINDOW1_ENCR2 |
| ); |
| |
| |
| Biff8EncryptionKey.setCurrentUserPassword("passw0rd"); |
| |
| expectedEx.expect(EncryptedDocumentException.class); |
| expectedEx.expectMessage("Supplied password is invalid for salt/verifier/verifierHash"); |
| createRFIS(dataWrongDefault); |
| } |
| |
| @Test |
| public void suppliedPasswordOK() { |
| // This encoding depends on docId, password and stream position |
| final String SAMPLE_WINDOW1_ENCR2 = "3D 00 12 00" |
| + "45, B9, 90, FE, B6, C6, EC, 73, EE, 3F, 52, 45, 97, DB, E3, C1, D6, FE"; |
| |
| Biff8EncryptionKey.setCurrentUserPassword("passw0rd"); |
| |
| byte[] dataCorrectDefault = HexRead.readFromString("" |
| + COMMON_HEX_DATA |
| + "C728659A C38E35E0 568A338F C3FC9D70" // correct saltHash for supplied password (and docId/saltHash) |
| + SAMPLE_WINDOW1_ENCR2 |
| ); |
| |
| RecordFactoryInputStream rfis = createRFIS(dataCorrectDefault); |
| Biff8EncryptionKey.setCurrentUserPassword(null); |
| |
| confirmReadInitialRecords(rfis); |
| } |
| |
| |
| /** |
| * makes sure the record stream starts with {@link BOFRecord}, {@link FilePassRecord} and then {@link WindowOneRecord} |
| * The third record is decrypted so this method also checks its content. |
| */ |
| private void confirmReadInitialRecords(RecordFactoryInputStream rfis) { |
| assertEquals(BOFRecord.class, rfis.nextRecord().getClass()); |
| FilePassRecord recFP = (FilePassRecord) rfis.nextRecord(); |
| WindowOneRecord rec1 = (WindowOneRecord) rfis.nextRecord(); |
| assertArrayEquals(HexRead.readFromString(SAMPLE_WINDOW1),rec1.serialize()); |
| } |
| |
| private static RecordFactoryInputStream createRFIS(byte[] data) { |
| return new RecordFactoryInputStream(new ByteArrayInputStream(data), true); |
| } |
| } |