proxygen
AeadTokenCipher-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
10 #include <fizz/crypto/Utils.h>
11 #include <fizz/crypto/aead/Aead.h>
12 
13 namespace fizz {
14 namespace server {
15 
16 /*
17  * Token structure:
18  *
19  * 32 bytes salt
20  * 4 bytes sequence number
21  * remaining data ciphertext
22  *
23  * secret = HKDF-Extract(Codec label, token secret)
24  * if (PSK context)
25  * secret = HKDF-Extract(PSK context, secret)
26  *
27  * (aead key | aead iv) = HKDF-Expand(
28  * secret, salt, key length + iv length)
29  *
30  * The 32 byte salt is used to derive an aead key with sufficient space such
31  * that the salts can be generated randomly without worry of collisions. The
32  * sequence number is currently always 0 when encrypting tokens, however it
33  * could be incremented to avoid an extra HKDF-Expand on every token.
34  */
35 
36 template <typename AeadType, typename HkdfType>
38  const std::vector<folly::ByteRange>& tokenSecrets) {
39  VLOG(3) << "Updating token secrets";
40 
41  for (const auto& tokenSecret : tokenSecrets) {
42  if (tokenSecret.size() < kMinTokenSecretLength) {
43  LOG(ERROR) << "Token cipher secret too small - not updating.";
44  return false;
45  }
46  }
47 
48  VLOG(4) << "Updating token secrets, num=" << tokenSecrets.size();
49  clearSecrets();
50  for (const auto& tokenSecret : tokenSecrets) {
51  Secret extracted(tokenSecret.begin(), tokenSecret.end());
52  for (const auto& contextString : contextStrings_) {
53  extracted = HkdfType().extract(
54  folly::range(contextString), folly::range(extracted));
55  }
56  secrets_.push_back(std::move(extracted));
57  }
58  return true;
59 }
60 
61 template <typename AeadType, typename HkdfType>
63  Buf plaintext) const {
64  if (secrets_.empty()) {
65  return folly::none;
66  }
67 
68  auto salt = RandomGenerator<kSaltLength>().generateRandom();
69  auto aead = createAead(folly::range(secrets_.front()), folly::range(salt));
70 
71  // For now we always use sequence number 0.
72  SeqNum seqNum = 0;
73  auto token = folly::IOBuf::create(kTokenHeaderLength);
74  folly::io::Appender appender(token.get(), kTokenHeaderLength);
75  appender.push(folly::range(salt));
76  appender.writeBE(seqNum);
77  token->prependChain(aead.encrypt(std::move(plaintext), nullptr, seqNum));
78 
79  return std::move(token);
80 }
81 
82 template <typename AeadType, typename HkdfType>
84  Buf token) const {
85  folly::io::Cursor cursor(token.get());
86  if (secrets_.empty() || !cursor.canAdvance(kTokenHeaderLength)) {
87  return folly::none;
88  }
89 
90  Salt salt;
91  cursor.pull(salt.data(), salt.size());
92  auto seqNum = cursor.readBE<SeqNum>();
93  Buf ciphertext;
94  cursor.clone(ciphertext, cursor.totalLength());
95 
96  for (const auto& secret : secrets_) {
97  auto aead = createAead(folly::range(secret), folly::range(salt));
98  auto result = aead.tryDecrypt(ciphertext->clone(), nullptr, seqNum);
99  if (result) {
100  return std::move(result);
101  }
102  }
103 
104  VLOG(6) << "Failed to decrypt token.";
105  return folly::none;
106 }
107 
108 template <typename AeadType, typename HkdfType>
111  folly::ByteRange salt) const {
112  AeadType aead;
113  std::unique_ptr<folly::IOBuf> info = folly::IOBuf::wrapBuffer(salt);
114  auto keys =
115  HkdfType().expand(secret, *info, aead.keyLength() + aead.ivLength());
116  folly::io::Cursor cursor(keys.get());
117  TrafficKey key;
118  cursor.clone(key.key, aead.keyLength());
119  cursor.clone(key.iv, aead.ivLength());
120  aead.setKey(std::move(key));
121  return aead;
122 }
123 
124 template <typename AeadType, typename HkdfType>
126  for (auto& secret : secrets_) {
128  }
129  secrets_.clear();
130 }
131 } // namespace server
132 } // namespace fizz
def info()
Definition: deadlock.py:447
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
static std::unique_ptr< IOBuf > wrapBuffer(const void *buf, std::size_t capacity)
Definition: IOBuf.cpp:353
static void clean(folly::MutableByteRange range)
Definition: Utils.cpp:38
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::vector< uint8_t > Secret
void push(const uint8_t *buf, size_t len)
Definition: Cursor.h:755
std::array< uint8_t, kSaltLength > Salt
folly::Optional< Buf > encrypt(Buf plaintext) const
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
Definition: Actions.h:16
std::unique_ptr< folly::IOBuf > Buf
Definition: Types.h:22
static constexpr StringPiece secret
bool setSecrets(const std::vector< folly::ByteRange > &tokenSecrets)
constexpr None none
Definition: Optional.h:87
folly::Optional< Buf > decrypt(Buf) const
AeadType createAead(folly::ByteRange secret, folly::ByteRange salt) const