1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <crypto/bytes.h>
11 #include <crypto/secret.h>
12 #include <crypto/cipher.h>
13 #include <fbl/macros.h>
14 #include <zircon/types.h>
15 
16 // |crypto::AEAD| is an authenticated encryption and decryption cipher.  It differs from |Cipher| in
17 // that it incurs additional overhead to store its authentication tag, but can verify data integrity
18 // as a result.  The ciphertext produced by an AEAD is the same length as its plaintext, excluding
19 // the IV and tag.  A 64 bit nonce is used to seal plain texts, meaning a given key and IV can be
20 // used for at most 2^64 - 1 operations.
21 namespace crypto {
22 
23 class AEAD final {
24 public:
25     // Algorithm enumerates the supported secret key ciphers.
26     enum Algorithm {
27         kUninitialized = 0,
28         kAES128_GCM,
29         kAES128_GCM_SIV,
30     };
31 
32     AEAD();
33     ~AEAD();
34 
35     // Gets the number of bytes needed for the symmetric key used by the given |aead|.
36     static zx_status_t GetKeyLen(Algorithm aead, size_t* out);
37 
38     // Gets the number of bytes needed for the initialization vector (IV) used by the given
39     // |aead|.
40     static zx_status_t GetIVLen(Algorithm aead, size_t* out);
41 
42     // Gets the length of an authentication tag created by the given |aead|.
43     static zx_status_t GetTagLen(Algorithm aead, size_t* out);
44 
45     // Sets up the AEAD to use the algorithm indicated by |aead| to encrypt data using the given
46     // |key| and |iv|.
InitSeal(Algorithm aead,const Secret & key,const Bytes & iv)47     zx_status_t InitSeal(Algorithm aead, const Secret& key, const Bytes& iv) {
48         return Init(aead, key, iv, Cipher::kEncrypt);
49     }
50 
51     // Sets up the AEAD to use the algorithm indicated by |aead| to decrypt data using the given
52     // |key| and |iv|.
InitOpen(Algorithm aead,const Secret & key,const Bytes & iv)53     zx_status_t InitOpen(Algorithm aead, const Secret& key, const Bytes& iv) {
54         return Init(aead, key, iv, Cipher::kDecrypt);
55     }
56 
57     // Encrypts data from |ptext| to |ctext|, based on the parameters set in |InitSeal|.  Saves the
58     // |iv| used;  |iv| will be resized and filled automatically.  The AEAD tag is stored at the end
59     // of |ctext|  This method will fail if called 2^64 or more times with the same key and IV.  The
60     // second variant includes additional authenticated data in the tag calculation.
Seal(const Bytes & ptext,uint64_t * out_nonce,Bytes * out_ctext)61     zx_status_t Seal(const Bytes& ptext, uint64_t* out_nonce, Bytes* out_ctext) {
62         return Seal(ptext, nullptr, 0, out_nonce, out_ctext);
63     }
Seal(const Bytes & ptext,const Bytes & aad,uint64_t * out_nonce,Bytes * out_ctext)64     zx_status_t Seal(const Bytes& ptext, const Bytes& aad, uint64_t* out_nonce, Bytes* out_ctext) {
65         return Seal(ptext, aad.get(), aad.len(), out_nonce, out_ctext);
66     }
67 
68     // Decrypts data from |ctext| to |ptext|, based on the parameters set in |InitOpen|.
69     // Decryption can only succeed if the |iv| matches those produced by |Seal| and the AEAD tag is
70     // included in |ctext|.  The second variant includes additional authenticated data in the tag
71     // calculation.
Open(uint64_t nonce,const Bytes & ctext,Bytes * out_ptext)72     zx_status_t Open(uint64_t nonce, const Bytes& ctext, Bytes* out_ptext) {
73         return Open(nonce, ctext, nullptr, 0, out_ptext);
74     }
Open(uint64_t nonce,const Bytes & ctext,const Bytes & aad,Bytes * out_ptext)75     zx_status_t Open(uint64_t nonce, const Bytes& ctext, const Bytes& aad, Bytes* out_ptext) {
76         return Open(nonce, ctext, aad.get(), aad.len(), out_ptext);
77     }
78 
79     // Clears all state from this instance.
80     void Reset();
81 
82 private:
83     DISALLOW_COPY_ASSIGN_AND_MOVE(AEAD);
84 
85     // Sets up the aead to encrypt or decrypt data using the given |key| based on the
86     // given |direction|.
87     zx_status_t Init(Algorithm aead, const Secret& key, const Bytes& iv,
88                      Cipher::Direction direction);
89     zx_status_t Seal(const Bytes& ptext, const uint8_t* aad, size_t aad_len, uint64_t* out_nonce,
90                      Bytes* out_ctext);
91     zx_status_t Open(uint64_t nonce, const Bytes& ctext, const uint8_t* aad, size_t aad_len,
92                      Bytes* out_ptext);
93 
94     // Opaque crypto implementation context.
95     struct Context;
96 
97     // Opaque pointer to the crypto implementation context.
98     fbl::unique_ptr<Context> ctx_;
99     // Indicates whether configured to encrypt or decrypt.
100     Cipher::Direction direction_;
101     // Buffer holding initial vector.  The IV is expanded to be |uint64_t|-aligned.
102     fbl::unique_ptr<uint64_t[]> iv_;
103     // Original value of |iv_[0]|.  |Seal| will fail if |iv_[0]| wraps around to this value.
104     uint64_t iv0_;
105     // Size of the actual IV.
106     size_t iv_len_;
107     // Length of authentication tag.
108     size_t tag_len_;
109 };
110 } // namespace crypto
111