/** * Decrypt the Document-/SummaryInformation and other optionally streams. * Opposed to other crypto modes, cryptoapi is record based and can't be used * to stream-decrypt a whole file * * @see <a href="http://msdn.microsoft.com/en-us/library/dd943321(v=office.12).aspx">2.3.5.4 RC4 CryptoAPI Encrypted Summary Stream</a> */ public override InputStream GetDataStream(DirectoryNode dir) { NPOIFSFileSystem fsOut = new NPOIFSFileSystem(); DocumentNode es = (DocumentNode)dir.GetEntry("EncryptedSummary"); DocumentInputStream dis = dir.CreateDocumentInputStream(es); MemoryStream bos = new MemoryStream(); IOUtils.Copy(dis, bos); dis.Close(); SeekableMemoryStream sbis = new SeekableMemoryStream(bos.ToArray()); LittleEndianInputStream leis = new LittleEndianInputStream(sbis); int streamDescriptorArrayOffset = (int)leis.ReadUInt(); int streamDescriptorArraySize = (int)leis.ReadUInt(); sbis.Seek(streamDescriptorArrayOffset - 8, SeekOrigin.Current);// sbis.Skip(streamDescriptorArrayOffset - 8); sbis.SetBlock(0); int encryptedStreamDescriptorCount = (int)leis.ReadUInt(); StreamDescriptorEntry[] entries = new StreamDescriptorEntry[encryptedStreamDescriptorCount]; for (int i = 0; i < encryptedStreamDescriptorCount; i++) { StreamDescriptorEntry entry = new StreamDescriptorEntry(); entries[i] = entry; entry.streamOffset = (int)leis.ReadUInt(); entry.streamSize = (int)leis.ReadUInt(); entry.block = leis.ReadUShort(); int nameSize = leis.ReadUByte(); entry.flags = leis.ReadUByte(); bool IsStream = StreamDescriptorEntry.flagStream.IsSet(entry.flags); entry.reserved2 = leis.ReadInt(); entry.streamName = StringUtil.ReadUnicodeLE(leis, nameSize); leis.ReadShort(); Debug.Assert(entry.streamName.Length == nameSize); } foreach (StreamDescriptorEntry entry in entries) { sbis.Seek(entry.streamOffset); sbis.SetBlock(entry.block); Stream is1 = new BufferedStream(sbis, entry.streamSize); fsOut.CreateDocument(is1, entry.streamName); } leis.Close(); sbis = null; bos.Seek(0, SeekOrigin.Begin); //bos.Reset(); fsOut.WriteFileSystem(bos); fsOut.Close(); _length = bos.Length; ByteArrayInputStream bis = new ByteArrayInputStream(bos.ToArray()); throw new NotImplementedException("ByteArrayInputStream should be derived from InputStream"); }
/** * Encrypt the Document-/SummaryInformation and other optionally streams. * Opposed to other crypto modes, cryptoapi is record based and can't be used * to stream-encrypt a whole file * * @see <a href="http://msdn.microsoft.com/en-us/library/dd943321(v=office.12).aspx">2.3.5.4 RC4 CryptoAPI Encrypted Summary Stream</a> */ public override OutputStream GetDataStream(DirectoryNode dir) { CipherByteArrayOutputStream bos = new CipherByteArrayOutputStream(this); byte[] buf = new byte[8]; bos.Write(buf, 0, 8); // skip header String[] entryNames = { SummaryInformation.DEFAULT_STREAM_NAME, DocumentSummaryInformation.DEFAULT_STREAM_NAME }; List <StreamDescriptorEntry> descList = new List <StreamDescriptorEntry>(); int block = 0; foreach (String entryName in entryNames) { if (!dir.HasEntry(entryName)) { continue; } StreamDescriptorEntry descEntry = new StreamDescriptorEntry(); descEntry.block = block; descEntry.streamOffset = (int)bos.Length; descEntry.streamName = entryName; descEntry.flags = StreamDescriptorEntry.flagStream.SetValue(0, 1); descEntry.reserved2 = 0; bos.SetBlock(block); DocumentInputStream dis = dir.CreateDocumentInputStream(entryName); IOUtils.Copy(dis, bos); dis.Close(); descEntry.streamSize = (int)(bos.Length - descEntry.streamOffset); descList.Add(descEntry); dir.GetEntry(entryName).Delete(); block++; } int streamDescriptorArrayOffset = (int)bos.Length; bos.SetBlock(0); LittleEndian.PutUInt(buf, 0, descList.Count); bos.Write(buf, 0, 4); foreach (StreamDescriptorEntry sde in descList) { LittleEndian.PutUInt(buf, 0, sde.streamOffset); bos.Write(buf, 0, 4); LittleEndian.PutUInt(buf, 0, sde.streamSize); bos.Write(buf, 0, 4); LittleEndian.PutUShort(buf, 0, sde.block); bos.Write(buf, 0, 2); LittleEndian.PutUByte(buf, 0, (short)sde.streamName.Length); bos.Write(buf, 0, 1); LittleEndian.PutUByte(buf, 0, (short)sde.flags); bos.Write(buf, 0, 1); LittleEndian.PutUInt(buf, 0, sde.reserved2); bos.Write(buf, 0, 4); byte[] nameBytes = StringUtil.GetToUnicodeLE(sde.streamName); bos.Write(nameBytes, 0, nameBytes.Length); LittleEndian.PutShort(buf, 0, (short)0); // null-termination bos.Write(buf, 0, 2); } int savedSize = (int)bos.Length; int streamDescriptorArraySize = savedSize - streamDescriptorArrayOffset; LittleEndian.PutUInt(buf, 0, streamDescriptorArrayOffset); LittleEndian.PutUInt(buf, 4, streamDescriptorArraySize); bos.Reset(); bos.SetBlock(0); bos.Write(buf, 0, 8); bos.SetSize(savedSize); dir.CreateDocument("EncryptedSummary", new MemoryStream(bos.GetBuf(), 0, savedSize)); DocumentSummaryInformation dsi = PropertySetFactory.NewDocumentSummaryInformation(); try { dsi.Write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME); } catch (WritingNotSupportedException e) { throw new IOException(e.Message); } //return bos; throw new NotImplementedException("CipherByteArrayOutputStream should be derived from OutputStream"); }