You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestDocumentEncryption.java 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hslf.record;
  16. import static org.junit.jupiter.api.Assertions.assertArrayEquals;
  17. import static org.junit.jupiter.api.Assertions.assertEquals;
  18. import static org.junit.jupiter.api.Assertions.assertNotNull;
  19. import static org.junit.jupiter.api.Assertions.assertTrue;
  20. import java.io.InputStream;
  21. import java.security.MessageDigest;
  22. import java.util.Base64;
  23. import java.util.List;
  24. import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
  25. import org.apache.poi.POIDataSamples;
  26. import org.apache.poi.hpsf.DocumentSummaryInformation;
  27. import org.apache.poi.hpsf.PropertySet;
  28. import org.apache.poi.hpsf.PropertySetFactory;
  29. import org.apache.poi.hpsf.SummaryInformation;
  30. import org.apache.poi.hslf.usermodel.HSLFPictureData;
  31. import org.apache.poi.hslf.usermodel.HSLFSlide;
  32. import org.apache.poi.hslf.usermodel.HSLFSlideShow;
  33. import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl;
  34. import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
  35. import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
  36. import org.apache.poi.poifs.crypt.CryptoFunctions;
  37. import org.apache.poi.poifs.crypt.EncryptionInfo;
  38. import org.apache.poi.poifs.crypt.HashAlgorithm;
  39. import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIDecryptor;
  40. import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  41. import org.junit.jupiter.api.Test;
  42. import org.junit.jupiter.params.ParameterizedTest;
  43. import org.junit.jupiter.params.provider.ValueSource;
  44. /**
  45. * Tests that DocumentEncryption works properly.
  46. */
  47. public class TestDocumentEncryption {
  48. private static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
  49. @ParameterizedTest
  50. @ValueSource(strings = {
  51. "Password_Protected-56-hello.ppt",
  52. "Password_Protected-hello.ppt",
  53. "Password_Protected-np-hello.ppt"
  54. })
  55. void cryptoAPIDecryptionOther(String pptFile) throws Exception {
  56. Biff8EncryptionKey.setCurrentUserPassword("hello");
  57. try {
  58. try (POIFSFileSystem fs = new POIFSFileSystem(slTests.getFile(pptFile), true);
  59. HSLFSlideShow ppt = new HSLFSlideShow(fs)) {
  60. assertTrue(ppt.getSlides().size() > 0);
  61. }
  62. } finally {
  63. Biff8EncryptionKey.setCurrentUserPassword(null);
  64. }
  65. }
  66. @Test
  67. void cryptoAPIChangeKeySize() throws Exception {
  68. String pptFile = "cryptoapi-proc2356.ppt";
  69. Biff8EncryptionKey.setCurrentUserPassword("crypto");
  70. try (POIFSFileSystem fs = new POIFSFileSystem(slTests.getFile(pptFile), true);
  71. HSLFSlideShowImpl hss = new HSLFSlideShowImpl(fs)) {
  72. // need to cache data (i.e. read all data) before changing the key size
  73. List<HSLFPictureData> picsExpected = hss.getPictureData();
  74. hss.getDocumentSummaryInformation();
  75. DocumentEncryptionAtom documentEncryptionAtom = hss.getDocumentEncryptionAtom();
  76. assertNotNull(documentEncryptionAtom);
  77. EncryptionInfo ei = documentEncryptionAtom.getEncryptionInfo();
  78. ei.getHeader().setKeySize(0x78);
  79. UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
  80. hss.write(bos);
  81. try (POIFSFileSystem fs2 = new POIFSFileSystem(bos.toInputStream());
  82. HSLFSlideShowImpl hss2 = new HSLFSlideShowImpl(fs2)) {
  83. List<HSLFPictureData> picsActual = hss2.getPictureData();
  84. assertEquals(picsExpected.size(), picsActual.size());
  85. for (int i = 0; i < picsExpected.size(); i++) {
  86. assertArrayEquals(picsExpected.get(i).getRawData(), picsActual.get(i).getRawData());
  87. }
  88. }
  89. } finally {
  90. Biff8EncryptionKey.setCurrentUserPassword(null);
  91. }
  92. }
  93. @Test
  94. void cryptoAPIEncryption() throws Exception {
  95. /* documents with multiple edits need to be normalized for encryption */
  96. String pptFile = "57272_corrupted_usereditatom.ppt";
  97. UnsynchronizedByteArrayOutputStream encrypted = new UnsynchronizedByteArrayOutputStream();
  98. UnsynchronizedByteArrayOutputStream expected = new UnsynchronizedByteArrayOutputStream();
  99. UnsynchronizedByteArrayOutputStream actual = new UnsynchronizedByteArrayOutputStream();
  100. try {
  101. try (POIFSFileSystem fs = new POIFSFileSystem(slTests.getFile(pptFile), true);
  102. HSLFSlideShowImpl hss = new HSLFSlideShowImpl(fs)) {
  103. hss.normalizeRecords();
  104. // normalized ppt
  105. hss.write(expected);
  106. // encrypted
  107. Biff8EncryptionKey.setCurrentUserPassword("hello");
  108. hss.write(encrypted);
  109. }
  110. // decrypted
  111. try (InputStream bis = encrypted.toInputStream();
  112. POIFSFileSystem fs = new POIFSFileSystem(bis);
  113. HSLFSlideShowImpl hss = new HSLFSlideShowImpl(fs)) {
  114. Biff8EncryptionKey.setCurrentUserPassword(null);
  115. hss.write(actual);
  116. }
  117. } finally {
  118. Biff8EncryptionKey.setCurrentUserPassword(null);
  119. }
  120. assertArrayEquals(expected.toByteArray(), actual.toByteArray());
  121. }
  122. @Test
  123. void cryptoAPIDecryption() throws Exception {
  124. // taken from a msdn blog:
  125. // http://blogs.msdn.com/b/openspecification/archive/2009/05/08/dominic-salemno.aspx
  126. Biff8EncryptionKey.setCurrentUserPassword("crypto");
  127. try (POIFSFileSystem fs = new POIFSFileSystem(slTests.getFile("cryptoapi-proc2356.ppt"));
  128. HSLFSlideShow ss = new HSLFSlideShow(fs)) {
  129. HSLFSlide slide = ss.getSlides().get(0);
  130. String rawText = HSLFTextParagraph.getRawText(slide.getTextParagraphs().get(0));
  131. assertEquals("Dominic Salemno", rawText);
  132. String[][] picCmp = {
  133. {"0", "nKsDTKqxTCR8LFkVVWlP9GSTvZ0="},
  134. {"95163", "SuNOR+9V1UVYZIoeD65l3VTaLoc="},
  135. {"100864", "Ql3IGrr4bNq07ZTp5iPg7b+pva8="},
  136. {"714114", "8pdst9NjBGSfWezSZE8+aVhIRe0="},
  137. {"723752", "go6xqW7lvkCtlOO5tYLiMfb4oxw="},
  138. {"770128", "gZUM8YqRNL5kGNfyyYvEEernvCc="},
  139. {"957958", "CNU2iiqUFAnk3TDXsXV1ihH9eRM="},
  140. };
  141. MessageDigest md = CryptoFunctions.getMessageDigest(HashAlgorithm.sha1);
  142. List<HSLFPictureData> pd = ss.getSlideShowImpl().getPictureData();
  143. int i = 0;
  144. for (HSLFPictureData p : pd) {
  145. byte[] hash = md.digest(p.getData());
  146. assertEquals(Integer.parseInt(picCmp[i][0]), p.getOffset());
  147. assertEquals(picCmp[i][1], Base64.getEncoder().encodeToString(hash));
  148. i++;
  149. }
  150. DocumentEncryptionAtom dea = ss.getSlideShowImpl().getDocumentEncryptionAtom();
  151. assertNotNull(dea);
  152. CryptoAPIDecryptor dec = (CryptoAPIDecryptor) dea.getEncryptionInfo().getDecryptor();
  153. try (POIFSFileSystem fs2 = dec.getSummaryEntries(fs.getRoot(), "EncryptedSummary")) {
  154. PropertySet ps = PropertySetFactory.create(fs2.getRoot(), SummaryInformation.DEFAULT_STREAM_NAME);
  155. assertNotNull(ps);
  156. assertTrue(ps.isSummaryInformation());
  157. assertEquals("RC4 CryptoAPI Encryption", ps.getProperties()[1].getValue());
  158. ps = PropertySetFactory.create(fs2.getRoot(), DocumentSummaryInformation.DEFAULT_STREAM_NAME);
  159. assertNotNull(ps);
  160. assertTrue(ps.isDocumentSummaryInformation());
  161. assertEquals("On-screen Show (4:3)", ps.getProperties()[1].getValue());
  162. }
  163. } finally {
  164. Biff8EncryptionKey.setCurrentUserPassword(null);
  165. }
  166. }
  167. }