1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_crypto/aes_mbedtls.h"
16
17 #include <mbedtls/aes.h>
18 #include <mbedtls/cmac.h>
19
20 #include "pw_assert/check.h"
21 #include "pw_crypto/aes.h"
22 #include "pw_status/status.h"
23
24 namespace {
25 /// Number of bits in a byte.
26 constexpr size_t kBits = 8;
27 } // namespace
28
29 namespace pw::crypto::aes::backend {
30 namespace {
31 using CmacCtx = NativeCmacContext;
32 } // namespace
33
DoInit(CmacCtx & ctx,ConstByteSpan key)34 Status DoInit(CmacCtx& ctx, ConstByteSpan key) {
35 const auto key_data = reinterpret_cast<const unsigned char*>(key.data());
36
37 const mbedtls_cipher_info_t* info;
38 switch (key.size()) {
39 case kKey128SizeBytes:
40 info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
41 break;
42 case kKey192SizeBytes:
43 info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_192_ECB);
44 break;
45 case kKey256SizeBytes:
46 info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB);
47 break;
48 default:
49 PW_CRASH("Unsupported key size for Cmac (%zu bit)", key.size() * kBits);
50 }
51
52 if (mbedtls_cipher_setup(&ctx.cipher, info)) {
53 return Status::Internal();
54 }
55 if (mbedtls_cipher_cmac_starts(&ctx.cipher, key_data, key.size() * kBits)) {
56 return Status::Internal();
57 }
58
59 return OkStatus();
60 }
61
DoUpdate(CmacCtx & ctx,ConstByteSpan data)62 Status DoUpdate(CmacCtx& ctx, ConstByteSpan data) {
63 const auto data_in = reinterpret_cast<const unsigned char*>(data.data());
64 if (mbedtls_cipher_cmac_update(&ctx.cipher, data_in, data.size())) {
65 return Status::Internal();
66 }
67
68 return OkStatus();
69 }
70
DoFinal(CmacCtx & ctx,BlockSpan out_mac)71 Status DoFinal(CmacCtx& ctx, BlockSpan out_mac) {
72 const auto data_out = reinterpret_cast<unsigned char*>(out_mac.data());
73 if (mbedtls_cipher_cmac_finish(&ctx.cipher, data_out)) {
74 return Status::Internal();
75 }
76
77 return OkStatus();
78 }
79
DoEncryptBlock(ConstByteSpan key,ConstBlockSpan plaintext,BlockSpan out_ciphertext)80 Status DoEncryptBlock(ConstByteSpan key,
81 ConstBlockSpan plaintext,
82 BlockSpan out_ciphertext) {
83 const auto key_data = reinterpret_cast<const unsigned char*>(key.data());
84 const auto in = reinterpret_cast<const unsigned char*>(plaintext.data());
85 const auto out = reinterpret_cast<unsigned char*>(out_ciphertext.data());
86
87 mbedtls_aes_context aes;
88 mbedtls_aes_init(&aes);
89
90 if (mbedtls_aes_setkey_enc(&aes, key_data, key.size() * kBits)) {
91 mbedtls_aes_free(&aes);
92 return Status::Internal();
93 }
94 if (mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, in, out)) {
95 mbedtls_aes_free(&aes);
96 return Status::Internal();
97 }
98
99 mbedtls_aes_free(&aes);
100 return OkStatus();
101 }
102
103 } // namespace pw::crypto::aes::backend
104