1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_quota_DecryptingInputStream_h
8 #define mozilla_dom_quota_DecryptingInputStream_h
9 
10 // Local includes
11 #include "EncryptedBlock.h"
12 
13 // Global includes
14 #include <cstddef>
15 #include <cstdint>
16 #include "ErrorList.h"
17 #include "mozilla/InitializedOnce.h"
18 #include "mozilla/Maybe.h"
19 #include "mozilla/NotNull.h"
20 #include "mozilla/ipc/InputStreamParams.h"
21 #include "nsCOMPtr.h"
22 #include "nsICloneableInputStream.h"
23 #include "nsIIPCSerializableInputStream.h"
24 #include "nsIInputStream.h"
25 #include "nsISeekableStream.h"
26 #include "nsISupports.h"
27 #include "nsITellableStream.h"
28 #include "nsTArray.h"
29 #include "nscore.h"
30 
31 namespace mozilla::ipc {
32 class ChildToParentStreamActorManager;
33 class ParentToChildStreamActorManager;
34 }  // namespace mozilla::ipc
35 
36 template <class T>
37 class nsCOMPtr;
38 
39 namespace mozilla::dom::quota {
40 
41 class DecryptingInputStreamBase : public nsIInputStream,
42                                   public nsISeekableStream,
43                                   public nsICloneableInputStream,
44                                   public nsIIPCSerializableInputStream {
45  public:
46   NS_DECL_THREADSAFE_ISUPPORTS
47 
48   NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval) final;
49   NS_IMETHOD IsNonBlocking(bool* _retval) final;
50 
51   NS_IMETHOD SetEOF() final;
52 
53   using nsICloneableInputStream::GetCloneable;
54   NS_IMETHOD GetCloneable(bool* aCloneable) final;
55 
56   using nsIIPCSerializableInputStream::Serialize;
57   void Serialize(mozilla::ipc::InputStreamParams& aParams,
58                  FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
59                  uint32_t aMaxSize, uint32_t* aSizeUsed,
60                  mozilla::ipc::ChildToParentStreamActorManager* aManager) final;
61 
62  protected:
63   DecryptingInputStreamBase(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
64                             size_t aBlockSize);
65 
66   // For deserialization only.
67   DecryptingInputStreamBase() = default;
68 
69   virtual ~DecryptingInputStreamBase() = default;
70 
71   void Init(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
72             size_t aBlockSize);
73 
74   // Convenience routine to determine how many bytes of plain data
75   // we currently have in our buffer.
76   size_t PlainLength() const;
77 
78   size_t EncryptedBufferLength() const;
79 
80   LazyInitializedOnceEarlyDestructible<const NotNull<nsCOMPtr<nsIInputStream>>>
81       mBaseStream;
82   LazyInitializedOnce<const NotNull<nsISeekableStream*>> mBaseSeekableStream;
83   LazyInitializedOnce<const NotNull<nsICloneableInputStream*>>
84       mBaseCloneableInputStream;
85   LazyInitializedOnce<const NotNull<nsIIPCSerializableInputStream*>>
86       mBaseIPCSerializableInputStream;
87 
88   // Number of bytes of plain data in mBuffer.
89   size_t mPlainBytes = 0;
90 
91   // Next byte of mBuffer to return in ReadSegments().
92   size_t mNextByte = 0;
93 
94   LazyInitializedOnceNotNull<const size_t> mBlockSize;
95 
96   size_t mLastBlockLength = 0;
97 };
98 
99 // Wraps another nsIInputStream which contains data written using
100 // EncryptingInputStream with a compatible CipherStategy and key. See the
101 // remarks on EncryptingOutputStream.
102 template <typename CipherStrategy>
103 class DecryptingInputStream final : public DecryptingInputStreamBase {
104  public:
105   // Construct a new blocking stream to decrypt the given base stream.  The
106   // base stream must also be blocking.  The base stream does not have to be
107   // buffered.
108   DecryptingInputStream(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
109                         size_t aBlockSize,
110                         typename CipherStrategy::KeyType aKey);
111 
112   // For deserialization only.
113   explicit DecryptingInputStream();
114 
115   NS_IMETHOD Close() override;
116   NS_IMETHOD Available(uint64_t* _retval) override;
117   NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
118                           uint32_t aCount, uint32_t* _retval) override;
119 
120   NS_DECL_NSITELLABLESTREAM
121 
122   NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset) override;
123 
124   NS_IMETHOD Clone(nsIInputStream** _retval) override;
125 
126   using DecryptingInputStreamBase::Serialize;
127   void Serialize(
128       mozilla::ipc::InputStreamParams& aParams,
129       FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
130       uint32_t aMaxSize, uint32_t* aSizeUsed,
131       mozilla::ipc::ParentToChildStreamActorManager* aManager) override;
132 
133   bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,
134                    const FileDescriptorArray& aFileDescriptors) override;
135 
136  private:
137   ~DecryptingInputStream();
138 
139   // Parse the next chunk of data.  This may populate mBuffer and set
140   // mBufferFillSize.  This should not be called when mBuffer already
141   // contains data.
142   nsresult ParseNextChunk(uint32_t* aBytesReadOut);
143 
144   // Convenience routine to Read() from the base stream until we get
145   // the given number of bytes or reach EOF.
146   //
147   // aBuf           - The buffer to write the bytes into.
148   // aCount         - Max number of bytes to read. If the stream closes
149   //                  fewer bytes my be read.
150   // aMinValidCount - A minimum expected number of bytes.  If we find
151   //                  fewer than this many bytes, then return
152   //                  NS_ERROR_CORRUPTED_CONTENT.  If nothing was read due
153   //                  due to EOF (aBytesReadOut == 0), then NS_OK is returned.
154   // aBytesReadOut  - An out parameter indicating how many bytes were read.
155   nsresult ReadAll(char* aBuf, uint32_t aCount, uint32_t aMinValidCount,
156                    uint32_t* aBytesReadOut);
157 
158   bool EnsureBuffers();
159 
160   CipherStrategy mCipherStrategy;
161   LazyInitializedOnce<const typename CipherStrategy::KeyType> mKey;
162 
163   // Buffer to hold encrypted data.  Must copy here since we need a
164   // flat buffer to run the decryption process on.
165   using EncryptedBlockType = EncryptedBlock<CipherStrategy::BlockPrefixLength,
166                                             CipherStrategy::BasicBlockSize>;
167   Maybe<EncryptedBlockType> mEncryptedBlock;
168 
169   // Buffer storing the resulting plain data.
170   nsTArray<uint8_t> mPlainBuffer;
171 };
172 
173 }  // namespace mozilla::dom::quota
174 
175 #endif
176