/* ==================================================================== 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); } }