proxygen
OpenSSLEVPCipher-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 
9 namespace fizz {
10 namespace detail {
12  std::unique_ptr<folly::IOBuf>&& ciphertext,
13  const folly::IOBuf* associatedData,
16  bool useBlockOps,
17  EVP_CIPHER_CTX* decryptCtx);
18 
19 std::unique_ptr<folly::IOBuf> evpEncrypt(
20  std::unique_ptr<folly::IOBuf>&& plaintext,
21  const folly::IOBuf* associatedData,
23  size_t tagLen,
24  bool useBlockOps,
25  size_t headroom,
26  EVP_CIPHER_CTX* encryptCtx);
27 } // namespace detail
28 
29 template <typename EVPImpl>
31  encryptCtx_.reset(EVP_CIPHER_CTX_new());
32  if (encryptCtx_ == nullptr) {
33  throw std::runtime_error("Unable to allocate an EVP_CIPHER_CTX object");
34  }
35  decryptCtx_.reset(EVP_CIPHER_CTX_new());
36  if (decryptCtx_ == nullptr) {
37  throw std::runtime_error("Unable to allocate an EVP_CIPHER_CTX object");
38  }
39  if (EVP_EncryptInit_ex(
40  encryptCtx_.get(), EVPImpl::Cipher(), nullptr, nullptr, nullptr) !=
41  1) {
42  throw std::runtime_error("Init error");
43  }
44  if (EVP_CIPHER_CTX_ctrl(
45  encryptCtx_.get(),
46  EVP_CTRL_GCM_SET_IVLEN,
47  EVPImpl::kIVLength,
48  nullptr) != 1) {
49  throw std::runtime_error("Error setting iv length");
50  }
51  if (EVP_DecryptInit_ex(
52  decryptCtx_.get(), EVPImpl::Cipher(), nullptr, nullptr, nullptr) !=
53  1) {
54  throw std::runtime_error("Init error");
55  }
56  if (EVP_CIPHER_CTX_ctrl(
57  decryptCtx_.get(),
58  EVP_CTRL_GCM_SET_IVLEN,
59  EVPImpl::kIVLength,
60  nullptr) != 1) {
61  throw std::runtime_error("Error setting iv length");
62  }
63 
64  if (EVPImpl::kRequiresPresetTagLen) {
65  if (EVP_CIPHER_CTX_ctrl(
66  encryptCtx_.get(),
67  EVP_CTRL_GCM_SET_TAG,
68  EVPImpl::kTagLength,
69  nullptr) != 1) {
70  throw std::runtime_error("Error setting enc tag length");
71  }
72 
73  if (EVP_CIPHER_CTX_ctrl(
74  decryptCtx_.get(),
75  EVP_CTRL_GCM_SET_TAG,
76  EVPImpl::kTagLength,
77  nullptr) != 1) {
78  throw std::runtime_error("Error setting dec tag length");
79  }
80  }
81 }
82 
83 template <typename EVPImpl>
85  trafficKey.key->coalesce();
86  trafficKey.iv->coalesce();
87  if (trafficKey.key->length() != EVPImpl::kKeyLength) {
88  throw std::runtime_error("Invalid key");
89  }
90  if (trafficKey.iv->length() != EVPImpl::kIVLength) {
91  throw std::runtime_error("Invalid IV");
92  }
93  trafficKey_ = std::move(trafficKey);
94  if (EVP_EncryptInit_ex(
95  encryptCtx_.get(),
96  nullptr,
97  nullptr,
98  trafficKey_.key->data(),
99  nullptr) != 1) {
100  throw std::runtime_error("Error setting encrypt key");
101  }
102  if (EVP_DecryptInit_ex(
103  decryptCtx_.get(),
104  nullptr,
105  nullptr,
106  trafficKey_.key->data(),
107  nullptr) != 1) {
108  throw std::runtime_error("Error setting decrypt key");
109  }
110 }
111 
112 template <typename EVPImpl>
113 std::unique_ptr<folly::IOBuf> OpenSSLEVPCipher<EVPImpl>::encrypt(
114  std::unique_ptr<folly::IOBuf>&& plaintext,
115  const folly::IOBuf* associatedData,
116  uint64_t seqNum) const {
117  auto iv = createIV(seqNum);
118  return detail::evpEncrypt(
119  std::move(plaintext),
120  associatedData,
121  iv,
122  EVPImpl::kTagLength,
123  EVPImpl::kOperatesInBlocks,
124  headroom_,
125  encryptCtx_.get());
126 }
127 
128 template <typename EVPImpl>
131  std::unique_ptr<folly::IOBuf>&& ciphertext,
132  const folly::IOBuf* associatedData,
133  uint64_t seqNum) const {
134  auto iv = createIV(seqNum);
135  // buffer to copy the tag into when we decrypt
136  std::array<uint8_t, EVPImpl::kTagLength> tagData;
137  folly::MutableByteRange tagOut{tagData};
138  return detail::evpDecrypt(
139  std::move(ciphertext),
140  associatedData,
141  iv,
142  tagOut,
143  EVPImpl::kOperatesInBlocks,
144  decryptCtx_.get());
145 }
146 
147 template <typename EVPImpl>
149  return EVPImpl::kTagLength;
150 }
151 
152 template <typename EVPImpl>
153 std::array<uint8_t, EVPImpl::kIVLength> OpenSSLEVPCipher<EVPImpl>::createIV(
154  uint64_t seqNum) const {
155  std::array<uint8_t, EVPImpl::kIVLength> iv;
156  uint64_t bigEndianSeqNum = folly::Endian::big(seqNum);
157  const size_t prefixLength = EVPImpl::kIVLength - sizeof(uint64_t);
158  memset(iv.data(), 0, prefixLength);
159  memcpy(iv.data() + prefixLength, &bigEndianSeqNum, 8);
160  XOR(trafficKey_.iv->coalesce(), folly::range(iv));
161  return iv;
162 }
163 } // namespace fizz
std::unique_ptr< folly::IOBuf > encrypt(std::unique_ptr< folly::IOBuf > &&plaintext, const folly::IOBuf *associatedData, uint64_t seqNum) const override
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::unique_ptr< folly::IOBuf > key
Definition: Aead.h:17
std::unique_ptr< folly::IOBuf > iv
Definition: Aead.h:18
void XOR(ByteRange first, MutableByteRange second)
Definition: IOBufUtil.cpp:33
static T big(T x)
Definition: Bits.h:259
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
Definition: Actions.h:16
std::array< uint8_t, EVPImpl::kIVLength > createIV(uint64_t seqNum) const
folly::Optional< std::unique_ptr< folly::IOBuf > > tryDecrypt(std::unique_ptr< folly::IOBuf > &&ciphertext, const folly::IOBuf *associatedData, uint64_t seqNum) const override
std::unique_ptr< folly::IOBuf > evpEncrypt(std::unique_ptr< folly::IOBuf > &&plaintext, const folly::IOBuf *associatedData, folly::ByteRange iv, size_t tagLen, bool useBlockOps, size_t headroom, EVP_CIPHER_CTX *encryptCtx)
void setKey(TrafficKey trafficKey) override
size_t getCipherOverhead() const override
folly::Optional< std::unique_ptr< folly::IOBuf > > evpDecrypt(std::unique_ptr< folly::IOBuf > &&ciphertext, const folly::IOBuf *associatedData, folly::ByteRange iv, folly::MutableByteRange tag, bool useBlockOps, EVP_CIPHER_CTX *decryptCtx)