feat: HMAC support in Crypto APIs
This commit is contained in:
@ -100,3 +100,7 @@ if env["builtin_mbedtls"]:
|
||||
|
||||
# Module sources
|
||||
env_mbed_tls.add_source_files(env.modules_sources, "*.cpp")
|
||||
|
||||
if env["tests"]:
|
||||
env_mbed_tls.Append(CPPDEFINES=["TESTS_ENABLED"])
|
||||
env_mbed_tls.add_source_files(env.modules_sources, "./tests/*.cpp")
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#define PEM_END_CRT "-----END CERTIFICATE-----\n"
|
||||
|
||||
#include <mbedtls/debug.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/pem.h>
|
||||
|
||||
CryptoKey *CryptoKeyMbedTLS::create() {
|
||||
@ -186,6 +187,68 @@ Error X509CertificateMbedTLS::save(String p_path) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool HMACContextMbedTLS::is_md_type_allowed(mbedtls_md_type_t p_md_type) {
|
||||
switch (p_md_type) {
|
||||
case MBEDTLS_MD_SHA1:
|
||||
case MBEDTLS_MD_SHA256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HMACContext *HMACContextMbedTLS::create() {
|
||||
return memnew(HMACContextMbedTLS);
|
||||
}
|
||||
|
||||
Error HMACContextMbedTLS::start(HashingContext::HashType p_hash_type, PackedByteArray p_key) {
|
||||
ERR_FAIL_COND_V_MSG(ctx != nullptr, ERR_FILE_ALREADY_IN_USE, "HMACContext already started.");
|
||||
|
||||
// HMAC keys can be any size.
|
||||
ERR_FAIL_COND_V_MSG(p_key.empty(), ERR_INVALID_PARAMETER, "Key must not be empty.");
|
||||
|
||||
hash_type = p_hash_type;
|
||||
mbedtls_md_type_t ht = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, hash_len);
|
||||
|
||||
bool allowed = HMACContextMbedTLS::is_md_type_allowed(ht);
|
||||
ERR_FAIL_COND_V_MSG(!allowed, ERR_INVALID_PARAMETER, "Unsupported hash type.");
|
||||
|
||||
ctx = memalloc(sizeof(mbedtls_md_context_t));
|
||||
mbedtls_md_init((mbedtls_md_context_t *)ctx);
|
||||
|
||||
mbedtls_md_setup((mbedtls_md_context_t *)ctx, mbedtls_md_info_from_type((mbedtls_md_type_t)ht), 1);
|
||||
int ret = mbedtls_md_hmac_starts((mbedtls_md_context_t *)ctx, (const uint8_t *)p_key.ptr(), (size_t)p_key.size());
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
Error HMACContextMbedTLS::update(PackedByteArray p_data) {
|
||||
ERR_FAIL_COND_V_MSG(ctx == nullptr, ERR_INVALID_DATA, "Start must be called before update.");
|
||||
|
||||
ERR_FAIL_COND_V_MSG(p_data.empty(), ERR_INVALID_PARAMETER, "Src must not be empty.");
|
||||
|
||||
int ret = mbedtls_md_hmac_update((mbedtls_md_context_t *)ctx, (const uint8_t *)p_data.ptr(), (size_t)p_data.size());
|
||||
return ret ? FAILED : OK;
|
||||
}
|
||||
|
||||
PackedByteArray HMACContextMbedTLS::finish() {
|
||||
ERR_FAIL_COND_V_MSG(ctx == nullptr, PackedByteArray(), "Start must be called before finish.");
|
||||
ERR_FAIL_COND_V_MSG(hash_len == 0, PackedByteArray(), "Unsupported hash type.");
|
||||
|
||||
PackedByteArray out;
|
||||
out.resize(hash_len);
|
||||
|
||||
unsigned char *out_ptr = (unsigned char *)out.ptrw();
|
||||
int ret = mbedtls_md_hmac_finish((mbedtls_md_context_t *)ctx, out_ptr);
|
||||
|
||||
mbedtls_md_free((mbedtls_md_context_t *)ctx);
|
||||
memfree((mbedtls_md_context_t *)ctx);
|
||||
ctx = nullptr;
|
||||
hash_len = 0;
|
||||
|
||||
ERR_FAIL_COND_V_MSG(ret, PackedByteArray(), "Error received while finishing HMAC");
|
||||
return out;
|
||||
}
|
||||
|
||||
Crypto *CryptoMbedTLS::create() {
|
||||
return memnew(CryptoMbedTLS);
|
||||
}
|
||||
@ -199,6 +262,7 @@ void CryptoMbedTLS::initialize_crypto() {
|
||||
Crypto::_load_default_certificates = load_default_certificates;
|
||||
X509CertificateMbedTLS::make_default();
|
||||
CryptoKeyMbedTLS::make_default();
|
||||
HMACContextMbedTLS::make_default();
|
||||
}
|
||||
|
||||
void CryptoMbedTLS::finalize_crypto() {
|
||||
@ -210,6 +274,7 @@ void CryptoMbedTLS::finalize_crypto() {
|
||||
}
|
||||
X509CertificateMbedTLS::finalize();
|
||||
CryptoKeyMbedTLS::finalize();
|
||||
HMACContextMbedTLS::finalize();
|
||||
}
|
||||
|
||||
CryptoMbedTLS::CryptoMbedTLS() {
|
||||
@ -313,7 +378,7 @@ PackedByteArray CryptoMbedTLS::generate_random_bytes(int p_bytes) {
|
||||
return out;
|
||||
}
|
||||
|
||||
mbedtls_md_type_t CryptoMbedTLS::_md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
|
||||
mbedtls_md_type_t CryptoMbedTLS::md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size) {
|
||||
switch (p_hash_type) {
|
||||
case HashingContext::HASH_MD5:
|
||||
r_size = 16;
|
||||
@ -332,7 +397,7 @@ mbedtls_md_type_t CryptoMbedTLS::_md_type_from_hashtype(HashingContext::HashType
|
||||
|
||||
Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Ref<CryptoKey> p_key) {
|
||||
int size;
|
||||
mbedtls_md_type_t type = _md_type_from_hashtype(p_hash_type, size);
|
||||
mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
|
||||
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, Vector<uint8_t>(), "Invalid hash type.");
|
||||
ERR_FAIL_COND_V_MSG(p_hash.size() != size, Vector<uint8_t>(), "Invalid hash provided. Size must be " + itos(size));
|
||||
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
|
||||
@ -350,7 +415,7 @@ Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector
|
||||
|
||||
bool CryptoMbedTLS::verify(HashingContext::HashType p_hash_type, Vector<uint8_t> p_hash, Vector<uint8_t> p_signature, Ref<CryptoKey> p_key) {
|
||||
int size;
|
||||
mbedtls_md_type_t type = _md_type_from_hashtype(p_hash_type, size);
|
||||
mbedtls_md_type_t type = CryptoMbedTLS::md_type_from_hashtype(p_hash_type, size);
|
||||
ERR_FAIL_COND_V_MSG(type == MBEDTLS_MD_NONE, false, "Invalid hash type.");
|
||||
ERR_FAIL_COND_V_MSG(p_hash.size() != size, false, "Invalid hash provided. Size must be " + itos(size));
|
||||
Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
|
||||
|
||||
@ -101,12 +101,31 @@ public:
|
||||
friend class SSLContextMbedTLS;
|
||||
};
|
||||
|
||||
class HMACContextMbedTLS : public HMACContext {
|
||||
private:
|
||||
HashingContext::HashType hash_type;
|
||||
int hash_len = 0;
|
||||
void *ctx = nullptr;
|
||||
|
||||
public:
|
||||
static HMACContext *create();
|
||||
static void make_default() { HMACContext::_create = create; }
|
||||
static void finalize() { HMACContext::_create = nullptr; }
|
||||
|
||||
static bool is_md_type_allowed(mbedtls_md_type_t p_md_type);
|
||||
|
||||
virtual Error start(HashingContext::HashType p_hash_type, PackedByteArray p_key);
|
||||
virtual Error update(PackedByteArray p_data);
|
||||
virtual PackedByteArray finish();
|
||||
|
||||
HMACContextMbedTLS() {}
|
||||
};
|
||||
|
||||
class CryptoMbedTLS : public Crypto {
|
||||
private:
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
static X509CertificateMbedTLS *default_certs;
|
||||
mbedtls_md_type_t _md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
|
||||
|
||||
public:
|
||||
static Crypto *create();
|
||||
@ -114,6 +133,7 @@ public:
|
||||
static void finalize_crypto();
|
||||
static X509CertificateMbedTLS *get_default_certificates();
|
||||
static void load_default_certificates(String p_path);
|
||||
static mbedtls_md_type_t md_type_from_hashtype(HashingContext::HashType p_hash_type, int &r_size);
|
||||
|
||||
virtual PackedByteArray generate_random_bytes(int p_bytes);
|
||||
virtual Ref<CryptoKey> generate_rsa(int p_bytes);
|
||||
|
||||
@ -35,6 +35,10 @@
|
||||
#include "packet_peer_mbed_dtls.h"
|
||||
#include "stream_peer_mbedtls.h"
|
||||
|
||||
#ifdef TESTS_ENABLED
|
||||
#include "tests/test_crypto_mbedtls.h"
|
||||
#endif
|
||||
|
||||
void register_mbedtls_types() {
|
||||
CryptoMbedTLS::initialize_crypto();
|
||||
StreamPeerMbedTLS::initialize_ssl();
|
||||
|
||||
62
modules/mbedtls/tests/test_crypto_mbedtls.cpp
Normal file
62
modules/mbedtls/tests/test_crypto_mbedtls.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*************************************************************************/
|
||||
/* test_crypto_mbedtls.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "modules/mbedtls/tests/test_crypto_mbedtls.h"
|
||||
|
||||
#include "modules/mbedtls/crypto_mbedtls.h"
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
namespace TestCryptoMbedTLS {
|
||||
|
||||
void hmac_digest_test(HashingContext::HashType ht, String expected_hex) {
|
||||
CryptoMbedTLS crypto;
|
||||
PackedByteArray key = String("supersecretkey").to_utf8_buffer();
|
||||
PackedByteArray msg = String("Return of the MAC!").to_utf8_buffer();
|
||||
PackedByteArray digest = crypto.hmac_digest(ht, key, msg);
|
||||
String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
|
||||
CHECK(hex == expected_hex);
|
||||
}
|
||||
|
||||
void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex) {
|
||||
HMACContextMbedTLS ctx;
|
||||
PackedByteArray key = String("supersecretkey").to_utf8_buffer();
|
||||
PackedByteArray msg1 = String("Return of ").to_utf8_buffer();
|
||||
PackedByteArray msg2 = String("the MAC!").to_utf8_buffer();
|
||||
Error err = ctx.start(ht, key);
|
||||
CHECK(err == OK);
|
||||
err = ctx.update(msg1);
|
||||
CHECK(err == OK);
|
||||
err = ctx.update(msg2);
|
||||
CHECK(err == OK);
|
||||
PackedByteArray digest = ctx.finish();
|
||||
String hex = String::hex_encode_buffer(digest.ptr(), digest.size());
|
||||
CHECK(hex == expected_hex);
|
||||
}
|
||||
} // namespace TestCryptoMbedTLS
|
||||
61
modules/mbedtls/tests/test_crypto_mbedtls.h
Normal file
61
modules/mbedtls/tests/test_crypto_mbedtls.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*************************************************************************/
|
||||
/* test_crypto_mbedtls.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef TEST_CRYPTO_MBEDTLS_H
|
||||
#define TEST_CRYPTO_MBEDTLS_H
|
||||
|
||||
#include "core/crypto/hashing_context.h"
|
||||
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
namespace TestCryptoMbedTLS {
|
||||
|
||||
void hmac_digest_test(HashingContext::HashType ht, String expected_hex);
|
||||
|
||||
TEST_CASE("[CryptoMbedTLS] HMAC digest") {
|
||||
// SHA-256
|
||||
hmac_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
|
||||
|
||||
// SHA-1
|
||||
hmac_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
|
||||
}
|
||||
|
||||
void hmac_context_digest_test(HashingContext::HashType ht, String expected_hex);
|
||||
|
||||
TEST_CASE("[HMACContext] HMAC digest") {
|
||||
// SHA-256
|
||||
hmac_context_digest_test(HashingContext::HashType::HASH_SHA256, "fe442023f8a7d36a810e1e7cd8a8e2816457f350a008fbf638296afa12085e59");
|
||||
|
||||
// SHA-1
|
||||
hmac_context_digest_test(HashingContext::HashType::HASH_SHA1, "a0ac4cd68a2f4812c355983d94e8d025afe7dddf");
|
||||
}
|
||||
} // namespace TestCryptoMbedTLS
|
||||
|
||||
#endif // TEST_CRYPTO_MBEDTLS_H
|
||||
Reference in New Issue
Block a user