mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'support/add_srp_salt_ver_gen_api_v5.2' into 'release/v5.2'
Generate Salt and verifier pair for given username and password (v5.2) See merge request espressif/esp-idf!27360
This commit is contained in:
commit
821d82f04e
@ -6,8 +6,9 @@ endif()
|
||||
|
||||
set(include_dirs include/common
|
||||
include/security
|
||||
include/transports)
|
||||
set(priv_include_dirs proto-c src/common src/crypto/srp6a/include)
|
||||
include/transports
|
||||
include/crypto/srp6a)
|
||||
set(priv_include_dirs proto-c src/common)
|
||||
set(srcs
|
||||
"src/common/protocomm.c"
|
||||
"proto-c/constants.pb-c.c"
|
||||
|
228
components/protocomm/include/crypto/srp6a/esp_srp.h
Normal file
228
components/protocomm/include/crypto/srp6a/esp_srp.h
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SRP-6a protocol implementation
|
||||
*
|
||||
* More information on protocol can be found: https://datatracker.ietf.org/doc/html/rfc5054
|
||||
*
|
||||
* This implementation is used by security2 of wifi_provisioning and local control features.
|
||||
* Details on how these protocols use this feature can be found here: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/provisioning/provisioning.html#security-2-scheme
|
||||
*
|
||||
* Below is the example usage of the srp6a protocol in protocomm component,
|
||||
* which can help understand the APIs better.
|
||||
*
|
||||
* Variables used:
|
||||
*
|
||||
* N, g: group parameters (prime and generator)
|
||||
* s: salt
|
||||
* B, b: server's public and private values
|
||||
* A, a: client's public and private values
|
||||
* I: user name (aka "identity")
|
||||
* P: password
|
||||
* v: verifier
|
||||
* k: SRP-6 multiplier
|
||||
*
|
||||
* salt (s) is random of given length, 16 in our case, which along with username and password
|
||||
* is used to generate verifier.
|
||||
*
|
||||
* x = SHA1(s | SHA1(I | ":" | P))
|
||||
* v = g^x % N
|
||||
*
|
||||
* Steps involved (From protocomm component usage):
|
||||
* Step1. Client Hello (PhoneApp):
|
||||
* a. Generate Key pair:
|
||||
* a (cli_privkey) = 256 bit random value,
|
||||
* A (cli_pubkey) = g^a.
|
||||
* g - generator, N - large safe prime, All arithmetic operations are performed in ring of integers modulo N,
|
||||
* thus all occurrences like y^z should be read as y^z modulo N.
|
||||
* b. SessionCmd0 (cli_pubkey, username I)
|
||||
*
|
||||
* Step2. Device(ESP):
|
||||
* a. Obtain Salt and verifier stored on ESP
|
||||
* Salt s = 256 bit random value,
|
||||
* Verifier v = g^× where x = H(s | I | P)
|
||||
* b. Generate Key Pair
|
||||
* b (dev_privkey) = 256 bit random value
|
||||
* B(dev_pubkey) = k*v + g^b where k = H(N, g)
|
||||
* c. Shared Key K = H(S) where,
|
||||
* S = (A * v^u) ^ b
|
||||
* u = H(A, B)
|
||||
* d. SessionResp0(dev_pubkey B, dev_random)
|
||||
*
|
||||
* Step3. Client (PhoneApp)
|
||||
* a. shared_key(K) = H(S) where,
|
||||
* S = (B - k*v) ^ (a + ux),
|
||||
* u = H(A, B),
|
||||
* k = H(N, g),
|
||||
* V = g^x,
|
||||
* x = H(s | I | P).
|
||||
* b. Verification token
|
||||
* client proof M = H[H(N) XOR H(g) | H(I) | S | A | B | K]
|
||||
* c. SessionCmd1(Client proof M1)
|
||||
*
|
||||
* Step4. Device (ESP):
|
||||
* a. Verify client:
|
||||
* device generates M1 = H[H(N) XOR H(g) | H(I) | S | A | B | K]
|
||||
* device verifies this M1 with the M1 obtained from Client
|
||||
* b. Verification token: Device generate device proof M2 = H(A, M, K)
|
||||
* c. Initialization Vector(IV):
|
||||
* dev_rand = gen_16byte_random) This random number is to be used for AES-GCM operation
|
||||
* for encryption and decryption of the data using the shared secret
|
||||
* d. SessionResp1 (DeviceProofM2, dev_rand)
|
||||
*
|
||||
* Step5. Client (PhoneApp)
|
||||
* a. Verify Device
|
||||
* Client calculates device proof M2 as M2 = H(A, M, K)
|
||||
* verifies this M2 with M2 obtained from device
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Large prime+generator to be used for the algorithm
|
||||
*/
|
||||
typedef enum {
|
||||
/* SRP specific:
|
||||
* N = 3072 bit large safe prime,
|
||||
* g = generator */
|
||||
ESP_NG_3072 = 0,
|
||||
} esp_ng_type_t;
|
||||
|
||||
typedef struct esp_srp_handle esp_srp_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize srp context for given NG type
|
||||
*
|
||||
* @param ng NG type given by `esp_ng_type_t`
|
||||
* @return esp_srp_handle_t* srp handle
|
||||
*
|
||||
* @note the handle gets freed with `esp_srp_free`
|
||||
*/
|
||||
esp_srp_handle_t *esp_srp_init(esp_ng_type_t ng);
|
||||
|
||||
/**
|
||||
* @brief free esp_srp_context
|
||||
*
|
||||
* @param hd handle to be free
|
||||
*/
|
||||
void esp_srp_free(esp_srp_handle_t *hd);
|
||||
|
||||
/**
|
||||
* @brief Returns B (pub key) and salt. [Step2.b]
|
||||
*
|
||||
* @param hd esp_srp handle
|
||||
* @param username Username not expected NULL terminated
|
||||
* @param username_len Username length
|
||||
* @param pass Password not expected to be NULL terminated
|
||||
* @param pass_len Pasword length
|
||||
* @param salt_len Salt length
|
||||
* @param bytes_B Public Key returned
|
||||
* @param len_B Length of the public key
|
||||
* @param bytes_salt Salt bytes generated
|
||||
* @return esp_err_t ESP_OK on success, appropriate error otherwise
|
||||
*
|
||||
* @note *bytes_B MUST NOT BE FREED BY THE CALLER
|
||||
* @note *bytes_salt MUST NOT BE FREE BY THE CALLER
|
||||
*/
|
||||
esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len,
|
||||
const char *pass, int pass_len, int salt_len,
|
||||
char **bytes_B, int *len_B, char **bytes_salt);
|
||||
|
||||
/**
|
||||
* @brief Generate salt-verifier pair, given username, password and salt length
|
||||
*
|
||||
* @param[in] username username
|
||||
* @param[in] username_len length of the username
|
||||
* @param[in] pass password
|
||||
* @param[in] pass_len length of the password
|
||||
* @param[out] bytes_salt generated salt on successful generation, or NULL
|
||||
* @param[in] salt_len salt length
|
||||
* @param[out] verifier generated verifier on successful generation, or NULL
|
||||
* @param[out] verifier_len length of the generated verifier
|
||||
* @return esp_err_t ESP_OK on success, appropriate error otherwise
|
||||
*
|
||||
* @note if API has returned ESP_OK, salt and verifier generated need to be freed by caller
|
||||
* @note Usually, username and password are not saved on the device. Rather salt and verifier are
|
||||
* generated outside the device and are embedded.
|
||||
* this covenience API can be used to generate salt and verifier on the fly for development use case.
|
||||
* OR for devices which intentionally want to generate different password each time and can send it
|
||||
* to the client securely. e.g., a device has a display and it shows the pin
|
||||
*/
|
||||
esp_err_t esp_srp_gen_salt_verifier(const char *username, int username_len,
|
||||
const char *pass, int pass_len,
|
||||
char **bytes_salt, int salt_len,
|
||||
char **verifier, int *verifier_len);
|
||||
|
||||
/**
|
||||
* @brief Set the Salt and Verifier pre-generated for a given password.
|
||||
* This should be used only if the actual password is not available.
|
||||
* The public key can then be generated using esp_srp_srv_pubkey_from_salt_verifier()
|
||||
* and not esp_srp_srv_pubkey()
|
||||
*
|
||||
* @param hd esp_srp_handle
|
||||
* @param salt pre-generated salt bytes
|
||||
* @param salt_len length of the salt bytes
|
||||
* @param verifier pre-generated verifier
|
||||
* @param verifier_len length of the verifier bytes
|
||||
* @return esp_err_t ESP_OK on success, appropriate error otherwise
|
||||
*/
|
||||
esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len,
|
||||
const char *verifier, int verifier_len);
|
||||
|
||||
/**
|
||||
* @brief Returns B (pub key)[Step2.b] when the salt and verifier are set using esp_srp_set_salt_verifier()
|
||||
*
|
||||
* @param hd esp_srp handle
|
||||
* @param bytes_B Key returned to the called
|
||||
* @param len_B Length of the key returned
|
||||
* @return esp_err_t ESP_OK on success, appropriate error otherwise
|
||||
*
|
||||
* @note *bytes_B MUST NOT BE FREED BY THE CALLER
|
||||
*/
|
||||
esp_err_t esp_srp_srv_pubkey_from_salt_verifier(esp_srp_handle_t *hd, char **bytes_B, int *len_B);
|
||||
|
||||
/**
|
||||
* @brief Get session key in `*bytes_key` given by len in `*len_key`. [Step2.c].
|
||||
*
|
||||
* This calculated session key is used for further communication given the proofs are
|
||||
* exchanged/authenticated with `esp_srp_exchange_proofs`
|
||||
*
|
||||
* @param hd esp_srp handle
|
||||
* @param bytes_A Private Key
|
||||
* @param len_A Private Key length
|
||||
* @param bytes_key Key returned to the caller
|
||||
* @param len_key length of the key in *bytes_key
|
||||
* @return esp_err_t ESP_OK on success, appropriate error otherwise
|
||||
*
|
||||
* @note *bytes_key MUST NOT BE FREED BY THE CALLER
|
||||
*/
|
||||
esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, uint16_t *len_key);
|
||||
|
||||
/**
|
||||
* @brief Complete the authentication. If this step fails, the session_key exchanged should not be used
|
||||
*
|
||||
* This is the final authentication step in SRP algorithm [Step4.1, Step4.b, Step4.c]
|
||||
*
|
||||
* @param hd esp_srp handle
|
||||
* @param username Username not expected NULL terminated
|
||||
* @param username_len Username length
|
||||
* @param bytes_user_proof param in
|
||||
* @param bytes_host_proof parameter out (should be SHA512_DIGEST_LENGTH) bytes in size
|
||||
* @return esp_err_t ESP_OK if user's proof is ok and subsequently bytes_host_proof is populated with our own proof.
|
||||
*/
|
||||
esp_err_t esp_srp_exchange_proofs(esp_srp_handle_t *hd, char *username, uint16_t username_len,
|
||||
char *bytes_user_proof, char *bytes_host_proof);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -17,6 +17,44 @@
|
||||
|
||||
static const char *TAG = "srp6a";
|
||||
|
||||
typedef struct esp_srp_handle {
|
||||
esp_ng_type_t type;
|
||||
esp_mpi_ctx_t *ctx;
|
||||
|
||||
/* N
|
||||
* the bytes_n simply points to the static array
|
||||
*/
|
||||
esp_mpi_t *n;
|
||||
const char *bytes_n;
|
||||
int len_n;
|
||||
|
||||
/* g
|
||||
* the bytes_g simply points to the static array
|
||||
*/
|
||||
esp_mpi_t *g;
|
||||
const char *bytes_g;
|
||||
int len_g;
|
||||
|
||||
/* Salt */
|
||||
esp_mpi_t *s;
|
||||
char *bytes_s;
|
||||
int len_s;
|
||||
/* Verifier */
|
||||
esp_mpi_t *v;
|
||||
/* B */
|
||||
esp_mpi_t *B;
|
||||
char *bytes_B;
|
||||
int len_B;
|
||||
/* b */
|
||||
esp_mpi_t *b;
|
||||
/* A */
|
||||
esp_mpi_t *A;
|
||||
char *bytes_A;
|
||||
int len_A;
|
||||
/* K - session key*/
|
||||
char *session_key;
|
||||
} esp_srp_handle;
|
||||
|
||||
static void hexdump_mpi(const char *name, esp_mpi_t *bn)
|
||||
{
|
||||
int len = 0;
|
||||
@ -59,15 +97,13 @@ static const char N_3072[] = {
|
||||
static const char g_3072[] = { 5 };
|
||||
|
||||
|
||||
esp_err_t esp_srp_init(esp_srp_handle_t *hd, esp_ng_type_t ng)
|
||||
esp_srp_handle_t *esp_srp_init(esp_ng_type_t ng)
|
||||
{
|
||||
if (hd->allocated) {
|
||||
esp_srp_free(hd);
|
||||
esp_srp_handle_t *hd = calloc(1, sizeof(esp_srp_handle));
|
||||
if (!hd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(hd, 0, sizeof(*hd));
|
||||
hd->allocated = 1;
|
||||
|
||||
hd->ctx = esp_mpi_ctx_new();
|
||||
if (! hd->ctx) {
|
||||
goto error;
|
||||
@ -90,18 +126,17 @@ esp_err_t esp_srp_init(esp_srp_handle_t *hd, esp_ng_type_t ng)
|
||||
goto error;
|
||||
}
|
||||
hd->type = ng;
|
||||
return ESP_OK;
|
||||
return hd;
|
||||
error:
|
||||
esp_srp_free(hd);
|
||||
return ESP_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void esp_srp_free(esp_srp_handle_t *hd)
|
||||
{
|
||||
if (hd->allocated != 1) {
|
||||
if (!hd) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hd->ctx) {
|
||||
esp_mpi_ctx_free(hd->ctx);
|
||||
}
|
||||
@ -138,7 +173,7 @@ void esp_srp_free(esp_srp_handle_t *hd)
|
||||
if (hd->session_key) {
|
||||
free(hd->session_key);
|
||||
}
|
||||
memset(hd, 0, sizeof(*hd));
|
||||
free(hd);
|
||||
}
|
||||
|
||||
static esp_mpi_t *calculate_x(char *bytes_salt, int salt_len, const char *username, int username_len, const char *pass, int pass_len)
|
||||
@ -223,7 +258,7 @@ static esp_mpi_t *calculate_u(esp_srp_handle_t *hd, char *A, int len_A)
|
||||
return calculate_padded_hash(hd, A, len_A, hd->bytes_B, hd->len_B);
|
||||
}
|
||||
|
||||
esp_err_t __esp_srp_srv_pubkey(esp_srp_handle_t *hd, char **bytes_B, int *len_B)
|
||||
static esp_err_t __esp_srp_srv_pubkey(esp_srp_handle_t *hd, char **bytes_B, int *len_B)
|
||||
{
|
||||
esp_mpi_t *k = calculate_k(hd);
|
||||
esp_mpi_t *kv = NULL;
|
||||
@ -279,47 +314,46 @@ error:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len, const char *pass, int pass_len, int salt_len,
|
||||
char **bytes_B, int *len_B, char **bytes_salt)
|
||||
static esp_err_t _esp_srp_gen_salt_verifier(esp_srp_handle_t *hd, const char *username, int username_len,
|
||||
const char *pass, int pass_len, int salt_len)
|
||||
{
|
||||
/* Get Salt */
|
||||
int str_salt_len;
|
||||
esp_mpi_t *x = NULL;
|
||||
hd->s = esp_mpi_new();
|
||||
if (! hd->s) {
|
||||
if (!hd->s) {
|
||||
ESP_LOGE(TAG, "Failed to allocate bignum s");
|
||||
goto error;
|
||||
}
|
||||
|
||||
esp_mpi_get_rand(hd->s, 8 * salt_len, -1, 0);
|
||||
*bytes_salt = esp_mpi_to_bin(hd->s, &str_salt_len);
|
||||
if (! *bytes_salt) {
|
||||
hd->bytes_s = esp_mpi_to_bin(hd->s, &str_salt_len);
|
||||
if (!hd->bytes_s) {
|
||||
ESP_LOGE(TAG, "Failed to generate salt of len %d", salt_len);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hd->bytes_s = *bytes_salt;
|
||||
hd->len_s = salt_len;
|
||||
ESP_LOGD(TAG, "Salt ->");
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(TAG, *bytes_salt, str_salt_len, ESP_LOG_DEBUG);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(TAG, hd->bytes_s, str_salt_len, ESP_LOG_DEBUG);
|
||||
|
||||
/* Calculate X which is simply a hash for all these things */
|
||||
x = calculate_x(*bytes_salt, str_salt_len, username, username_len, pass, pass_len);
|
||||
if (! x) {
|
||||
x = calculate_x(hd->bytes_s, str_salt_len, username, username_len, pass, pass_len);
|
||||
if (!x) {
|
||||
ESP_LOGE(TAG, "Failed to calculate x");
|
||||
goto error;
|
||||
}
|
||||
hexdump_mpi("x", x);
|
||||
|
||||
/* v = g^x % N */
|
||||
hd->v = esp_mpi_new();
|
||||
if (! hd->v) {
|
||||
if (!hd->v) {
|
||||
ESP_LOGE(TAG, "Failed to allocate bignum v");
|
||||
goto error;
|
||||
}
|
||||
esp_mpi_a_exp_b_mod_c(hd->v, hd->g, x, hd->n, hd->ctx);
|
||||
hexdump_mpi("Verifier", hd->v);
|
||||
|
||||
if (__esp_srp_srv_pubkey(hd, bytes_B, len_B) < 0 ) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
esp_mpi_free(x);
|
||||
return ESP_OK;
|
||||
|
||||
@ -328,9 +362,8 @@ error:
|
||||
esp_mpi_free(hd->s);
|
||||
hd->s = NULL;
|
||||
}
|
||||
if (*bytes_salt) {
|
||||
free(*bytes_salt);
|
||||
*bytes_salt = NULL;
|
||||
if (hd->bytes_s) {
|
||||
free(hd->bytes_s);
|
||||
hd->bytes_s = NULL;
|
||||
hd->len_s = 0;
|
||||
}
|
||||
@ -345,11 +378,86 @@ error:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len,
|
||||
const char *pass, int pass_len, int salt_len,
|
||||
char **bytes_B, int *len_B, char **bytes_salt)
|
||||
{
|
||||
if (!hd || !username || !pass) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (ESP_OK != _esp_srp_gen_salt_verifier(hd, username, username_len, pass, pass_len, salt_len)) {
|
||||
goto error;
|
||||
}
|
||||
*bytes_salt = hd->bytes_s;
|
||||
|
||||
if (__esp_srp_srv_pubkey(hd, bytes_B, len_B) < 0 ) {
|
||||
goto error;
|
||||
}
|
||||
return ESP_OK;
|
||||
|
||||
error:
|
||||
if (hd->s) {
|
||||
esp_mpi_free(hd->s);
|
||||
hd->s = NULL;
|
||||
}
|
||||
if (*bytes_salt) {
|
||||
free(*bytes_salt);
|
||||
*bytes_salt = NULL;
|
||||
hd->bytes_s = NULL;
|
||||
hd->len_s = 0;
|
||||
}
|
||||
if (hd->v) {
|
||||
esp_mpi_free(hd->v);
|
||||
hd->v = NULL;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_srp_srv_pubkey_from_salt_verifier(esp_srp_handle_t *hd, char **bytes_B, int *len_B)
|
||||
{
|
||||
if (!hd || !bytes_B || !len_B) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return __esp_srp_srv_pubkey(hd, bytes_B, len_B);
|
||||
}
|
||||
|
||||
/* Generate salt-verifier pair for given username and password */
|
||||
esp_err_t esp_srp_gen_salt_verifier(const char *username, int username_len,
|
||||
const char *pass, int pass_len,
|
||||
char **bytes_salt, int salt_len,
|
||||
char **verifier, int *verifier_len)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
|
||||
/* allocate and init temporary SRP handle */
|
||||
esp_srp_handle_t *srp_hd = esp_srp_init(ESP_NG_3072);
|
||||
if (!srp_hd) {
|
||||
ESP_LOGE(TAG, "Failed to initialise security context!");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// get salt and verifier
|
||||
if (ESP_OK != _esp_srp_gen_salt_verifier(srp_hd, username, username_len, pass, pass_len, salt_len)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// convert to verifier bytes
|
||||
*verifier = esp_mpi_to_bin(srp_hd->v, verifier_len);
|
||||
if (!*verifier) {
|
||||
ESP_LOGE(TAG, "Failed to allocate verifier bytes!");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*bytes_salt = srp_hd->bytes_s;
|
||||
srp_hd->bytes_s = NULL; // so that it won't be freed in `esp_srp_free` step
|
||||
ret = ESP_OK;
|
||||
|
||||
cleanup:
|
||||
esp_srp_free(srp_hd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len,
|
||||
const char *verifier, int verifier_len)
|
||||
{
|
||||
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_srp_mpi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
/* SRP specific:
|
||||
* N = 3072 bit large safe prime,
|
||||
* g = generator */
|
||||
ESP_NG_3072 = 0,
|
||||
} esp_ng_type_t;
|
||||
|
||||
typedef struct esp_srp_handle {
|
||||
int allocated;
|
||||
esp_ng_type_t type;
|
||||
esp_mpi_ctx_t *ctx;
|
||||
|
||||
/* N
|
||||
* the bytes_n simply points to the static array
|
||||
*/
|
||||
esp_mpi_t *n;
|
||||
const char *bytes_n;
|
||||
int len_n;
|
||||
|
||||
/* g
|
||||
* the bytes_g simply points to the static array
|
||||
*/
|
||||
esp_mpi_t *g;
|
||||
const char *bytes_g;
|
||||
int len_g;
|
||||
|
||||
/* Salt */
|
||||
esp_mpi_t *s;
|
||||
char *bytes_s;
|
||||
int len_s;
|
||||
/* Verifier */
|
||||
esp_mpi_t *v;
|
||||
/* B */
|
||||
esp_mpi_t *B;
|
||||
char *bytes_B;
|
||||
int len_B;
|
||||
/* b */
|
||||
esp_mpi_t *b;
|
||||
/* A */
|
||||
esp_mpi_t *A;
|
||||
char *bytes_A;
|
||||
int len_A;
|
||||
/* K - session key*/
|
||||
char *session_key;
|
||||
} esp_srp_handle_t;
|
||||
|
||||
int esp_srp_init(esp_srp_handle_t *hd, esp_ng_type_t ng);
|
||||
|
||||
void esp_srp_free(esp_srp_handle_t *hd);
|
||||
|
||||
/* Returns B (pub key) and salt
|
||||
*
|
||||
* *bytes_B MUST NOT BE FREED BY THE CALLER
|
||||
* *bytes_salt MUST NOT BE FREE BY THE CALLER
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len, const char *pass, int pass_len, int salt_len,
|
||||
char **bytes_B, int *len_B, char **bytes_salt);
|
||||
|
||||
/* Set the Salt and Verifier pre-generated for a given password.
|
||||
* This should be used only if the actual password is not available.
|
||||
* The public key can then be generated using esp_srp_srv_pubkey_from_salt_verifier()
|
||||
* and not esp_srp_srv_pubkey()
|
||||
*/
|
||||
esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len,
|
||||
const char *verifier, int verifier_len);
|
||||
|
||||
/* Returns B (pub key) when the salt and verifier are set using esp_srp_set_salt_verifier()
|
||||
*
|
||||
* *bytes_B MUST NOT BE FREED BY THE CALLER
|
||||
*/
|
||||
esp_err_t esp_srp_srv_pubkey_from_salt_verifier(esp_srp_handle_t *hd, char **bytes_B, int *len_B);
|
||||
|
||||
/* Returns bytes_key
|
||||
* *bytes_key MUST NOT BE FREED BY THE CALLER
|
||||
*/
|
||||
esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, uint16_t *len_key);
|
||||
|
||||
/* Exchange proofs
|
||||
* Returns 1 if user's proof is ok. Also 1 when is returned, bytes_host_proof contains our proof.
|
||||
*
|
||||
* bytes_user_proof is parameter in
|
||||
* bytes_host_proof is parameter out (should be SHA512_DIGEST_LENGTH) bytes in size
|
||||
*/
|
||||
esp_err_t esp_srp_exchange_proofs(esp_srp_handle_t *hd, char *username, uint16_t username_len, char *bytes_user_proof, char *bytes_host_proof);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -109,15 +109,9 @@ static esp_err_t handle_session_command0(session_t *cur_session,
|
||||
hexdump("Client Public Key", (char *) in->sc0->client_pubkey.data, PUBLIC_KEY_LEN);
|
||||
|
||||
/* Initialize mu srp context */
|
||||
cur_session->srp_hd = calloc(1, sizeof(esp_srp_handle_t));
|
||||
if (!cur_session->srp_hd) {
|
||||
ESP_LOGE(TAG, "Failed to allocate security context!");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (esp_srp_init(cur_session->srp_hd, ESP_NG_3072) != ESP_OK) {
|
||||
cur_session->srp_hd = esp_srp_init(ESP_NG_3072);
|
||||
if (cur_session->srp_hd == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialise security context!");
|
||||
free(cur_session->srp_hd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@ -131,14 +125,15 @@ static esp_err_t handle_session_command0(session_t *cur_session,
|
||||
ESP_LOGI(TAG, "Using salt and verifier to generate public key...");
|
||||
|
||||
if (sv->salt != NULL && sv->salt_len != 0 && sv->verifier != NULL && sv->verifier_len != 0) {
|
||||
if (esp_srp_set_salt_verifier(cur_session->srp_hd, cur_session->salt, cur_session->salt_len, cur_session->verifier, cur_session->verifier_len) != ESP_OK) {
|
||||
if (esp_srp_set_salt_verifier(cur_session->srp_hd, cur_session->salt,
|
||||
cur_session->salt_len, cur_session->verifier, cur_session->verifier_len) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set salt and verifier!");
|
||||
free(cur_session->srp_hd);
|
||||
esp_srp_free(cur_session->srp_hd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (esp_srp_srv_pubkey_from_salt_verifier(cur_session->srp_hd, &device_pubkey, &device_pubkey_len) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to device public key!");
|
||||
free(cur_session->srp_hd);
|
||||
esp_srp_free(cur_session->srp_hd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
@ -147,7 +142,7 @@ static esp_err_t handle_session_command0(session_t *cur_session,
|
||||
if (esp_srp_get_session_key(cur_session->srp_hd, (char *) in->sc0->client_pubkey.data, PUBLIC_KEY_LEN,
|
||||
&cur_session->session_key, &cur_session->session_key_len) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate device session key!");
|
||||
free(cur_session->srp_hd);
|
||||
esp_srp_free(cur_session->srp_hd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
hexdump("Session Key", cur_session->session_key, cur_session->session_key_len);
|
||||
@ -156,7 +151,7 @@ static esp_err_t handle_session_command0(session_t *cur_session,
|
||||
S2SessionResp0 *out_resp = (S2SessionResp0 *) malloc(sizeof(S2SessionResp0));
|
||||
if (!out || !out_resp) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for response0");
|
||||
free(cur_session->srp_hd);
|
||||
esp_srp_free(cur_session->srp_hd);
|
||||
free(out);
|
||||
free(out_resp);
|
||||
return ESP_ERR_NO_MEM;
|
||||
@ -185,7 +180,7 @@ static esp_err_t handle_session_command0(session_t *cur_session,
|
||||
cur_session->username = malloc(cur_session->username_len);
|
||||
if (!cur_session->username) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory!");
|
||||
free(cur_session->srp_hd);
|
||||
esp_srp_free(cur_session->srp_hd);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(cur_session->username, in->sc0->client_username.data, in->sc0->client_username.len);
|
||||
@ -365,7 +360,6 @@ static esp_err_t sec2_close_session(protocomm_security_handle_t handle, uint32_t
|
||||
|
||||
if (cur_session->srp_hd) {
|
||||
esp_srp_free(cur_session->srp_hd);
|
||||
free(cur_session->srp_hd);
|
||||
}
|
||||
|
||||
memset(cur_session, 0, sizeof(session_t));
|
||||
|
@ -274,9 +274,11 @@ INPUT = \
|
||||
$(PROJECT_PATH)/components/protocomm/include/security/protocomm_security.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/security/protocomm_security0.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/security/protocomm_security1.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/security/protocomm_security2.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/transports/protocomm_ble.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/transports/protocomm_console.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/transports/protocomm_httpd.h \
|
||||
$(PROJECT_PATH)/components/protocomm/include/crypto/srp6a/esp_srp.h \
|
||||
$(PROJECT_PATH)/components/pthread/include/esp_pthread.h \
|
||||
$(PROJECT_PATH)/components/sdmmc/include/sdmmc_cmd.h \
|
||||
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/adc_channel.h \
|
||||
|
@ -43,7 +43,7 @@ The protocomm component provides a project configuration menu to enable/disable
|
||||
* Support ``protocomm_security2`` with SRP6a-based key exchange + AES-GCM encryption/decryption: :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
Enabling multiple security versions at once offers the ability to control them dynamically but also increases the firmware size.
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
@ -299,5 +299,7 @@ API Reference
|
||||
.. include-build-file:: inc/protocomm_security.inc
|
||||
.. include-build-file:: inc/protocomm_security0.inc
|
||||
.. include-build-file:: inc/protocomm_security1.inc
|
||||
.. include-build-file:: inc/protocomm_security2.inc
|
||||
.. include-build-file:: inc/esp_srp.inc
|
||||
.. include-build-file:: inc/protocomm_httpd.inc
|
||||
.. include-build-file:: inc/protocomm_ble.inc
|
||||
|
@ -40,10 +40,10 @@ Protocomm 为以下各种传输提供框架:
|
||||
|
||||
* 支持 ``protocomm_security0``,该版本无安全功能::ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0`,该选项默认启用。
|
||||
* 支持 ``protocomm_security1``,使用 Curve25519 密钥交换和 AES-CTR 加密/解密::ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1`,该选项默认启用。
|
||||
* 支持 ``protocomm_security2``,使用基于 SRP6a 的密钥交换和 AES-GCM 加密/解密::ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2`。
|
||||
* 支持 ``protocomm_security2``,使用基于 SRP6a 的密钥交换和 AES-GCM 加密/解密::ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2`。
|
||||
|
||||
.. note::
|
||||
|
||||
.. note::
|
||||
|
||||
启用多个安全版本后可以动态控制安全版本,但也会增加固件大小。
|
||||
|
||||
.. only:: SOC_WIFI_SUPPORTED
|
||||
@ -241,7 +241,7 @@ Protocomm 为以下各种传输提供框架:
|
||||
|
||||
使用 Security 0 的低功耗蓝牙传输方案示例
|
||||
-------------------------------------------
|
||||
|
||||
|
||||
示例用法请参阅 :component_file:`wifi_provisioning/src/scheme_ble.c`。
|
||||
|
||||
.. highlight:: c
|
||||
@ -299,5 +299,7 @@ API 参考
|
||||
.. include-build-file:: inc/protocomm_security.inc
|
||||
.. include-build-file:: inc/protocomm_security0.inc
|
||||
.. include-build-file:: inc/protocomm_security1.inc
|
||||
.. include-build-file:: inc/protocomm_security2.inc
|
||||
.. include-build-file:: inc/esp_srp.inc
|
||||
.. include-build-file:: inc/protocomm_httpd.inc
|
||||
.. include-build-file:: inc/protocomm_ble.inc
|
||||
|
Loading…
Reference in New Issue
Block a user