Skip to content

[wip] Port some keystore functions to Rust #1425

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
[submodule "external/cryptoauthlib"]
path = external/cryptoauthlib
url = https://github.com/BitBoxSwiss/cryptoauthlib.git
[submodule "external/ctaes"]
path = external/ctaes
url = https://github.com/BitBoxSwiss/ctaes.git
[submodule "external/libwally-core"]
path = external/libwally-core
url = https://github.com/BitBoxSwiss/libwally-core.git
Expand Down
5 changes: 0 additions & 5 deletions external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,6 @@ set_property(TARGET fatfs PROPERTY INTERFACE_LINK_LIBRARIES "")
target_include_directories(fatfs SYSTEM PUBLIC fatfs/source)
target_compile_options(fatfs PRIVATE -Wno-switch-default)

add_library(ctaes
ctaes/ctaes.c
)
target_include_directories(ctaes SYSTEM PUBLIC ctaes)

add_library(rtt
SEGGER_RTT_V796b/RTT/SEGGER_RTT.c
)
Expand Down
1 change: 0 additions & 1 deletion external/ctaes
Submodule ctaes deleted from 8012b0
1 change: 0 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ if(CMAKE_CROSSCOMPILING)
optiga
cryptoauthlib
fatfs
ctaes
c
samd51a-ds
asf4-drivers-min
Expand Down
179 changes: 15 additions & 164 deletions src/cipher/cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,154 +13,34 @@
// limitations under the License.

#include "cipher.h"
#include <ctaes.h>

#include <stdlib.h>
#include <string.h>

#include <random.h>
#include <util.h>
#include <wally_crypto.h>
#include <rust/rust.h>

#ifdef TESTING
#include <mock_cipher.h>
#endif

#define N_BLOCK (16U)
// Used to sanity-check input to avoid large stack allocations
#define CIPHER_MAX_ALLOC (200U)

static bool _derive_hmac_keys(
const uint8_t* secret,
uint8_t* encryption_key_out,
uint8_t* authentication_key_out)
{
uint8_t hash[64];
UTIL_CLEANUP_64(hash);
if (wally_sha512(secret, 32, hash, sizeof(hash)) != WALLY_OK) {
return false;
}
memcpy(encryption_key_out, hash, 32);
memcpy(authentication_key_out, hash + 32, 32);
return true;
}

// out_len must be at least in_len + N_BLOCK + N_BLOCK
// necessary in_len/out_len range checks are done in cipher_aes_hmac_encrypt().
static bool _aes_encrypt(
const uint8_t* in,
bool cipher_aes_hmac_encrypt(
const unsigned char* in,
size_t in_len,
uint8_t* out,
size_t* out_len,
const uint8_t* key)
const uint8_t* secret)
{
if (in_len > CIPHER_MAX_ALLOC) {
return false;
}
size_t padlen = N_BLOCK - in_len % N_BLOCK;
size_t inpadlen = in_len + padlen;
uint8_t inpad[inpadlen];
*out_len = inpadlen + N_BLOCK;

// PKCS7 padding
memcpy(inpad, in, in_len);
for (size_t i = 0; i < padlen; i++) {
inpad[in_len + i] = padlen;
}

uint8_t iv[32] = {0}; // only 16 bytes needed for IV.
#ifdef TESTING
cipher_mock_iv(iv);
#else
random_32_bytes(iv);
#endif
memcpy(out, iv, N_BLOCK);

AES256_CBC_ctx ctx = {0};
AES256_CBC_init(&ctx, key, iv);
AES256_CBC_encrypt(&ctx, inpadlen / N_BLOCK, out + N_BLOCK, inpad);
*out_len = inpadlen + N_BLOCK;

util_zero(inpad, inpadlen);
util_zero(&ctx, sizeof(ctx));
return true;
}

bool cipher_aes_hmac_encrypt(
const unsigned char* in,
size_t in_len,
uint8_t* out,
size_t* out_len,
const uint8_t* secret)
{
// in_len + iv + pad + hmac
if (*out_len != in_len + N_BLOCK + N_BLOCK + 32) {
return false;
}
uint8_t encryption_key[32];
UTIL_CLEANUP_32(encryption_key);
uint8_t authentication_key[32];
UTIL_CLEANUP_32(authentication_key);
if (!_derive_hmac_keys(secret, encryption_key, authentication_key)) {
return false;
}

size_t encrypt_len = in_len + 32;
if (!_aes_encrypt(in, in_len, out, &encrypt_len, encryption_key)) {
return false;
}

*out_len = encrypt_len + 32;

return wally_hmac_sha256(
authentication_key,
sizeof(authentication_key),
out,
encrypt_len,
out + encrypt_len,
32) == WALLY_OK;
}

// necessary in_len/out_len range checks are done in cipher_aes_hmac_decrypt().
static bool _aes_decrypt(
const uint8_t* in,
size_t in_len,
uint8_t* out,
size_t* out_len,
const uint8_t* key)
{
if (in_len > CIPHER_MAX_ALLOC) {
return false;
}
uint8_t dec_pad[in_len - N_BLOCK];
const uint8_t* iv = in; // first 16 bytes

AES256_CBC_ctx ctx = {0};
AES256_CBC_init(&ctx, key, iv);
AES256_CBC_decrypt(&ctx, in_len / N_BLOCK - 1, dec_pad, in + N_BLOCK);

// Strip PKCS7 padding
uint8_t padlen = dec_pad[in_len - N_BLOCK - 1];
if (padlen > N_BLOCK) {
goto error;
}
if (in_len < N_BLOCK + padlen) {
goto error;
}
for (size_t i = 0; i < padlen; i++) {
if (dec_pad[in_len - N_BLOCK - 1 - i] != padlen) {
goto error;
}
}
memcpy(out, dec_pad, in_len - N_BLOCK - padlen);
*out_len = in_len - N_BLOCK - padlen;
util_zero(dec_pad, sizeof(dec_pad));
util_zero(&ctx, sizeof(ctx));
rust_cipher_encrypt(
rust_util_bytes(iv, 16),
rust_util_bytes(secret, 32),
rust_util_bytes(in, in_len),
rust_util_bytes_mut(out, *out_len),
out_len);
return true;
error:
util_zero(dec_pad, sizeof(dec_pad));
util_zero(&ctx, sizeof(ctx));
return false;
}

bool cipher_aes_hmac_decrypt(
Expand All @@ -170,38 +50,9 @@ bool cipher_aes_hmac_decrypt(
size_t* out_len,
const uint8_t* key)
{
// iv + pad + hmac
if (in_len < N_BLOCK + N_BLOCK + 32) {
return false;
}
// have space for at least in_len - iv - hmac
if (*out_len != in_len - N_BLOCK - 32) {
return false;
}

uint8_t encryption_key[32];
UTIL_CLEANUP_32(encryption_key);
uint8_t authentication_key[32];
UTIL_CLEANUP_32(authentication_key);

if (!_derive_hmac_keys(key, encryption_key, authentication_key)) {
return false;
}

uint8_t hmac[32];
UTIL_CLEANUP_32(hmac);
if (wally_hmac_sha256(
authentication_key,
sizeof(authentication_key),
in,
in_len - sizeof(hmac),
hmac,
sizeof(hmac)) != WALLY_OK) {
return false;
}

if (!MEMEQ(hmac, in + in_len - sizeof(hmac), sizeof(hmac))) {
return false;
}
return _aes_decrypt(in, in_len - sizeof(hmac), out, out_len, encryption_key);
return rust_cipher_decrypt(
rust_util_bytes(key, 32),
rust_util_bytes(in, in_len),
rust_util_bytes_mut(out, *out_len),
out_len);
}
57 changes: 1 addition & 56 deletions src/keystore.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,67 +210,12 @@ static keystore_error_t _get_and_decrypt_seed(
return KEYSTORE_OK;
}

static bool _verify_seed(
const char* password,
const uint8_t* expected_seed,
size_t expected_seed_len)
{
uint8_t decrypted_seed[KEYSTORE_MAX_SEED_LENGTH] = {0};
size_t seed_len;
UTIL_CLEANUP_32(decrypted_seed);
if (_get_and_decrypt_seed(password, decrypted_seed, &seed_len, NULL) != KEYSTORE_OK) {
return false;
}
if (expected_seed_len != seed_len) {
return false;
}
if (!MEMEQ(expected_seed, decrypted_seed, seed_len)) {
return false;
}
return true;
}

keystore_error_t keystore_encrypt_and_store_seed(
const uint8_t* seed,
size_t seed_length,
const char* password)
{
if (memory_is_initialized()) {
return KEYSTORE_ERR_MEMORY;
}
keystore_lock();
if (!_validate_seed_length(seed_length)) {
return KEYSTORE_ERR_SEED_SIZE;
}
if (securechip_init_new_password(password)) {
return KEYSTORE_ERR_SECURECHIP;
}
uint8_t secret[32] = {0};
UTIL_CLEANUP_32(secret);
if (securechip_stretch_password(password, secret)) {
return KEYSTORE_ERR_SECURECHIP;
}

size_t encrypted_seed_len = seed_length + 64;
uint8_t encrypted_seed[encrypted_seed_len];
UTIL_CLEANUP_32(encrypted_seed);
if (!cipher_aes_hmac_encrypt(seed, seed_length, encrypted_seed, &encrypted_seed_len, secret)) {
return KEYSTORE_ERR_ENCRYPT;
}
if (encrypted_seed_len > 255) { // sanity check, can't happen
Abort("keystore_encrypt_and_store_seed");
}
uint8_t encrypted_seed_len_u8 = (uint8_t)encrypted_seed_len;
if (!memory_set_encrypted_seed_and_hmac(encrypted_seed, encrypted_seed_len_u8)) {
return KEYSTORE_ERR_MEMORY;
}
if (!_verify_seed(password, seed, seed_length)) {
if (!memory_reset_hww()) {
return KEYSTORE_ERR_MEMORY;
}
return KEYSTORE_ERR_MEMORY;
}
return KEYSTORE_OK;
return rust_keystore_encrypt_and_store_seed(rust_util_bytes(seed, seed_length), password);
}

keystore_error_t keystore_create_and_store_seed(
Expand Down
3 changes: 3 additions & 0 deletions src/memory/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,9 @@ bool memory_set_encrypted_seed_and_hmac(const uint8_t* encrypted_seed_and_hmac,
{
chunk_1_t chunk = {0};
CLEANUP_CHUNK(chunk);
if (len > sizeof(chunk.fields.encrypted_seed_and_hmac)) {
return false;
}
_read_chunk(CHUNK_1, chunk_bytes);
chunk.fields.encrypted_seed_and_hmac_len = len;
memset(
Expand Down
Loading
Loading