CryptoRandomByte,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_data_hash")))]
CryptoDataHash,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_hmac")))]
+ CryptoHMAC,
#[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_hkdf")))]
CryptoDataHKDF,
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))]
&Instruction::CallScryerPrologVersion |
&Instruction::CallCryptoRandomByte |
&Instruction::CallCryptoDataHash |
+ &Instruction::CallCryptoHMAC |
&Instruction::CallCryptoDataHKDF |
&Instruction::CallCryptoPasswordHash |
&Instruction::CallCryptoCurveScalarMult |
&Instruction::ExecuteScryerPrologVersion |
&Instruction::ExecuteCryptoRandomByte |
&Instruction::ExecuteCryptoDataHash |
+ &Instruction::ExecuteCryptoHMAC |
&Instruction::ExecuteCryptoDataHKDF |
&Instruction::ExecuteCryptoPasswordHash |
&Instruction::ExecuteCryptoCurveScalarMult |
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Part of Scryer Prolog.
/** Predicates for cryptographic applications.
% The default encoding is `utf8`. The alternative is `octet`, to
% 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:
%
% ```
( hash_algorithm(A) -> true
; 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).
+hmac_algorithm(sha256).
+hmac_algorithm(sha384).
+hmac_algorithm(sha512).
+
options_data_chars(Options, Data, Chars, Encoding) :-
option(encoding(Encoding), Options, utf8),
must_be(atom, Encoding),
self.crypto_data_hash();
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 => {
self.crypto_data_hkdf();
step_or_fail!(self, self.machine_st.p += 1);
use blake2::{Blake2b, Blake2s};
use ring::rand::{SecureRandom, SystemRandom};
-use ring::{digest, hkdf, pbkdf2};
+use ring::{digest, hkdf, hmac, pbkdf2};
#[cfg(feature = "crypto-full")]
use ring::aead;
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)]
pub(crate) fn crypto_data_hkdf(&mut self) {
let encoding = cell_as_atom!(self.deref_register(2));