mirror of
https://github.com/polhenarejos/pico-hsm.git
synced 2024-09-20 03:10:09 +00:00
Compare commits
28 Commits
7493f9eb3e
...
b571b0b945
Author | SHA1 | Date | |
---|---|---|---|
|
b571b0b945 | ||
|
5ae63959d5 | ||
|
8e8bd32b44 | ||
|
68d2909653 | ||
|
e64eb2157c | ||
|
af23b401cb | ||
|
1da29f22c1 | ||
|
f458750c91 | ||
|
c5143df212 | ||
|
60f471cdd7 | ||
|
5c3c45a189 | ||
|
3b92ce0597 | ||
|
56ab770a26 | ||
|
09f7ed6640 | ||
|
aaf1bc2bbd | ||
|
f7e8359835 | ||
|
1c45295d28 | ||
|
af099cd416 | ||
|
36d1011471 | ||
|
c5714a91ab | ||
|
b8002a1a08 | ||
|
604fc1aa45 | ||
|
39a5af8649 | ||
|
28c63a500c | ||
|
ef03ce4020 | ||
|
9335b088cf | ||
|
9cc934282c | ||
|
2ad67e5e17 |
@ -20,8 +20,6 @@ cmake_minimum_required(VERSION 3.13)
|
||||
if(ESP_PLATFORM)
|
||||
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(USB_ITF_CCID 1)
|
||||
set(USB_ITF_WCID 1)
|
||||
else()
|
||||
if(ENABLE_EMULATION)
|
||||
else()
|
||||
@ -104,29 +102,30 @@ if (NOT MSVC)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(pico_hsm PUBLIC
|
||||
-fdata-sections
|
||||
-ffunction-sections
|
||||
)
|
||||
endif()
|
||||
if(APPLE)
|
||||
target_link_options(pico_hsm PUBLIC
|
||||
-Wl,-dead_strip
|
||||
)
|
||||
elseif(MSVC)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(pico_hsm PUBLIC
|
||||
-WX
|
||||
)
|
||||
|
||||
target_link_libraries(pico_hsm PUBLIC wsock32 ws2_32 Bcrypt)
|
||||
else()
|
||||
target_link_options(pico_hsm PUBLIC
|
||||
-Wl,--gc-sections
|
||||
-fdata-sections
|
||||
-ffunction-sections
|
||||
)
|
||||
endif()
|
||||
if(APPLE)
|
||||
target_link_options(pico_hsm PUBLIC
|
||||
-Wl,-dead_strip
|
||||
)
|
||||
elseif(MSVC)
|
||||
target_compile_options(pico_hsm PUBLIC
|
||||
-WX
|
||||
)
|
||||
endif (APPLE)
|
||||
|
||||
target_link_libraries(pico_hsm PUBLIC wsock32 ws2_32 Bcrypt)
|
||||
else()
|
||||
target_link_options(pico_hsm PUBLIC
|
||||
-Wl,--gc-sections
|
||||
)
|
||||
endif (APPLE)
|
||||
target_link_libraries(pico_hsm PRIVATE pthread m)
|
||||
else()
|
||||
pico_add_extra_outputs(pico_hsm)
|
||||
target_link_libraries(pico_hsm PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)
|
||||
|
||||
target_link_libraries(pico_hsm PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id pico_aon_timer tinyusb_device tinyusb_board)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -1,45 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION_MAJOR="4"
|
||||
VERSION_MINOR="0-eddsa1"
|
||||
VERSION_MINOR="2-eddsa1"
|
||||
|
||||
rm -rf release/*
|
||||
cd build_release
|
||||
|
||||
for board in adafruit_feather_rp2040 \
|
||||
for board in 0xcb_helios \
|
||||
adafruit_feather_rp2040_usb_host \
|
||||
adafruit_feather_rp2040 \
|
||||
adafruit_itsybitsy_rp2040 \
|
||||
adafruit_kb2040 \
|
||||
adafruit_macropad_rp2040 \
|
||||
adafruit_qtpy_rp2040 \
|
||||
adafruit_trinkey_qt2040 \
|
||||
amethyst_fpga \
|
||||
archi \
|
||||
arduino_nano_rp2040_connect \
|
||||
cytron_maker_pi_rp2040 \
|
||||
datanoisetv_rp2040_dsp \
|
||||
eetree_gamekit_rp2040 \
|
||||
garatronic_pybstick26_rp2040 \
|
||||
gen4_rp2350_24 \
|
||||
gen4_rp2350_24ct \
|
||||
gen4_rp2350_24t \
|
||||
gen4_rp2350_28 \
|
||||
gen4_rp2350_28ct \
|
||||
gen4_rp2350_28t \
|
||||
gen4_rp2350_32 \
|
||||
gen4_rp2350_32ct \
|
||||
gen4_rp2350_32t \
|
||||
gen4_rp2350_35 \
|
||||
gen4_rp2350_35ct \
|
||||
gen4_rp2350_35t \
|
||||
hellbender_2350A_devboard \
|
||||
ilabs_challenger_rp2350_bconnect \
|
||||
ilabs_challenger_rp2350_wifi_ble \
|
||||
ilabs_opendec02 \
|
||||
melopero_perpetuo_rp2350_lora \
|
||||
melopero_shake_rp2040 \
|
||||
metrotech_xerxes_rp2040 \
|
||||
net8086_usb_interposer \
|
||||
nullbits_bit_c_pro \
|
||||
phyx_rick_tny_rp2350 \
|
||||
pi-plates_micropi \
|
||||
pico \
|
||||
pico_w \
|
||||
pico2 \
|
||||
pimoroni_badger2040 \
|
||||
pimoroni_interstate75 \
|
||||
pimoroni_keybow2040 \
|
||||
pimoroni_motor2040 \
|
||||
pimoroni_pga2040 \
|
||||
pimoroni_pga2350 \
|
||||
pimoroni_pico_plus2_rp2350 \
|
||||
pimoroni_picolipo_4mb \
|
||||
pimoroni_picolipo_16mb \
|
||||
pimoroni_picosystem \
|
||||
pimoroni_plasma2040 \
|
||||
pimoroni_plasma2350 \
|
||||
pimoroni_servo2040 \
|
||||
pimoroni_tiny2040 \
|
||||
pimoroni_tiny2040_2mb \
|
||||
pimoroni_tiny2350 \
|
||||
pololu_3pi_2040_robot \
|
||||
pololu_zumo_2040_robot \
|
||||
seeed_xiao_rp2040 \
|
||||
seeed_xiao_rp2350 \
|
||||
solderparty_rp2040_stamp \
|
||||
solderparty_rp2040_stamp_carrier \
|
||||
solderparty_rp2040_stamp_round_carrier \
|
||||
solderparty_rp2350_stamp_xl \
|
||||
solderparty_rp2350_stamp \
|
||||
sparkfun_micromod \
|
||||
sparkfun_promicro \
|
||||
sparkfun_promicro_rp2350 \
|
||||
sparkfun_thingplus \
|
||||
switchscience_picossci2_conta_base \
|
||||
switchscience_picossci2_dev_board \
|
||||
switchscience_picossci2_micro \
|
||||
switchscience_picossci2_rp2350_breakout \
|
||||
switchscience_picossci2_tiny \
|
||||
tinycircuits_thumby_color_rp2350 \
|
||||
vgaboard \
|
||||
waveshare_rp2040_lcd_0.96 \
|
||||
waveshare_rp2040_lcd_1.28 \
|
||||
@ -47,6 +89,10 @@ for board in adafruit_feather_rp2040 \
|
||||
waveshare_rp2040_plus_4mb \
|
||||
waveshare_rp2040_plus_16mb \
|
||||
waveshare_rp2040_zero \
|
||||
weact_studio_rp2040_2mb \
|
||||
weact_studio_rp2040_4mb \
|
||||
weact_studio_rp2040_8mb \
|
||||
weact_studio_rp2040_16mb \
|
||||
wiznet_w5100s_evb_pico
|
||||
do
|
||||
rm -rf *
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b945ae4f0ea203d079d723223864e9f17fedd6a5
|
||||
Subproject commit 75ab3ec70e93387cc16e9da9fd28874e1932d0c3
|
@ -1,13 +1,11 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
|
||||
|
||||
CONFIG_TINYUSB=y
|
||||
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
CONFIG_WL_SECTOR_MODE_PERF=y
|
||||
@ -30,7 +28,7 @@ CONFIG_MBEDTLS_TLS_DISABLED=y
|
||||
# CONFIG_ESP_WIFI_ENABLED is not set
|
||||
# CONFIG_ESP_WIFI_MBEDTLS_CRYPTO is not set
|
||||
# CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT is not set
|
||||
# CONFIG_WPA_MBEDTLS_CRYPTO is not set
|
||||
# CONFIG_ESP_WIFI_MBEDTLS_CRYPTO is not set
|
||||
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||
# CONFIG_MBEDTLS_KEY_EXCHANGE_RSA is not set
|
||||
# CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE is not set
|
||||
@ -45,8 +43,8 @@ CONFIG_MBEDTLS_TLS_DISABLED=y
|
||||
# CONFIG_MBEDTLS_SSL_ALPN is not set
|
||||
# CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS is not set
|
||||
# CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS is not set
|
||||
# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set
|
||||
# CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA is not set
|
||||
# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set
|
||||
# CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA is not set
|
||||
# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set
|
||||
# CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA is not set
|
||||
|
||||
|
@ -664,6 +664,7 @@ int cmd_cipher_sym() {
|
||||
secret[64] = { 0 };
|
||||
mbedtls_aes_init(&ctx);
|
||||
if (hd_keytype != 0x3) {
|
||||
mbedtls_ecdsa_free(&hd_context);
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
key_size = 32;
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
#include "sc_hsm.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include "hardware/rtc.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "pico/aon_timer.h"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
@ -45,24 +45,14 @@ int cmd_extras() {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
if (apdu.nc == 0) {
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
datetime_t dt;
|
||||
if (!rtc_get_datetime(&dt)) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
res_APDU[res_APDU_size++] = dt.year >> 8;
|
||||
res_APDU[res_APDU_size++] = dt.year & 0xff;
|
||||
res_APDU[res_APDU_size++] = dt.month;
|
||||
res_APDU[res_APDU_size++] = dt.day;
|
||||
res_APDU[res_APDU_size++] = dt.dotw;
|
||||
res_APDU[res_APDU_size++] = dt.hour;
|
||||
res_APDU[res_APDU_size++] = dt.min;
|
||||
res_APDU[res_APDU_size++] = dt.sec;
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv;
|
||||
aon_timer_get_time(&tv);
|
||||
#else
|
||||
struct timeval tv;
|
||||
struct tm *tm;
|
||||
gettimeofday(&tv, NULL);
|
||||
tm = localtime(&tv.tv_sec);
|
||||
#endif
|
||||
struct tm *tm = localtime(&tv.tv_sec);
|
||||
res_APDU[res_APDU_size++] = (tm->tm_year + 1900) >> 8;
|
||||
res_APDU[res_APDU_size++] = (tm->tm_year + 1900) & 0xff;
|
||||
res_APDU[res_APDU_size++] = tm->tm_mon;
|
||||
@ -71,27 +61,12 @@ int cmd_extras() {
|
||||
res_APDU[res_APDU_size++] = tm->tm_hour;
|
||||
res_APDU[res_APDU_size++] = tm->tm_min;
|
||||
res_APDU[res_APDU_size++] = tm->tm_sec;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (apdu.nc != 8) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
datetime_t dt;
|
||||
dt.year = (apdu.data[0] << 8) | (apdu.data[1]);
|
||||
dt.month = apdu.data[2];
|
||||
dt.day = apdu.data[3];
|
||||
dt.dotw = apdu.data[4];
|
||||
dt.hour = apdu.data[5];
|
||||
dt.min = apdu.data[6];
|
||||
dt.sec = apdu.data[7];
|
||||
if (!rtc_set_datetime(&dt)) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
#else
|
||||
struct tm tm;
|
||||
struct timeval tv;
|
||||
tm.tm_year = ((apdu.data[0] << 8) | (apdu.data[1])) - 1900;
|
||||
tm.tm_mon = apdu.data[2];
|
||||
tm.tm_mday = apdu.data[3];
|
||||
@ -99,7 +74,12 @@ int cmd_extras() {
|
||||
tm.tm_hour = apdu.data[5];
|
||||
tm.tm_min = apdu.data[6];
|
||||
tm.tm_sec = apdu.data[7];
|
||||
tv.tv_sec = mktime(&tm);
|
||||
time_t tv_sec = mktime(&tm);
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv = {.tv_sec = tv_sec, .tv_nsec = 0};
|
||||
aon_timer_set_time(&tv);
|
||||
#else
|
||||
struct timeval tv = {.tv_sec = tv_sec, .tv_usec = 0};
|
||||
settimeofday(&tv, NULL);
|
||||
#endif
|
||||
}
|
||||
@ -131,16 +111,9 @@ int cmd_extras() {
|
||||
mbedtls_ecdh_context hkey;
|
||||
mbedtls_ecdh_init(&hkey);
|
||||
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
|
||||
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp,
|
||||
&hkey.ctx.mbed_ecdh.d,
|
||||
&hkey.ctx.mbed_ecdh.Q,
|
||||
random_gen,
|
||||
NULL);
|
||||
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
|
||||
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
|
||||
ret = mbedtls_ecp_point_read_binary(&hkey.ctx.mbed_ecdh.grp,
|
||||
&hkey.ctx.mbed_ecdh.Qp,
|
||||
apdu.data,
|
||||
apdu.nc);
|
||||
ret = mbedtls_ecp_point_read_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Qp, apdu.data, apdu.nc);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecdh_free(&hkey);
|
||||
return SW_WRONG_DATA();
|
||||
@ -149,38 +122,20 @@ int cmd_extras() {
|
||||
|
||||
uint8_t buf[MBEDTLS_ECP_MAX_BYTES];
|
||||
size_t olen = 0;
|
||||
ret = mbedtls_ecdh_calc_secret(&hkey,
|
||||
&olen,
|
||||
buf,
|
||||
MBEDTLS_ECP_MAX_BYTES,
|
||||
random_gen,
|
||||
NULL);
|
||||
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecdh_free(&hkey);
|
||||
mbedtls_platform_zeroize(buf, sizeof(buf));
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
|
||||
NULL,
|
||||
0,
|
||||
buf,
|
||||
olen,
|
||||
mse.Qpt,
|
||||
sizeof(mse.Qpt),
|
||||
mse.key_enc,
|
||||
sizeof(mse.key_enc));
|
||||
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, buf, olen, mse.Qpt, sizeof(mse.Qpt), mse.key_enc, sizeof(mse.key_enc));
|
||||
mbedtls_platform_zeroize(buf, sizeof(buf));
|
||||
if (ret != 0) {
|
||||
mbedtls_ecdh_free(&hkey);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
||||
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp,
|
||||
&hkey.ctx.mbed_ecdh.Q,
|
||||
MBEDTLS_ECP_PF_UNCOMPRESSED,
|
||||
&olen,
|
||||
res_APDU,
|
||||
4096);
|
||||
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 4096);
|
||||
mbedtls_ecdh_free(&hkey);
|
||||
if (ret != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
|
@ -52,6 +52,9 @@ int cmd_key_domain() {
|
||||
if (tf_kd_size == 0) {
|
||||
return SW_WRONG_P1P2();
|
||||
}
|
||||
if (2 * p2 >= tf_kd_size) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
uint8_t *kdata = file_get_data(tf_kd), dkeks = kdata ? kdata[2 * p2] : 0,
|
||||
current_dkeks = kdata ? kdata[2 * p2 + 1] : 0;
|
||||
if (p1 == 0x0) { //dkek import
|
||||
@ -90,9 +93,6 @@ int cmd_key_domain() {
|
||||
}
|
||||
else {
|
||||
file_t *tf = search_file(EF_XKEK + p2);
|
||||
if (2 * p2 >= tf_kd_size) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
if (current_dkeks == 0xff && !file_has_data(tf)) { //XKEK have always 0xff
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
|
@ -291,11 +291,13 @@ int cmd_signature() {
|
||||
}
|
||||
else if (p2 == ALGO_HD) {
|
||||
size_t olen = 0;
|
||||
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN];
|
||||
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN] = {0};
|
||||
if (hd_context.grp.id == MBEDTLS_ECP_DP_NONE) {
|
||||
mbedtls_ecdsa_free(&hd_context);
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
}
|
||||
if (hd_keytype != 0x1 && hd_keytype != 0x2) {
|
||||
mbedtls_ecdsa_free(&hd_context);
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
md = MBEDTLS_MD_SHA256;
|
||||
|
@ -80,7 +80,8 @@ extern int cmd_bip_slip();
|
||||
|
||||
extern const uint8_t *ccid_atr;
|
||||
|
||||
int sc_hsm_select_aid(app_t *a) {
|
||||
int sc_hsm_select_aid(app_t *a, uint8_t force) {
|
||||
(void) force;
|
||||
a->process_apdu = sc_hsm_process_apdu;
|
||||
a->unload = sc_hsm_unload;
|
||||
init_sc_hsm();
|
||||
@ -271,8 +272,6 @@ uint16_t get_device_options() {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
extern uint32_t board_button_read(void);
|
||||
|
||||
bool wait_button_pressed() {
|
||||
uint32_t val = EV_PRESS_BUTTON;
|
||||
#ifndef ENABLE_EMULATION
|
||||
|
@ -18,7 +18,7 @@
|
||||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define HSM_VERSION 0x0400
|
||||
#define HSM_VERSION 0x0402
|
||||
|
||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||
|
@ -131,7 +131,7 @@ def parse_args():
|
||||
parser_keygen = subparser.add_parser('keygen', help='Generates private keypair or secret key.')
|
||||
subparser_keygen = parser_keygen.add_subparsers(title='commands', dest='subcommand', required=True)
|
||||
parser_keygen_aes = subparser_keygen.add_parser('aes', help='Generates an AES key.')
|
||||
parser_keygen_aes.add_argument('--size', help='Specifies the size of AES key [128, 192 or 256]',choices=[128, 192, 256], default=128)
|
||||
parser_keygen_aes.add_argument('--size', help='Specifies the size of AES key [128, 192 or 256]',choices=[128, 192, 256], default=128, type=int)
|
||||
parser_keygen_x25519 = subparser_keygen.add_parser('x25519', help='Generates a private X25519 keypair.')
|
||||
parser_keygen_x448 = subparser_keygen.add_parser('x448', help='Generates a private X448 keypair.')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user