feat: HMAC support in Crypto APIs
This commit is contained in:
@ -65,6 +65,22 @@ void X509Certificate::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("load", "path"), &X509Certificate::load);
|
||||
}
|
||||
|
||||
/// HMACContext
|
||||
|
||||
void HMACContext::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("start", "hash_type", "key"), &HMACContext::start);
|
||||
ClassDB::bind_method(D_METHOD("update", "data"), &HMACContext::update);
|
||||
ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish);
|
||||
}
|
||||
|
||||
HMACContext *(*HMACContext::_create)() = nullptr;
|
||||
HMACContext *HMACContext::create() {
|
||||
if (_create) {
|
||||
return _create();
|
||||
}
|
||||
ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled.");
|
||||
}
|
||||
|
||||
/// Crypto
|
||||
|
||||
void (*Crypto::_load_default_certificates)(String p_path) = nullptr;
|
||||
@ -82,6 +98,35 @@ void Crypto::load_default_certificates(String p_path) {
|
||||
}
|
||||
}
|
||||
|
||||
PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg) {
|
||||
Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create());
|
||||
ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available witout mbedtls module.");
|
||||
Error err = ctx->start(p_hash_type, p_key);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
err = ctx->update(p_msg);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
return ctx->finish();
|
||||
}
|
||||
|
||||
// Compares two HMACS for equality without leaking timing information in order to prevent timing attakcs.
|
||||
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
|
||||
bool Crypto::constant_time_compare(PackedByteArray p_trusted, PackedByteArray p_received) {
|
||||
const uint8_t *t = p_trusted.ptr();
|
||||
const uint8_t *r = p_received.ptr();
|
||||
int tlen = p_trusted.size();
|
||||
int rlen = p_received.size();
|
||||
// If the lengths are different then nothing else matters.
|
||||
if (tlen != rlen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t v = 0;
|
||||
for (int i = 0; i < tlen; i++) {
|
||||
v |= t[i] ^ r[i];
|
||||
}
|
||||
return v == 0;
|
||||
}
|
||||
|
||||
void Crypto::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes);
|
||||
ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa);
|
||||
@ -90,6 +135,8 @@ void Crypto::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("verify", "hash_type", "hash", "signature", "key"), &Crypto::verify);
|
||||
ClassDB::bind_method(D_METHOD("encrypt", "key", "plaintext"), &Crypto::encrypt);
|
||||
ClassDB::bind_method(D_METHOD("decrypt", "key", "ciphertext"), &Crypto::decrypt);
|
||||
ClassDB::bind_method(D_METHOD("hmac_digest", "hash_type", "key", "msg"), &Crypto::hmac_digest);
|
||||
ClassDB::bind_method(D_METHOD("constant_time_compare", "trusted", "received"), &Crypto::constant_time_compare);
|
||||
}
|
||||
|
||||
/// Resource loader/saver
|
||||
|
||||
@ -67,6 +67,23 @@ public:
|
||||
virtual Error save(String p_path) = 0;
|
||||
};
|
||||
|
||||
class HMACContext : public Reference {
|
||||
GDCLASS(HMACContext, Reference);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static HMACContext *(*_create)();
|
||||
|
||||
public:
|
||||
static HMACContext *create();
|
||||
|
||||
virtual Error start(HashingContext::HashType p_hash_type, PackedByteArray p_key) = 0;
|
||||
virtual Error update(PackedByteArray p_data) = 0;
|
||||
virtual PackedByteArray finish() = 0;
|
||||
|
||||
HMACContext() {}
|
||||
};
|
||||
|
||||
class Crypto : public Reference {
|
||||
GDCLASS(Crypto, Reference);
|
||||
|
||||
@ -88,6 +105,12 @@ public:
|
||||
virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_plaintext) = 0;
|
||||
virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_ciphertext) = 0;
|
||||
|
||||
PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg);
|
||||
|
||||
// Compares two PackedByteArrays for equality without leaking timing information in order to prevent timing attacks.
|
||||
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
|
||||
bool constant_time_compare(PackedByteArray p_trusted, PackedByteArray p_received);
|
||||
|
||||
Crypto() {}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user