ADDED: Hash-based message authentication code (HMAC), using hmac(Key).

This commit is contained in:
Markus Triska
2024-02-22 20:17:20 +01:00
parent d4bde5008d
commit 27852eafd7
4 changed files with 63 additions and 3 deletions

View File

@@ -497,6 +497,8 @@ enum SystemClauseType {
CryptoRandomByte, CryptoRandomByte,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_data_hash")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_data_hash")))]
CryptoDataHash, CryptoDataHash,
#[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_hmac")))]
CryptoHMAC,
#[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_hkdf")))] #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_hkdf")))]
CryptoDataHKDF, CryptoDataHKDF,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))]
@@ -1846,6 +1848,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallScryerPrologVersion | &Instruction::CallScryerPrologVersion |
&Instruction::CallCryptoRandomByte | &Instruction::CallCryptoRandomByte |
&Instruction::CallCryptoDataHash | &Instruction::CallCryptoDataHash |
&Instruction::CallCryptoHMAC |
&Instruction::CallCryptoDataHKDF | &Instruction::CallCryptoDataHKDF |
&Instruction::CallCryptoPasswordHash | &Instruction::CallCryptoPasswordHash |
&Instruction::CallCryptoCurveScalarMult | &Instruction::CallCryptoCurveScalarMult |
@@ -2082,6 +2085,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteScryerPrologVersion | &Instruction::ExecuteScryerPrologVersion |
&Instruction::ExecuteCryptoRandomByte | &Instruction::ExecuteCryptoRandomByte |
&Instruction::ExecuteCryptoDataHash | &Instruction::ExecuteCryptoDataHash |
&Instruction::ExecuteCryptoHMAC |
&Instruction::ExecuteCryptoDataHKDF | &Instruction::ExecuteCryptoDataHKDF |
&Instruction::ExecuteCryptoPasswordHash | &Instruction::ExecuteCryptoPasswordHash |
&Instruction::ExecuteCryptoCurveScalarMult | &Instruction::ExecuteCryptoCurveScalarMult |

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written 2020-2023 by Markus Triska (triska@metalevel.at) Written 2020-2024 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog. Part of Scryer Prolog.
/** Predicates for cryptographic applications. /** Predicates for cryptographic applications.
@@ -192,6 +192,11 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
% The default encoding is `utf8`. The alternative is `octet`, to % The default encoding is `utf8`. The alternative is `octet`, to
% treat the input as a list of raw bytes. % treat the input as a list of raw bytes.
% %
% - `hmac(+Key)`
% Compute a hash-based message authentication code (HMAC) using
% Key, a list of bytes. This option is currently supported for
% algorithms `sha256`, `sha384` and `sha512`.
%
% Example: % Example:
% %
% ``` % ```
@@ -214,9 +219,18 @@ crypto_data_hash(Data0, Hash, Options0) :-
( hash_algorithm(A) -> true ( hash_algorithm(A) -> true
; domain_error(hash_algorithm, A, crypto_data_hash/3) ; domain_error(hash_algorithm, A, crypto_data_hash/3)
), ),
'$crypto_data_hash'(Data, Encoding, HashBytes, A), ( member(HMAC, Options0), nonvar(HMAC), HMAC = hmac(Ks) ->
must_be_bytes(Ks, crypto_data_hash/3),
hmac_algorithm(A),
'$crypto_hmac'(Data, Encoding, Ks, HashBytes, A)
; '$crypto_data_hash'(Data, Encoding, HashBytes, A)
),
hex_bytes(Hash, HashBytes). hex_bytes(Hash, HashBytes).
hmac_algorithm(sha256).
hmac_algorithm(sha384).
hmac_algorithm(sha512).
options_data_chars(Options, Data, Chars, Encoding) :- options_data_chars(Options, Data, Chars, Encoding) :-
option(encoding(Encoding), Options, utf8), option(encoding(Encoding), Options, utf8),
must_be(atom, Encoding), must_be(atom, Encoding),

View File

@@ -4464,6 +4464,14 @@ impl Machine {
self.crypto_data_hash(); self.crypto_data_hash();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallCryptoHMAC => {
self.crypto_hmac();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCryptoHMAC => {
self.crypto_hmac();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCryptoDataHKDF => { &Instruction::CallCryptoDataHKDF => {
self.crypto_data_hkdf(); self.crypto_data_hkdf();
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);

View File

@@ -78,7 +78,7 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use blake2::{Blake2b, Blake2s}; use blake2::{Blake2b, Blake2s};
use ring::rand::{SecureRandom, SystemRandom}; use ring::rand::{SecureRandom, SystemRandom};
use ring::{digest, hkdf, pbkdf2}; use ring::{digest, hkdf, hmac, pbkdf2};
#[cfg(feature = "crypto-full")] #[cfg(feature = "crypto-full")]
use ring::aead; use ring::aead;
@@ -7393,6 +7393,40 @@ impl Machine {
unify!(self.machine_st, self.machine_st.registers[3], ints_list); unify!(self.machine_st, self.machine_st.registers[3], ints_list);
} }
#[inline(always)]
pub(crate) fn crypto_hmac(&mut self) {
let encoding = cell_as_atom!(self.deref_register(2));
let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
let stub_gen = || functor_stub(atom!("crypto_data_hash"), 3);
let key = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
let algorithm = cell_as_atom!(self.deref_register(5));
let ralg = match algorithm {
atom!("sha256") => hmac::HMAC_SHA256,
atom!("sha384") => hmac::HMAC_SHA384,
atom!("sha512") => hmac::HMAC_SHA512,
_ => {
unreachable!()
}
};
let rkey = hmac::Key::new(ralg, key.as_ref());
let tag = hmac::sign(&rkey, &data);
let ints_list = heap_loc_as_cell!(iter_to_heap_list(
&mut self.machine_st.heap,
tag.as_ref()
.iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
));
unify!(self.machine_st, self.machine_st.registers[4], ints_list);
}
#[inline(always)] #[inline(always)]
pub(crate) fn crypto_data_hkdf(&mut self) { pub(crate) fn crypto_data_hkdf(&mut self) {
let encoding = cell_as_atom!(self.deref_register(2)); let encoding = cell_as_atom!(self.deref_register(2));