Skip to content

Commit 0b9ca47

Browse files
committed
Merge remote-tracking branch 'benma/rust-ctaes'
2 parents f12c725 + 09f9dae commit 0b9ca47

29 files changed

+5173
-198
lines changed

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
[submodule "external/cryptoauthlib"]
22
path = external/cryptoauthlib
33
url = https://github.com/BitBoxSwiss/cryptoauthlib.git
4-
[submodule "external/ctaes"]
5-
path = external/ctaes
6-
url = https://github.com/BitBoxSwiss/ctaes.git
74
[submodule "external/libwally-core"]
85
path = external/libwally-core
96
url = https://github.com/BitBoxSwiss/libwally-core.git

external/CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,6 @@ set_property(TARGET fatfs PROPERTY INTERFACE_LINK_LIBRARIES "")
253253
target_include_directories(fatfs SYSTEM PUBLIC fatfs/source)
254254
target_compile_options(fatfs PRIVATE -Wno-switch-default)
255255

256-
add_library(ctaes
257-
ctaes/ctaes.c
258-
)
259-
target_include_directories(ctaes SYSTEM PUBLIC ctaes)
260-
261256
add_library(rtt
262257
SEGGER_RTT_V796b/RTT/SEGGER_RTT.c
263258
)

external/ctaes

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,6 @@ if(CMAKE_CROSSCOMPILING)
485485
optiga
486486
cryptoauthlib
487487
fatfs
488-
ctaes
489488
c
490489
samd51a-ds
491490
asf4-drivers-min

src/cipher/cipher.c

Lines changed: 15 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -13,154 +13,34 @@
1313
// limitations under the License.
1414

1515
#include "cipher.h"
16-
#include <ctaes.h>
17-
18-
#include <stdlib.h>
19-
#include <string.h>
2016

2117
#include <random.h>
22-
#include <util.h>
23-
#include <wally_crypto.h>
18+
#include <rust/rust.h>
2419

2520
#ifdef TESTING
2621
#include <mock_cipher.h>
2722
#endif
2823

29-
#define N_BLOCK (16U)
30-
// Used to sanity-check input to avoid large stack allocations
31-
#define CIPHER_MAX_ALLOC (200U)
32-
33-
static bool _derive_hmac_keys(
34-
const uint8_t* secret,
35-
uint8_t* encryption_key_out,
36-
uint8_t* authentication_key_out)
37-
{
38-
uint8_t hash[64];
39-
UTIL_CLEANUP_64(hash);
40-
if (wally_sha512(secret, 32, hash, sizeof(hash)) != WALLY_OK) {
41-
return false;
42-
}
43-
memcpy(encryption_key_out, hash, 32);
44-
memcpy(authentication_key_out, hash + 32, 32);
45-
return true;
46-
}
47-
48-
// out_len must be at least in_len + N_BLOCK + N_BLOCK
49-
// necessary in_len/out_len range checks are done in cipher_aes_hmac_encrypt().
50-
static bool _aes_encrypt(
51-
const uint8_t* in,
24+
bool cipher_aes_hmac_encrypt(
25+
const unsigned char* in,
5226
size_t in_len,
5327
uint8_t* out,
5428
size_t* out_len,
55-
const uint8_t* key)
29+
const uint8_t* secret)
5630
{
57-
if (in_len > CIPHER_MAX_ALLOC) {
58-
return false;
59-
}
60-
size_t padlen = N_BLOCK - in_len % N_BLOCK;
61-
size_t inpadlen = in_len + padlen;
62-
uint8_t inpad[inpadlen];
63-
*out_len = inpadlen + N_BLOCK;
64-
65-
// PKCS7 padding
66-
memcpy(inpad, in, in_len);
67-
for (size_t i = 0; i < padlen; i++) {
68-
inpad[in_len + i] = padlen;
69-
}
70-
7131
uint8_t iv[32] = {0}; // only 16 bytes needed for IV.
7232
#ifdef TESTING
7333
cipher_mock_iv(iv);
7434
#else
7535
random_32_bytes(iv);
7636
#endif
77-
memcpy(out, iv, N_BLOCK);
78-
79-
AES256_CBC_ctx ctx = {0};
80-
AES256_CBC_init(&ctx, key, iv);
81-
AES256_CBC_encrypt(&ctx, inpadlen / N_BLOCK, out + N_BLOCK, inpad);
82-
*out_len = inpadlen + N_BLOCK;
83-
84-
util_zero(inpad, inpadlen);
85-
util_zero(&ctx, sizeof(ctx));
86-
return true;
87-
}
88-
89-
bool cipher_aes_hmac_encrypt(
90-
const unsigned char* in,
91-
size_t in_len,
92-
uint8_t* out,
93-
size_t* out_len,
94-
const uint8_t* secret)
95-
{
96-
// in_len + iv + pad + hmac
97-
if (*out_len != in_len + N_BLOCK + N_BLOCK + 32) {
98-
return false;
99-
}
100-
uint8_t encryption_key[32];
101-
UTIL_CLEANUP_32(encryption_key);
102-
uint8_t authentication_key[32];
103-
UTIL_CLEANUP_32(authentication_key);
104-
if (!_derive_hmac_keys(secret, encryption_key, authentication_key)) {
105-
return false;
106-
}
107-
108-
size_t encrypt_len = in_len + 32;
109-
if (!_aes_encrypt(in, in_len, out, &encrypt_len, encryption_key)) {
110-
return false;
111-
}
112-
113-
*out_len = encrypt_len + 32;
114-
115-
return wally_hmac_sha256(
116-
authentication_key,
117-
sizeof(authentication_key),
118-
out,
119-
encrypt_len,
120-
out + encrypt_len,
121-
32) == WALLY_OK;
122-
}
123-
124-
// necessary in_len/out_len range checks are done in cipher_aes_hmac_decrypt().
125-
static bool _aes_decrypt(
126-
const uint8_t* in,
127-
size_t in_len,
128-
uint8_t* out,
129-
size_t* out_len,
130-
const uint8_t* key)
131-
{
132-
if (in_len > CIPHER_MAX_ALLOC) {
133-
return false;
134-
}
135-
uint8_t dec_pad[in_len - N_BLOCK];
136-
const uint8_t* iv = in; // first 16 bytes
137-
138-
AES256_CBC_ctx ctx = {0};
139-
AES256_CBC_init(&ctx, key, iv);
140-
AES256_CBC_decrypt(&ctx, in_len / N_BLOCK - 1, dec_pad, in + N_BLOCK);
141-
142-
// Strip PKCS7 padding
143-
uint8_t padlen = dec_pad[in_len - N_BLOCK - 1];
144-
if (padlen > N_BLOCK) {
145-
goto error;
146-
}
147-
if (in_len < N_BLOCK + padlen) {
148-
goto error;
149-
}
150-
for (size_t i = 0; i < padlen; i++) {
151-
if (dec_pad[in_len - N_BLOCK - 1 - i] != padlen) {
152-
goto error;
153-
}
154-
}
155-
memcpy(out, dec_pad, in_len - N_BLOCK - padlen);
156-
*out_len = in_len - N_BLOCK - padlen;
157-
util_zero(dec_pad, sizeof(dec_pad));
158-
util_zero(&ctx, sizeof(ctx));
37+
rust_cipher_encrypt(
38+
rust_util_bytes(iv, 16),
39+
rust_util_bytes(secret, 32),
40+
rust_util_bytes(in, in_len),
41+
rust_util_bytes_mut(out, *out_len),
42+
out_len);
15943
return true;
160-
error:
161-
util_zero(dec_pad, sizeof(dec_pad));
162-
util_zero(&ctx, sizeof(ctx));
163-
return false;
16444
}
16545

16646
bool cipher_aes_hmac_decrypt(
@@ -170,38 +50,9 @@ bool cipher_aes_hmac_decrypt(
17050
size_t* out_len,
17151
const uint8_t* key)
17252
{
173-
// iv + pad + hmac
174-
if (in_len < N_BLOCK + N_BLOCK + 32) {
175-
return false;
176-
}
177-
// have space for at least in_len - iv - hmac
178-
if (*out_len != in_len - N_BLOCK - 32) {
179-
return false;
180-
}
181-
182-
uint8_t encryption_key[32];
183-
UTIL_CLEANUP_32(encryption_key);
184-
uint8_t authentication_key[32];
185-
UTIL_CLEANUP_32(authentication_key);
186-
187-
if (!_derive_hmac_keys(key, encryption_key, authentication_key)) {
188-
return false;
189-
}
190-
191-
uint8_t hmac[32];
192-
UTIL_CLEANUP_32(hmac);
193-
if (wally_hmac_sha256(
194-
authentication_key,
195-
sizeof(authentication_key),
196-
in,
197-
in_len - sizeof(hmac),
198-
hmac,
199-
sizeof(hmac)) != WALLY_OK) {
200-
return false;
201-
}
202-
203-
if (!MEMEQ(hmac, in + in_len - sizeof(hmac), sizeof(hmac))) {
204-
return false;
205-
}
206-
return _aes_decrypt(in, in_len - sizeof(hmac), out, out_len, encryption_key);
53+
return rust_cipher_decrypt(
54+
rust_util_bytes(key, 32),
55+
rust_util_bytes(in, in_len),
56+
rust_util_bytes_mut(out, *out_len),
57+
out_len);
20758
}

src/rust/Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/rust/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ members = [
2323
"bitbox02-sys",
2424
"erc20_params",
2525
"streaming-silent-payments",
26+
"bitbox-aes",
2627
]
2728

2829
resolver = "2"
@@ -73,3 +74,7 @@ codegen-units = 1
7374
panic = 'unwind'
7475
# Set to false to potentially reduce binary size
7576
incremental = true
77+
78+
[profile.test]
79+
debug-assertions = true
80+
overflow-checks = true

src/rust/bitbox-aes/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

src/rust/bitbox-aes/Cargo.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright 2025 Shift Cryptos AG
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+
[package]
16+
name = "bitbox-aes"
17+
version = "0.1.0"
18+
authors = ["Shift Crypto AG <[email protected]>"]
19+
edition = "2024"
20+
license = "Apache-2.0"
21+
22+
[dependencies]
23+
bitbox02 = { path = "../bitbox02", optional = true }
24+
sha2 = { workspace = true }
25+
hmac = { version = "0.12", default-features = false, features = ["reset"] }
26+
ctaes = { version = "0.1.0" }
27+
zeroize = { workspace = true }
28+
29+
[features]
30+
# We use wally_sha512 over `sha2::Sha512`, which bloats the binary by an additional ~12.7kB (at the
31+
# time of writing). This should be enabled for production builds until we can get rid of
32+
# wally_sha512 completely. This feature exists so `cargo test` works.
33+
use-wally-sha512 = [
34+
"dep:bitbox02",
35+
]

0 commit comments

Comments
 (0)