1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include "tink/subtle/aes_siv_boringssl.h"
18
19 #include <algorithm>
20 #include <cstdint>
21 #include <iterator>
22 #include <memory>
23 #include <string>
24 #include <utility>
25
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/string_view.h"
29 #include "absl/types/span.h"
30 #include "openssl/aes.h"
31 #include "openssl/crypto.h"
32 #include "tink/aead/internal/aead_util.h"
33 #include "tink/deterministic_aead.h"
34 #include "tink/internal/aes_util.h"
35 #include "tink/subtle/subtle_util.h"
36 #include "tink/util/errors.h"
37 #include "tink/util/status.h"
38 #include "tink/util/statusor.h"
39
40 namespace crypto {
41 namespace tink {
42 namespace subtle {
43 namespace {
44
InitializeAesKey(absl::Span<const uint8_t> key)45 crypto::tink::util::StatusOr<util::SecretUniquePtr<AES_KEY>> InitializeAesKey(
46 absl::Span<const uint8_t> key) {
47 util::SecretUniquePtr<AES_KEY> aes_key = util::MakeSecretUniquePtr<AES_KEY>();
48 if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key.data()),
49 8 * key.size(), aes_key.get()) != 0) {
50 return util::Status(absl::StatusCode::kInternal,
51 "could not initialize aes key");
52 }
53 return std::move(aes_key);
54 }
55
56 } // namespace
57
58 // static
59 crypto::tink::util::StatusOr<std::unique_ptr<DeterministicAead>>
New(const util::SecretData & key)60 AesSivBoringSsl::New(const util::SecretData& key) {
61 auto status = internal::CheckFipsCompatibility<AesSivBoringSsl>();
62 if (!status.ok()) return status;
63
64 if (!IsValidKeySizeInBytes(key.size())) {
65 return util::Status(absl::StatusCode::kInvalidArgument, "invalid key size");
66 }
67 auto k1_or = InitializeAesKey(absl::MakeSpan(key).subspan(0, key.size() / 2));
68 if (!k1_or.ok()) {
69 return k1_or.status();
70 }
71 util::SecretUniquePtr<AES_KEY> k1 = std::move(k1_or).value();
72 auto k2_or = InitializeAesKey(absl::MakeSpan(key).subspan(key.size() / 2));
73 if (!k2_or.ok()) {
74 return k2_or.status();
75 }
76
77 util::SecretUniquePtr<AES_KEY> k2 = std::move(k2_or).value();
78 return {absl::WrapUnique(new AesSivBoringSsl(std::move(k1), std::move(k2)))};
79 }
80
ComputeCmacK1() const81 util::SecretData AesSivBoringSsl::ComputeCmacK1() const {
82 util::SecretData cmac_k1(kBlockSize, 0);
83 EncryptBlock(cmac_k1.data(), cmac_k1.data());
84 MultiplyByX(cmac_k1.data());
85 return cmac_k1;
86 }
87
ComputeCmacK2() const88 util::SecretData AesSivBoringSsl::ComputeCmacK2() const {
89 util::SecretData cmac_k2(cmac_k1_);
90 MultiplyByX(cmac_k2.data());
91 return cmac_k2;
92 }
93
EncryptBlock(const uint8_t in[kBlockSize],uint8_t out[kBlockSize]) const94 void AesSivBoringSsl::EncryptBlock(const uint8_t in[kBlockSize],
95 uint8_t out[kBlockSize]) const {
96 AES_encrypt(in, out, k1_.get());
97 }
98
99 // static
MultiplyByX(uint8_t block[kBlockSize])100 void AesSivBoringSsl::MultiplyByX(uint8_t block[kBlockSize]) {
101 // Carry over 0x87 if msb is 1 0x00 if msb is 0.
102 uint8_t carry = 0x87 & -(block[0] >> 7);
103 for (size_t i = 0; i < kBlockSize - 1; ++i) {
104 block[i] = (block[i] << 1) | (block[i + 1] >> 7);
105 }
106 block[kBlockSize - 1] =
107 (block[kBlockSize - 1] << 1) ^ carry;
108 }
109
110 // static
XorBlock(const uint8_t x[kBlockSize],const uint8_t y[kBlockSize],uint8_t res[kBlockSize])111 void AesSivBoringSsl::XorBlock(const uint8_t x[kBlockSize],
112 const uint8_t y[kBlockSize],
113 uint8_t res[kBlockSize]) {
114 for (int i = 0; i < kBlockSize; ++i) {
115 res[i] = x[i] ^ y[i];
116 }
117 }
118
Cmac(absl::Span<const uint8_t> data,uint8_t mac[kBlockSize]) const119 void AesSivBoringSsl::Cmac(absl::Span<const uint8_t> data,
120 uint8_t mac[kBlockSize]) const {
121 const size_t blocks =
122 std::max(size_t{1}, (data.size() + kBlockSize - 1) / kBlockSize);
123 const size_t last_block_idx = kBlockSize * (blocks - 1);
124 const size_t last_block_size = data.size() - last_block_idx;
125 uint8_t block[kBlockSize];
126 std::fill(std::begin(block), std::end(block), 0);
127 for (size_t idx = 0; idx < last_block_idx; idx += kBlockSize) {
128 XorBlock(block, &data[idx], block);
129 EncryptBlock(block, block);
130 }
131 for (size_t j = 0; j < last_block_size; j++) {
132 block[j] ^= data[last_block_idx + j];
133 }
134 if (last_block_size == kBlockSize) {
135 XorBlock(block, cmac_k1_.data(), block);
136 } else {
137 block[last_block_size] ^= 0x80;
138 XorBlock(block, cmac_k2_.data(), block);
139 }
140 EncryptBlock(block, mac);
141 }
142
143 // Computes Cmac(XorEnd(data, last))
CmacLong(absl::Span<const uint8_t> data,const uint8_t last[kBlockSize],uint8_t mac[kBlockSize]) const144 void AesSivBoringSsl::CmacLong(absl::Span<const uint8_t> data,
145 const uint8_t last[kBlockSize],
146 uint8_t mac[kBlockSize]) const {
147 uint8_t block[kBlockSize];
148 std::copy_n(data.begin(), kBlockSize, block);
149 size_t idx = kBlockSize;
150 while (kBlockSize <= data.size() - idx) {
151 EncryptBlock(block, block);
152 XorBlock(block, &data[idx], block);
153 idx += kBlockSize;
154 }
155 size_t remaining = data.size() - idx;
156 for (int j = 0; j < kBlockSize - remaining; ++j) {
157 block[remaining + j] ^= last[j];
158 }
159 if (remaining == 0) {
160 XorBlock(block, cmac_k1_.data(), block);
161 } else {
162 EncryptBlock(block, block);
163 for (int j = 0; j < remaining; ++j) {
164 block[j] ^= last[kBlockSize - remaining + j];
165 block[j] ^= data[idx + j];
166 }
167 block[remaining] ^= 0x80;
168 XorBlock(block, cmac_k2_.data(), block);
169 }
170 EncryptBlock(block, mac);
171 }
172
S2v(absl::Span<const uint8_t> aad,absl::Span<const uint8_t> msg,uint8_t siv[kBlockSize]) const173 void AesSivBoringSsl::S2v(absl::Span<const uint8_t> aad,
174 absl::Span<const uint8_t> msg,
175 uint8_t siv[kBlockSize]) const {
176 // This stuff could be precomputed.
177 uint8_t block[kBlockSize];
178 std::fill(std::begin(block), std::end(block), 0);
179 Cmac(block, block);
180 MultiplyByX(block);
181
182 uint8_t aad_mac[kBlockSize];
183 Cmac(aad, aad_mac);
184 XorBlock(block, aad_mac, block);
185
186 if (msg.size() >= kBlockSize) {
187 CmacLong(msg, block, siv);
188 } else {
189 MultiplyByX(block);
190 for (size_t i = 0; i < msg.size(); ++i) {
191 block[i] ^= msg[i];
192 }
193 block[msg.size()] ^= 0x80;
194 Cmac(block, siv);
195 }
196 }
197
AesCtrCrypt(absl::string_view in,const uint8_t siv[kBlockSize],const AES_KEY * key,absl::Span<char> out) const198 util::Status AesSivBoringSsl::AesCtrCrypt(absl::string_view in,
199 const uint8_t siv[kBlockSize],
200 const AES_KEY* key,
201 absl::Span<char> out) const {
202 uint8_t iv[kBlockSize];
203 std::copy_n(siv, kBlockSize, iv);
204 iv[8] &= 0x7f;
205 iv[12] &= 0x7f;
206 return internal::AesCtr128Crypt(in, iv, key, out);
207 }
208
EncryptDeterministically(absl::string_view plaintext,absl::string_view associated_data) const209 util::StatusOr<std::string> AesSivBoringSsl::EncryptDeterministically(
210 absl::string_view plaintext, absl::string_view associated_data) const {
211 uint8_t siv[kBlockSize];
212 S2v(absl::MakeSpan(reinterpret_cast<const uint8_t*>(associated_data.data()),
213 associated_data.size()),
214 absl::MakeSpan(reinterpret_cast<const uint8_t*>(plaintext.data()),
215 plaintext.size()),
216 siv);
217 size_t ciphertext_size = plaintext.size() + kBlockSize;
218
219 std::string ciphertext;
220 ResizeStringUninitialized(&ciphertext, ciphertext_size);
221 std::copy(std::begin(siv), std::end(siv), ciphertext.begin());
222 util::Status res =
223 AesCtrCrypt(plaintext, siv, k2_.get(),
224 absl::MakeSpan(ciphertext).subspan(kBlockSize));
225 if (!res.ok()) {
226 return res;
227 }
228 return ciphertext;
229 }
230
DecryptDeterministically(absl::string_view ciphertext,absl::string_view associated_data) const231 util::StatusOr<std::string> AesSivBoringSsl::DecryptDeterministically(
232 absl::string_view ciphertext, absl::string_view associated_data) const {
233 if (ciphertext.size() < kBlockSize) {
234 return util::Status(absl::StatusCode::kInvalidArgument,
235 "ciphertext too short");
236 }
237 size_t plaintext_size = ciphertext.size() - kBlockSize;
238 std::string plaintext;
239 ResizeStringUninitialized(&plaintext, plaintext_size);
240 const uint8_t* siv = reinterpret_cast<const uint8_t*>(&ciphertext[0]);
241 util::Status res = AesCtrCrypt(ciphertext.substr(kBlockSize), siv, k2_.get(),
242 absl::MakeSpan(plaintext));
243 if (!res.ok()) {
244 return res;
245 }
246
247 uint8_t s2v[kBlockSize];
248 S2v(absl::MakeSpan(reinterpret_cast<const uint8_t*>(associated_data.data()),
249 associated_data.size()),
250 absl::MakeSpan(reinterpret_cast<const uint8_t*>(plaintext.data()),
251 plaintext_size),
252 s2v);
253 if (CRYPTO_memcmp(siv, s2v, kBlockSize) != 0) {
254 return util::Status(absl::StatusCode::kInvalidArgument,
255 "invalid ciphertext");
256 }
257 return plaintext;
258 }
259
260 } // namespace subtle
261 } // namespace tink
262 } // namespace crypto
263