Skip to content
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

[crypto] Add RSA 3K/4K encryption and basic tests. #20894

Merged
merged 2 commits into from
Jan 24, 2024
Merged
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
44 changes: 38 additions & 6 deletions sw/device/lib/crypto/impl/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,10 +813,18 @@ otcrypto_status_t otcrypto_rsa_encrypt_async_start(
label.data, label.len);
}
case kOtcryptoRsaSize3072: {
return OTCRYPTO_NOT_IMPLEMENTED;
HARDENED_CHECK_EQ(size, kOtcryptoRsaSize3072);
HARDENED_CHECK_EQ(public_key->key_length, sizeof(rsa_3072_public_key_t));
rsa_3072_public_key_t *pk = (rsa_3072_public_key_t *)public_key->key;
return rsa_encrypt_3072_start(pk, hash_mode, message.data, message.len,
label.data, label.len);
}
case kOtcryptoRsaSize4096: {
return OTCRYPTO_NOT_IMPLEMENTED;
HARDENED_CHECK_EQ(size, kOtcryptoRsaSize4096);
HARDENED_CHECK_EQ(public_key->key_length, sizeof(rsa_4096_public_key_t));
rsa_4096_public_key_t *pk = (rsa_4096_public_key_t *)public_key->key;
return rsa_encrypt_4096_start(pk, hash_mode, message.data, message.len,
label.data, label.len);
}
default:
// Invalid key size. Since the size was inferred, should be unreachable.
Expand Down Expand Up @@ -844,10 +852,16 @@ otcrypto_status_t otcrypto_rsa_encrypt_async_finalize(
return rsa_encrypt_2048_finalize(ctext);
}
case kRsa3072NumWords: {
return OTCRYPTO_NOT_IMPLEMENTED;
HARDENED_CHECK_EQ(ciphertext->len * sizeof(uint32_t),
sizeof(rsa_3072_int_t));
rsa_3072_int_t *ctext = (rsa_3072_int_t *)ciphertext->data;
return rsa_encrypt_3072_finalize(ctext);
}
case kRsa4096NumWords: {
return OTCRYPTO_NOT_IMPLEMENTED;
HARDENED_CHECK_EQ(ciphertext->len * sizeof(uint32_t),
sizeof(rsa_4096_int_t));
rsa_4096_int_t *ctext = (rsa_4096_int_t *)ciphertext->data;
return rsa_encrypt_4096_finalize(ctext);
}
default:
return OTCRYPTO_BAD_ARGS;
Expand Down Expand Up @@ -902,10 +916,28 @@ otcrypto_status_t otcrypto_rsa_decrypt_async_start(
return rsa_decrypt_2048_start(sk, ctext);
}
case kOtcryptoRsaSize3072: {
return OTCRYPTO_NOT_IMPLEMENTED;
HARDENED_CHECK_EQ(size, kOtcryptoRsaSize3072);
HARDENED_CHECK_EQ(private_key->keyblob_length,
sizeof(rsa_3072_private_key_t));
if (ciphertext.len != kRsa3072NumWords) {
return OTCRYPTO_BAD_ARGS;
}
rsa_3072_private_key_t *sk =
(rsa_3072_private_key_t *)private_key->keyblob;
rsa_3072_int_t *ctext = (rsa_3072_int_t *)ciphertext.data;
return rsa_decrypt_3072_start(sk, ctext);
}
case kOtcryptoRsaSize4096: {
return OTCRYPTO_NOT_IMPLEMENTED;
HARDENED_CHECK_EQ(size, kOtcryptoRsaSize4096);
HARDENED_CHECK_EQ(private_key->keyblob_length,
sizeof(rsa_4096_private_key_t));
if (ciphertext.len != kRsa4096NumWords) {
return OTCRYPTO_BAD_ARGS;
}
rsa_4096_private_key_t *sk =
(rsa_4096_private_key_t *)private_key->keyblob;
rsa_4096_int_t *ctext = (rsa_4096_int_t *)ciphertext.data;
return rsa_decrypt_4096_start(sk, ctext);
}
default:
// Invalid key size. Since the size was inferred, should be unreachable.
Expand Down
54 changes: 54 additions & 0 deletions sw/device/lib/crypto/impl/rsa/rsa_encryption.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,57 @@ status_t rsa_decrypt_finalize(const otcrypto_hash_mode_t hash_mode,
HARDENED_TRAP();
return OTCRYPTO_FATAL_ERR;
}

status_t rsa_encrypt_3072_start(const rsa_3072_public_key_t *public_key,
const otcrypto_hash_mode_t hash_mode,
const uint8_t *message, size_t message_bytelen,
const uint8_t *label, size_t label_bytelen) {
// Encode the message.
rsa_3072_int_t encoded_message;
HARDENED_TRY(rsa_padding_oaep_encode(
hash_mode, message, message_bytelen, label, label_bytelen,
ARRAYSIZE(encoded_message.data), encoded_message.data));

// Start computing (encoded_message ^ e) mod n with a variable-time
// exponentiation.
return rsa_modexp_vartime_3072_start(&encoded_message, public_key->e,
&public_key->n);
}

status_t rsa_encrypt_3072_finalize(rsa_3072_int_t *ciphertext) {
return rsa_modexp_3072_finalize(ciphertext);
}

status_t rsa_decrypt_3072_start(const rsa_3072_private_key_t *private_key,
const rsa_3072_int_t *ciphertext) {
// Start computing (ciphertext ^ d) mod n.
return rsa_modexp_consttime_3072_start(ciphertext, &private_key->d,
&private_key->n);
}

status_t rsa_encrypt_4096_start(const rsa_4096_public_key_t *public_key,
const otcrypto_hash_mode_t hash_mode,
const uint8_t *message, size_t message_bytelen,
const uint8_t *label, size_t label_bytelen) {
// Encode the message.
rsa_4096_int_t encoded_message;
HARDENED_TRY(rsa_padding_oaep_encode(
hash_mode, message, message_bytelen, label, label_bytelen,
ARRAYSIZE(encoded_message.data), encoded_message.data));

// Start computing (encoded_message ^ e) mod n with a variable-time
// exponentiation.
return rsa_modexp_vartime_4096_start(&encoded_message, public_key->e,
&public_key->n);
}

status_t rsa_encrypt_4096_finalize(rsa_4096_int_t *ciphertext) {
return rsa_modexp_4096_finalize(ciphertext);
}

status_t rsa_decrypt_4096_start(const rsa_4096_private_key_t *private_key,
const rsa_4096_int_t *ciphertext) {
// Start computing (ciphertext ^ d) mod n.
return rsa_modexp_consttime_4096_start(ciphertext, &private_key->d,
&private_key->n);
}
98 changes: 98 additions & 0 deletions sw/device/lib/crypto/impl/rsa/rsa_encryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,104 @@ status_t rsa_decrypt_finalize(const otcrypto_hash_mode_t hash_mode,
size_t plaintext_max_bytelen, uint8_t *plaintext,
size_t *plaintext_bytelen);

/**
* Starts encrypting a message with RSA-3072; returns immediately.
*
* The key exponent must be F4=65537; no other exponents are supported. The
* padding scheme is OAEP, and the mask generation function (MGF) is MGF1 with
* the hash function indicated by `hash_mode` and a salt the same length as the
* hash function output.
*
* Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy.
*
* @param public_key RSA public key.
* @param hash_mode Hash function to use for message encoding.
* @param message Message to encrypt.
* @param message_bytelen Message length in bytes.
* @param label Label for OAEP padding.
* @param label_bytelen Length of label in bytes.
* @return Result of the operation (OK or error).
*/
OT_WARN_UNUSED_RESULT
status_t rsa_encrypt_3072_start(const rsa_3072_public_key_t *public_key,
const otcrypto_hash_mode_t hash_mode,
const uint8_t *message, size_t message_bytelen,
const uint8_t *label, size_t label_bytelen);

/**
* Waits for an RSA-3072 encryption to complete.
*
* Should be invoked only after a `rsa_encrypt_3072_start` call. Blocks until
* OTBN is done processing.
*
* @param[out] ciphertext Encrypted message.
* @return Result of the operation (OK or error).
*/
OT_WARN_UNUSED_RESULT
status_t rsa_encrypt_3072_finalize(rsa_3072_int_t *ciphertext);

/**
* Start decrypting a message with RSA-3072; returns immediately.
*
* Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy.
*
* @param private_key RSA private key.
* @param ciphertext Encrypted message.
* @return Result of the operation (OK or error).
*/
OT_WARN_UNUSED_RESULT
status_t rsa_decrypt_3072_start(const rsa_3072_private_key_t *private_key,
const rsa_3072_int_t *ciphertext);

/**
* Starts encrypting a message with RSA-4096; returns immediately.
*
* The key exponent must be F4=65537; no other exponents are supported. The
* padding scheme is OAEP, and the mask generation function (MGF) is MGF1 with
* the hash function indicated by `hash_mode` and a salt the same length as the
* hash function output.
*
* Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy.
*
* @param public_key RSA public key.
* @param hash_mode Hash function to use for message encoding.
* @param message Message to encrypt.
* @param message_bytelen Message length in bytes.
* @param label Label for OAEP padding.
* @param label_bytelen Length of label in bytes.
* @return Result of the operation (OK or error).
*/
OT_WARN_UNUSED_RESULT
status_t rsa_encrypt_4096_start(const rsa_4096_public_key_t *public_key,
const otcrypto_hash_mode_t hash_mode,
const uint8_t *message, size_t message_bytelen,
const uint8_t *label, size_t label_bytelen);

/**
* Waits for an RSA-4096 encryption to complete.
*
* Should be invoked only after a `rsa_encrypt_4096_start` call. Blocks until
* OTBN is done processing.
*
* @param[out] ciphertext Encrypted message.
* @return Result of the operation (OK or error).
*/
OT_WARN_UNUSED_RESULT
status_t rsa_encrypt_4096_finalize(rsa_4096_int_t *ciphertext);

/**
* Start decrypting a message with RSA-4096; returns immediately.
*
* Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy.
*
* @param private_key RSA private key.
* @param ciphertext Encrypted message.
* @return Result of the operation (OK or error).
*/
OT_WARN_UNUSED_RESULT
status_t rsa_decrypt_4096_start(const rsa_4096_private_key_t *private_key,
const rsa_4096_int_t *ciphertext);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Expand Down
32 changes: 32 additions & 0 deletions sw/device/tests/crypto/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,38 @@ opentitan_test(
],
)

opentitan_test(
name = "rsa_3072_encryption_functest",
srcs = ["rsa_3072_encryption_functest.c"],
exec_env = EARLGREY_TEST_ENVS,
verilator = verilator_params(
timeout = "eternal",
),
deps = [
"//sw/device/lib/crypto/impl:hash",
"//sw/device/lib/crypto/impl:rsa",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing:profile",
"//sw/device/lib/testing/test_framework:ottf_main",
],
)

opentitan_test(
name = "rsa_4096_encryption_functest",
srcs = ["rsa_4096_encryption_functest.c"],
exec_env = EARLGREY_TEST_ENVS,
verilator = verilator_params(
timeout = "eternal",
),
deps = [
"//sw/device/lib/crypto/impl:hash",
"//sw/device/lib/crypto/impl:rsa",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing:profile",
"//sw/device/lib/testing/test_framework:ottf_main",
],
)

opentitan_test(
name = "rsa_2048_key_from_cofactor_functest",
srcs = ["rsa_2048_key_from_cofactor_functest.c"],
Expand Down
Loading
Loading