From 82e930c4b2128f2b9f9728ce6b20366ce7f85bae Mon Sep 17 00:00:00 2001 From: eeff <33566201+eeff@users.noreply.github.com> Date: Thu, 30 May 2024 19:23:46 +0800 Subject: [PATCH] feat(restful): user password must be encrypted --- include/neuron/errcodes.h | 1 + plugins/restful/normal_handle.c | 43 +++++++++------- plugins/restful/user.c | 88 +++++++++++++++++++++++++++++++++ plugins/restful/user.h | 2 + src/utils/base64.c | 8 ++- src/utils/http.c | 1 + 6 files changed, 123 insertions(+), 20 deletions(-) diff --git a/include/neuron/errcodes.h b/include/neuron/errcodes.h index 46f0ad22..51c7f199 100644 --- a/include/neuron/errcodes.h +++ b/include/neuron/errcodes.h @@ -49,6 +49,7 @@ typedef enum { NEU_ERR_IP_ADDRESS_IN_USE = 1016, NEU_ERR_WEAK_PASSWORD_ALPHABET = 1017, NEU_ERR_WEAK_PASSWORD_PATTERN = 1018, + NEU_ERR_DECRYPT_PASSWORD_FAILED = 1019, NEU_ERR_NODE_EXIST = 2002, NEU_ERR_NODE_NOT_EXIST = 2003, diff --git a/plugins/restful/normal_handle.c b/plugins/restful/normal_handle.c index 52fb800a..721b6699 100644 --- a/plugins/restful/normal_handle.c +++ b/plugins/restful/normal_handle.c @@ -53,23 +53,20 @@ void handle_login(nng_aio *aio) NEU_PROCESS_HTTP_REQUEST( aio, neu_json_login_req_t, neu_json_decode_login_req, { neu_json_login_resp_t login_resp = { 0 }; - neu_user_t * user = neu_load_user(req->name); - int pass_len = strlen(req->pass); + neu_user_t * user = NULL; + char *password = neu_decrypt_user_password(req->pass); - if (NULL == user) { + if (NULL == password) { + nlog_error("could not decrypt user `%s` password", req->name); + NEU_JSON_RESPONSE_ERROR(NEU_ERR_DECRYPT_PASSWORD_FAILED, { + neu_http_response(aio, error_code.error, result_error); + }); + } else if (NULL == (user = neu_load_user(req->name))) { nlog_error("could not find user `%s`", req->name); NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, { neu_http_response(aio, error_code.error, result_error); }); - } else if (pass_len < NEU_USER_PASSWORD_MIN_LEN || - pass_len > NEU_USER_PASSWORD_MAX_LEN) { - nlog_error("user `%s` password too short or too long", - req->name); - NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, { - neu_http_response(aio, error_code.error, result_error); - }); - } else if (neu_user_check_password(user, req->pass)) { - + } else if (neu_user_check_password(user, password)) { char *token = NULL; char *result = NULL; @@ -95,6 +92,7 @@ void handle_login(nng_aio *aio) }); } + free(password); neu_user_free(user); }) } @@ -105,21 +103,28 @@ void handle_password(nng_aio *aio) aio, neu_json_password_req_t, neu_json_decode_password_req, { neu_user_t *user = NULL; int rv = 0; - int pass_len = strlen(req->new_pass); + char * new_pass = neu_decrypt_user_password(req->new_pass); + char * old_pass = neu_decrypt_user_password(req->old_pass); + int pass_len = new_pass ? strlen(new_pass) : 0; - if (pass_len < NEU_USER_PASSWORD_MIN_LEN || - pass_len > NEU_USER_PASSWORD_MAX_LEN) { + if (NULL == new_pass) { + nlog_error("could not decrypt user `%s` new pass", req->name); + rv = NEU_ERR_DECRYPT_PASSWORD_FAILED; + } else if (NULL == old_pass) { + nlog_error("could not decrypt user `%s` old pass", req->name); + rv = NEU_ERR_DECRYPT_PASSWORD_FAILED; + } else if (pass_len < NEU_USER_PASSWORD_MIN_LEN || + pass_len > NEU_USER_PASSWORD_MAX_LEN) { nlog_error("user `%s` new password too short or too long", req->name); rv = NEU_ERR_INVALID_PASSWORD_LEN; } else if (NULL == (user = neu_load_user(req->name))) { nlog_error("could not find user `%s`", req->name); rv = NEU_ERR_INVALID_USER_OR_PASSWORD; - } else if (!neu_user_check_password(user, req->old_pass)) { + } else if (!neu_user_check_password(user, old_pass)) { nlog_error("user `%s` password check fail", req->name); rv = NEU_ERR_INVALID_USER_OR_PASSWORD; - } else if (0 != - (rv = neu_user_update_password(user, req->new_pass))) { + } else if (0 != (rv = neu_user_update_password(user, new_pass))) { nlog_error("user `%s` update password fail", req->name); } else if (0 != (rv = neu_save_user(user))) { nlog_error("user `%s` persist fail", req->name); @@ -129,6 +134,8 @@ void handle_password(nng_aio *aio) neu_http_response(aio, error_code.error, result_error); }); + free(new_pass); + free(old_pass); neu_user_free(user); }) } diff --git a/plugins/restful/user.c b/plugins/restful/user.c index d2485e60..4490cd0f 100644 --- a/plugins/restful/user.c +++ b/plugins/restful/user.c @@ -11,6 +11,7 @@ #include "errcodes.h" #include "user.h" +#include "utils/base64.h" #include "utils/log.h" static const unsigned char cov_2char[64] = { @@ -438,6 +439,93 @@ static inline int checkout_password_strength(const char *password) return 0; } +static inline EVP_CIPHER_CTX *aes_ctx_new() +{ + int ret = 0; + unsigned char key[32] = { 90, 45, 54, 10, 182, 19, 52, 130, + 109, 151, 202, 252, 248, 177, 136, 35, + 234, 204, 188, 2, 72, 215, 207, 52, + 22, 5, 193, 52, 228, 224, 157, 28 }; + unsigned char iv[16] = { 239, 227, 132, 238, 4, 225, 127, 67, + 202, 77, 31, 79, 203, 70, 149, 132 }; + + EVP_CIPHER_CTX *e = EVP_CIPHER_CTX_new(); + if (NULL == e) { + return NULL; + } + + EVP_CIPHER_CTX_init(e); + + ret = EVP_DecryptInit_ex(e, EVP_aes_256_cbc(), NULL, key, iv); + if (0 == ret) { + EVP_CIPHER_CTX_free(e); + return NULL; + } + + return e; +} + +static char *aes_decrypt(unsigned char *cipher_text, int *len) +{ + char *plain_text = NULL; + int plain_text_len = *len + EVP_CIPHER_block_size(EVP_aes_256_cbc()); + int f_len = 0; + int ret = 0; + + EVP_CIPHER_CTX *ctx = aes_ctx_new(); + if (NULL == ctx) { + nlog_warn("alloc ctx fail"); + return NULL; + } + + plain_text = calloc(1, plain_text_len + 1); + if (NULL == plain_text) { + nlog_warn("alloc plain_text fail"); + return NULL; + } + + ret = EVP_DecryptUpdate(ctx, (unsigned char *) plain_text, &plain_text_len, + (unsigned char *) cipher_text, *len); + if (ret <= 0) { + free(plain_text); + EVP_CIPHER_CTX_free(ctx); + nlog_warn("decrypt update error: %d", ret); + return NULL; + } + + ret = EVP_DecryptFinal_ex( + ctx, (unsigned char *) plain_text + plain_text_len, &f_len); + if (ret <= 0) { + free(plain_text); + EVP_CIPHER_CTX_free(ctx); + nlog_warn("decrypt final error: %d", ret); + return NULL; + } + + *len = plain_text_len + f_len; + EVP_CIPHER_CTX_free(ctx); + + return plain_text; +} + +char *neu_decrypt_user_password(const char *crypted_password) +{ + int len = 0; + char * password = NULL; + unsigned char *cipher_text = neu_decode64(&len, crypted_password); + if (cipher_text && (password = aes_decrypt(cipher_text, &len))) { + password[len] = '\0'; + for (int i = 0; i < len; ++i) { + if ('\0' == password[i]) { + free(password); + password = NULL; + } + } + } + free(cipher_text); + return password; +} + neu_user_t *neu_user_new(const char *name, const char *password) { neu_user_t *user = malloc(sizeof(*user)); diff --git a/plugins/restful/user.h b/plugins/restful/user.h index 6d5ce233..8331b301 100644 --- a/plugins/restful/user.h +++ b/plugins/restful/user.h @@ -41,6 +41,8 @@ int neu_user_update_password(neu_user_t *user, const char *new_password); neu_user_t *neu_load_user(const char *name); int neu_save_user(neu_user_t *user); +char *neu_decrypt_user_password(const char *crypted_password); + #ifdef __cplusplus } #endif diff --git a/src/utils/base64.c b/src/utils/base64.c index 4dd131a2..8cf95008 100644 --- a/src/utils/base64.c +++ b/src/utils/base64.c @@ -68,10 +68,14 @@ int Base64Decode(const char *b64message, unsigned char **buffer, int *length) BIO_set_flags( bio, BIO_FLAGS_BASE64_NO_NL); // Do not use newlines to flush buffer *length = BIO_read(bio, *buffer, strlen(b64message)); - assert(*length == decodeLen); // length should equal decodeLen, else - // something went horribly wrong BIO_free_all(bio); + if (*length != decodeLen) { + free(*buffer); + *buffer = NULL; + return -1; + } + return (0); // success } diff --git a/src/utils/http.c b/src/utils/http.c index 17d12ebc..2abc67fd 100644 --- a/src/utils/http.c +++ b/src/utils/http.c @@ -340,6 +340,7 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content) case NEU_ERR_DUPLICATE_PASSWORD: case NEU_ERR_WEAK_PASSWORD_ALPHABET: case NEU_ERR_WEAK_PASSWORD_PATTERN: + case NEU_ERR_DECRYPT_PASSWORD_FAILED: case NEU_ERR_TEMPLATE_NAME_TOO_LONG: case NEU_ERR_PLUGIN_NAME_TOO_LONG: case NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE: