]> Repositorios git - scryer-prolog.git/commitdiff
ADDED: Hash-based message authentication code (HMAC), using hmac(Key).
authorMarkus Triska <[email protected]>
Thu, 22 Feb 2024 19:17:20 +0000 (20:17 +0100)
committerMarkus Triska <[email protected]>
Thu, 22 Feb 2024 19:53:27 +0000 (20:53 +0100)
build/instructions_template.rs
src/lib/crypto.pl
src/machine/dispatch.rs
src/machine/system_calls.rs

index 1840341b1644ca2c1a07405b163d7c0ef98255e7..e554423908b0af4dd8c017fbd235ffdc5f9c24a2 100644 (file)
@@ -497,6 +497,8 @@ enum SystemClauseType {
     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")))]
@@ -1846,6 +1848,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallScryerPrologVersion |
                     &Instruction::CallCryptoRandomByte |
                     &Instruction::CallCryptoDataHash |
+                    &Instruction::CallCryptoHMAC |
                     &Instruction::CallCryptoDataHKDF |
                     &Instruction::CallCryptoPasswordHash |
                     &Instruction::CallCryptoCurveScalarMult |
@@ -2082,6 +2085,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteScryerPrologVersion |
                     &Instruction::ExecuteCryptoRandomByte |
                     &Instruction::ExecuteCryptoDataHash |
+                    &Instruction::ExecuteCryptoHMAC |
                     &Instruction::ExecuteCryptoDataHKDF |
                     &Instruction::ExecuteCryptoPasswordHash |
                     &Instruction::ExecuteCryptoCurveScalarMult |
index bcd2bb9d46fe08be500f464e9cca14944d150956..bd5e622d2c786d4d4a7a897c011b8546579b1221 100644 (file)
@@ -1,5 +1,5 @@
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-   Written 2020-2023 by Markus Triska ([email protected])
+   Written 2020-2024 by Markus Triska ([email protected])
    Part of Scryer Prolog.
 
 /** 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
 %      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:
 %
 % ```
@@ -214,9 +219,18 @@ crypto_data_hash(Data0, Hash, Options0) :-
         (   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),
index f3a73e6ced07d9050e398e413e219e164c765f4f..ddd077a59ab6b8abc41a4b0f642f037fab1fb1d3 100644 (file)
@@ -4464,6 +4464,14 @@ impl Machine {
                         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);
index 73bf62f226ec4ff5ae2ad9fe14c33c68605d2c51..fb3ecc1d5ea981b369e173107371cacbb65e2e79 100644 (file)
@@ -78,7 +78,7 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
 
 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;
@@ -7393,6 +7393,40 @@ impl Machine {
         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));