33#include  < gsl/gsl-lite.hpp> 
44#include  < optional> 
55
6+ #include  < sframe/map.h> 
7+ #include  < sframe/vector.h> 
8+ 
69namespace  sframe  {
710
811struct  crypto_error  : std::runtime_error
@@ -47,196 +50,29 @@ enum class CipherSuite : uint16_t
4750  AES_GCM_256_SHA512 = 5 ,
4851};
4952
50- constexpr  size_t  max_overhead = 17  + 16 ;
51- 
5253using  input_bytes = gsl::span<const  uint8_t >;
5354using  output_bytes = gsl::span<uint8_t >;
5455
55- using  KeyID = uint64_t ;
56- using  Counter = uint64_t ;
57- 
58- template <typename  T, size_t  N>
59- class  vector 
60- {
61- private: 
62-   std::array<T, N> _data;
63-   size_t  _size;
64- 
65- public: 
66-   constexpr  vector ()
67-     : _size(N)
68-   {
69-     std::fill (_data.begin (), _data.end (), T ());
70-   }
71- 
72-   constexpr  vector (size_t  size)
73-   {
74-     std::fill (_data.begin (), _data.end (), T ());
75-     resize (size);
76-   }
77- 
78-   constexpr  vector (std::initializer_list<uint8_t > content)
79-   {
80-     resize (content.size ());
81-     std::copy (content.begin (), content.end (), _data.begin ());
82-   }
83- 
84-   constexpr  vector (gsl::span<const  T> content)
85-   {
86-     resize (content.size ());
87-     std::copy (content.begin (), content.end (), _data.begin ());
88-   }
89- 
90-   //  XXX(RLB) This constructor seems redundant with the prior one, but for some
91-   //  reason the compiler won't auto-convert from vector to span.
92-   template <size_t  M>
93-   constexpr  vector (const  vector<T, M>& content)
94-   {
95-     resize (content.size ());
96-     std::copy (content.begin (), content.end (), _data.begin ());
97-   }
98- 
99-   uint8_t * data () { return  _data.data (); }
100- 
101-   auto  begin () const  { return  _data.begin (); }
102-   auto  begin () { return  _data.begin (); }
103- 
104-   auto  end () const  { return  _data.begin () + _size; }
105-   auto  end () { return  _data.begin () + _size; }
106- 
107-   auto  size () const  { return  _size; }
108-   auto  capacity () const  { return  N; }
109-   void  resize (size_t  size)
110-   {
111-     if  (size > N) {
112-       throw  std::out_of_range (" vector out of space"  );
113-     }
114- 
115-     _size = size;
116-   }
117- 
118-   void  push (T&& item)
119-   {
120-     resize (_size + 1 );
121-     _data.at (_size - 1 ) = item;
122-   }
123- 
124-   void  append (input_bytes content)
125-   {
126-     const  auto  start = _size;
127-     resize (_size + content.size ());
128-     std::copy (content.begin (), content.end (), begin () + start);
129-   }
130- 
131-   auto & operator [](size_t  i) { return  _data.at (i); }
132-   const  auto & operator [](size_t  i) const  { return  _data.at (i); }
133- 
134-   operator  gsl::span<const  T>() const  { return  gsl::span (_data).first (_size); }
135-   operator  gsl::span<T>() { return  gsl::span (_data).first (_size); }
136- };
137- 
138- template <typename  K, typename  V, size_t  N>
139- class  map  : private  vector <std::optional<std::pair<K, V>>, N>
140- {
141- public: 
142-   template <class ... Args>
143-   void  emplace (Args&&... args)
144-   {
145-     const  auto  pos = std::find_if (
146-       this ->begin (), this ->end (), [&](const  auto & pair) { return  !pair; });
147-     if  (pos == this ->end ()) {
148-       throw  std::out_of_range (" map out of space"  );
149-     }
150- 
151-     pos->emplace (args...);
152-   }
153- 
154-   auto  find (const  K& key)
155-   {
156-     return  std::find_if (this ->begin (), this ->end (), [&](const  auto & pair) {
157-       return  pair && pair.value ().first  == key;
158-     });
159-   }
160- 
161-   auto  find (const  K& key) const 
162-   {
163-     return  std::find_if (this ->begin (), this ->end (), [&](const  auto & pair) {
164-       return  pair && pair.value ().first  == key;
165-     });
166-   }
167- 
168-   bool  contains (const  K& key) const  { return  find (key) != this ->end (); }
169- 
170-   const  V& at (const  K& key) const 
171-   {
172-     const  auto  pos = find (key);
173-     if  (pos == this ->end ()) {
174-       throw  std::out_of_range (" map key not found"  );
175-     }
176- 
177-     return  pos->value ().second ;
178-   }
179- 
180-   V& at (const  K& key)
181-   {
182-     auto  pos = find (key);
183-     if  (pos == this ->end ()) {
184-       throw  std::out_of_range (" map key not found"  );
185-     }
186- 
187-     return  pos->value ().second ;
188-   }
189- 
190-   template <typename  F>
191-   void  erase_if_key (F&& f)
192-   {
193-     const  auto  to_erase = [&f](const  auto & maybe_pair) {
194-       return  maybe_pair && f (maybe_pair.value ().first );
195-     };
196- 
197-     std::replace_if (this ->begin (), this ->end (), to_erase, std::nullopt );
198-   }
199- };
200- 
20156template <size_t  N>
20257using  owned_bytes = vector<uint8_t , N>;
20358
204- class  Header 
205- {
206- public: 
207-   const  KeyID key_id;
208-   const  Counter counter;
209- 
210-   Header (KeyID key_id_in, Counter counter_in);
211-   static  Header parse (input_bytes buffer);
212- 
213-   input_bytes encoded () const  { return  _encoded; }
214-   size_t  size () const  { return  _encoded.size (); }
215- 
216-   //  Configuration byte plus 8-byte KID and CTR
217-   static  constexpr  size_t  max_size = 1  + 8  + 8 ;
218- 
219- private: 
220-   //  Just the configuration byte
221-   static  constexpr  size_t  min_size = 1 ;
59+ using  KeyID = uint64_t ;
60+ using  Counter = uint64_t ;
22261
223-   owned_bytes<max_size> _encoded;
224- 
225-   Header (KeyID key_id_in, Counter counter_in, input_bytes encoded_in);
226- };
62+ class  Header ;
22763
22864enum  struct  KeyUsage 
22965{
23066  protect,
23167  unprotect,
23268};
23369
234- struct  KeyAndSalt 
70+ struct  KeyRecord 
23571{
236-   static  KeyAndSalt  from_base_key (CipherSuite suite,
237-                                    KeyID key_id,
238-                                    KeyUsage usage,
239-                                    input_bytes base_key);
72+   static  KeyRecord  from_base_key (CipherSuite suite,
73+                                  KeyID key_id,
74+                                  KeyUsage usage,
75+                                  input_bytes base_key);
24076
24177  static  constexpr  size_t  max_key_size = 48 ;
24278  static  constexpr  size_t  max_salt_size = 12 ;
@@ -247,43 +83,10 @@ struct KeyAndSalt
24783  Counter counter;
24884};
24985
250- //  ContextBase represents the core SFrame encryption logic.  It remembers a set
251- //  of keys and salts identified by key IDs, and uses them to protect and
252- //  unprotect payloads.  The SFrame header is **not** written by the protect
253- //  method or read by the unprotect method.  It is assumed that the application
254- //  carries the header values in some other way.
255- // 
256- //  In general, you should prefer Context to ContextBase.
257- class  ContextBase 
258- {
259- public: 
260-   ContextBase (CipherSuite suite_in);
261-   virtual  ~ContextBase ();
262- 
263-   void  add_key (KeyID kid, KeyUsage usage, input_bytes key);
264- 
265-   output_bytes protect (const  Header& header,
266-                        output_bytes ciphertext,
267-                        input_bytes plaintext,
268-                        input_bytes metadata);
269-   output_bytes unprotect (const  Header& header,
270-                          output_bytes ciphertext,
271-                          input_bytes plaintext,
272-                          input_bytes metadata);
273- 
274-   static  constexpr  size_t  max_aad_size = Header::max_size + 512 ;
275- 
276- protected: 
277-   CipherSuite suite;
278- 
279-   static  constexpr  size_t  max_keys = 200 ;
280-   map<KeyID, KeyAndSalt, max_keys> keys;
281- };
282- 
28386//  Context applies the full SFrame transform.  It tracks a counter for each key
28487//  to ensure nonce uniqueness, adds the SFrame header on protect, and
28588//  reads/strips the SFrame header on unprotect.
286- class  Context  :  protected   ContextBase 
89+ class  Context 
28790{
28891public: 
28992  Context (CipherSuite suite);
@@ -299,9 +102,23 @@ class Context : protected ContextBase
299102                         input_bytes ciphertext,
300103                         input_bytes metadata);
301104
105+   static  constexpr  size_t  max_overhead = 17  + 16 ;
106+   static  constexpr  size_t  max_metadata_size = 512 ;
107+ 
302108protected: 
303-   static  constexpr  size_t  max_counters = 200 ;
304-   map<KeyID, Counter, max_counters> counters;
109+   static  constexpr  size_t  max_keys = 200 ;
110+ 
111+   CipherSuite suite;
112+   map<KeyID, KeyRecord, max_keys> keys;
113+ 
114+   output_bytes protect_inner (const  Header& header,
115+                              output_bytes ciphertext,
116+                              input_bytes plaintext,
117+                              input_bytes metadata);
118+   output_bytes unprotect_inner (const  Header& header,
119+                                output_bytes ciphertext,
120+                                input_bytes plaintext,
121+                                input_bytes metadata);
305122};
306123
307124//  MLSContext augments Context with logic for deriving keys from MLS.  Instead
0 commit comments