Authenticated encryption in library(crypto), new encoding/1 option for hashes (#515)
* shorten n_newlines//1 * remove unneeded variable * ADDED: authenticated encryption and decryption with ChaCha20-Poly1305 * ADDED: encoding/1 option for crypto_data_hash/3 and crypto_data_hkdf/4
This commit is contained in:
@@ -380,7 +380,7 @@ The modules that ship with Scryer Prolog are also called
|
|||||||
* [`crypto`](src/prolog/lib/crypto.pl)
|
* [`crypto`](src/prolog/lib/crypto.pl)
|
||||||
Cryptographically secure random numbers and hashes, HMAC-based
|
Cryptographically secure random numbers and hashes, HMAC-based
|
||||||
key derivation (HKDF), password-based key derivation (PBKDF2),
|
key derivation (HKDF), password-based key derivation (PBKDF2),
|
||||||
and reasoning about elliptic curves.
|
authenticated encryption, and reasoning about elliptic curves.
|
||||||
|
|
||||||
To read contents of external files, use `phrase_from_file/2` from
|
To read contents of external files, use `phrase_from_file/2` from
|
||||||
[`library(pio)`](src/prolog/lib/pio.pl) to apply a DCG to
|
[`library(pio)`](src/prolog/lib/pio.pl) to apply a DCG to
|
||||||
|
|||||||
@@ -289,7 +289,9 @@ pub enum SystemClauseType {
|
|||||||
CryptoRandomByte,
|
CryptoRandomByte,
|
||||||
CryptoDataHash,
|
CryptoDataHash,
|
||||||
CryptoDataHKDF,
|
CryptoDataHKDF,
|
||||||
CryptoPasswordHash
|
CryptoPasswordHash,
|
||||||
|
CryptoDataEncrypt,
|
||||||
|
CryptoDataDecrypt
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemClauseType {
|
impl SystemClauseType {
|
||||||
@@ -476,6 +478,8 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
|
&SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
|
||||||
&SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
|
&SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
|
||||||
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
||||||
|
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
||||||
|
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,6 +646,8 @@ impl SystemClauseType {
|
|||||||
("$crypto_data_hash", 3) => Some(SystemClauseType::CryptoDataHash),
|
("$crypto_data_hash", 3) => Some(SystemClauseType::CryptoDataHash),
|
||||||
("$crypto_data_hkdf", 6) => Some(SystemClauseType::CryptoDataHKDF),
|
("$crypto_data_hkdf", 6) => Some(SystemClauseType::CryptoDataHKDF),
|
||||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||||
|
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||||
|
("$crypto_data_decrypt", 5) => Some(SystemClauseType::CryptoDataDecrypt),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,17 +12,20 @@
|
|||||||
using strings leaves little trace of what was processed in the system,
|
using strings leaves little trace of what was processed in the system,
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
:- module(crypto, [hex_bytes/2, % ?Hex, ?Bytes
|
:- module(crypto,
|
||||||
crypto_n_random_bytes/2, % +N, -Bytes
|
[hex_bytes/2, % ?Hex, ?Bytes
|
||||||
crypto_data_hash/3, % +Data, -Hash, +Options
|
crypto_n_random_bytes/2, % +N, -Bytes
|
||||||
crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options
|
crypto_data_hash/3, % +Data, -Hash, +Options
|
||||||
crypto_name_curve/2, % +Name, -Curve
|
crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options
|
||||||
crypto_curve_order/2, % +Curve, -Order
|
crypto_password_hash/2, % +Password, ?Hash
|
||||||
crypto_curve_generator/2, % +Curve, -Generator
|
crypto_password_hash/3, % +Password, -Hash, +Options
|
||||||
crypto_curve_scalar_mult/4, % +Curve, +Scalar, +Point, -Result
|
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
||||||
crypto_password_hash/2, % +Password, ?Hash
|
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
||||||
crypto_password_hash/3 % +Password, -Hash, +Options
|
crypto_name_curve/2, % +Name, -Curve
|
||||||
]).
|
crypto_curve_order/2, % +Curve, -Order
|
||||||
|
crypto_curve_generator/2, % +Curve, -Generator
|
||||||
|
crypto_curve_scalar_mult/4 % +Curve, +Scalar, +Point, -Result
|
||||||
|
]).
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
@@ -152,16 +155,17 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
|||||||
characters, and Hash is the computed hash as a list of hexadecimal
|
characters, and Hash is the computed hash as a list of hexadecimal
|
||||||
characters.
|
characters.
|
||||||
|
|
||||||
The single supported option is:
|
Options is a list of:
|
||||||
|
|
||||||
algorithm(A)
|
- algorithm(+A)
|
||||||
|
where A is one of ripemd160, sha256, sha384, sha512,
|
||||||
where A is one of ripemd160, sha256, sha384, sha512, sha512_256,
|
sha512_256, or a variable. If A is a variable, then it is
|
||||||
or a variable.
|
unified with the default algorithm, which is an algorithm that
|
||||||
|
is considered cryptographically secure at the time of this
|
||||||
If A is a variable, then it is unified with the default algorithm,
|
writing.
|
||||||
which is an algorithm that is considered cryptographically secure
|
- encoding(+Encoding)
|
||||||
at the time of this writing.
|
The default encoding is utf8. The alternative is octet,
|
||||||
|
to treat the input as a list of raw bytes.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -179,8 +183,9 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
|||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
crypto_data_hash(Data0, Hash, Options0) :-
|
crypto_data_hash(Data0, Hash, Options0) :-
|
||||||
chars_bytes_(Data0, Data, crypto_data_hash/3),
|
|
||||||
must_be(list, Options0),
|
must_be(list, Options0),
|
||||||
|
option(encoding(Encoding), Options0, utf8),
|
||||||
|
encoding_bytes(Encoding, Data0, Data),
|
||||||
functor_hash_options(algorithm, A, Options0, _),
|
functor_hash_options(algorithm, A, 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)
|
||||||
@@ -232,6 +237,9 @@ hash_algorithm(sha512_256).
|
|||||||
- salt(+List)
|
- salt(+List)
|
||||||
Optionally, a list of bytes that are used as salt. The
|
Optionally, a list of bytes that are used as salt. The
|
||||||
default is all zeroes.
|
default is all zeroes.
|
||||||
|
- encoding(+Encoding)
|
||||||
|
The default encoding is utf8. The alternative is octet,
|
||||||
|
to treat the input as a list of raw bytes.
|
||||||
|
|
||||||
The `info/1` option can be used to generate multiple keys from a
|
The `info/1` option can be used to generate multiple keys from a
|
||||||
single master key, using for example values such as "key" and
|
single master key, using for example values such as "key" and
|
||||||
@@ -242,7 +250,8 @@ hash_algorithm(sha512_256).
|
|||||||
|
|
||||||
crypto_data_hkdf(Data0, L, Bytes, Options0) :-
|
crypto_data_hkdf(Data0, L, Bytes, Options0) :-
|
||||||
functor_hash_options(algorithm, Algorithm, Options0, Options),
|
functor_hash_options(algorithm, Algorithm, Options0, Options),
|
||||||
chars_bytes_(Data0, Data, crypto_data_hkdf/4),
|
option(encoding(Encoding), Options, utf8),
|
||||||
|
encoding_bytes(Encoding, Data0, Data),
|
||||||
option(salt(SaltBytes), Options, []),
|
option(salt(SaltBytes), Options, []),
|
||||||
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
|
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
|
||||||
option(info(Info0), Options, []),
|
option(info(Info0), Options, []),
|
||||||
@@ -336,7 +345,7 @@ dollar_segments(Ls, Segments) :-
|
|||||||
|
|
||||||
- algorithm(+Algorithm)
|
- algorithm(+Algorithm)
|
||||||
The algorithm to use. Currently, the only available algorithm
|
The algorithm to use. Currently, the only available algorithm
|
||||||
is =|pbkdf2-sha512|=, which is therefore also the default.
|
is 'pbkdf2-sha512', which is therefore also the default.
|
||||||
- cost(+C)
|
- cost(+C)
|
||||||
C is an integer, denoting the binary logarithm of the number
|
C is an integer, denoting the binary logarithm of the number
|
||||||
of _iterations_ used for the derivation of the hash. This
|
of _iterations_ used for the derivation of the hash. This
|
||||||
@@ -435,6 +444,165 @@ bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
|
|||||||
bytes_base64_(Ls).
|
bytes_base64_(Ls).
|
||||||
|
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_data_encrypt(+PlainText,
|
||||||
|
+Algorithm,
|
||||||
|
+Key,
|
||||||
|
+IV,
|
||||||
|
-CipherText,
|
||||||
|
+Options).
|
||||||
|
|
||||||
|
Encrypt the given PlainText, using the symmetric algorithm
|
||||||
|
Algorithm, key Key, and initialization vector (or nonce) IV, to
|
||||||
|
give CipherText.
|
||||||
|
|
||||||
|
PlainText must be a list of codes or characters, Key and IV must be
|
||||||
|
lists of bytes, and CipherText is created as a list of characters.
|
||||||
|
|
||||||
|
Keys and IVs can be chosen at random (using for example
|
||||||
|
crypto_n_random_bytes/2) or derived from input keying material (IKM)
|
||||||
|
using for example crypto_data_hkdf/4. This input is often a shared
|
||||||
|
secret, such as a negotiated point on an elliptic curve, or the hash
|
||||||
|
that was computed from a password via crypto_password_hash/3 with a
|
||||||
|
freshly generated and specified _salt_.
|
||||||
|
|
||||||
|
Reusing the same combination of Key and IV typically leaks at least
|
||||||
|
_some_ information about the plaintext. For example, identical
|
||||||
|
plaintexts will then correspond to identical ciphertexts. For some
|
||||||
|
algorithms, reusing an IV with the same Key has disastrous results
|
||||||
|
and can cause the loss of all properties that are otherwise
|
||||||
|
guaranteed. Especially in such cases, an IV is also called a
|
||||||
|
_nonce_ (number used once).
|
||||||
|
|
||||||
|
It is safe to store and transfer the used initialization vector (or
|
||||||
|
nonce) in plain text, but the key _must be kept secret_.
|
||||||
|
|
||||||
|
Currently, the only supported algorithm is 'chacha20-poly1305', a
|
||||||
|
powerful and efficient _authenticated_ encryption scheme, providing
|
||||||
|
secrecy and at the same time reliable protection against undetected
|
||||||
|
_modifications_ of the encrypted data. This is a very good choice
|
||||||
|
for virtually all use cases. It is a stream cipher and can encrypt
|
||||||
|
data of any length up to 256 GB. Further, the encrypted data has
|
||||||
|
exactly the same length as the original, and no padding is used.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
- encoding(+Encoding)
|
||||||
|
Encoding to use for PlainText. Default is utf8. The alternative
|
||||||
|
is octet to treat PlainText as raw bytes.
|
||||||
|
|
||||||
|
- tag(-List)
|
||||||
|
For authenticated encryption schemes, List is unified with a
|
||||||
|
list of _bytes_ holding the tag. This tag must be provided for
|
||||||
|
decryption.
|
||||||
|
|
||||||
|
Here is an example encryption and decryption, using the ChaCha20
|
||||||
|
stream cipher with the Poly1305 authenticator. This cipher uses a
|
||||||
|
256-bit key and a 96-bit nonce, i.e., 32 and 12 _bytes_,
|
||||||
|
respectively:
|
||||||
|
|
||||||
|
?- Algorithm = 'chacha20-poly1305',
|
||||||
|
crypto_n_random_bytes(32, Key),
|
||||||
|
crypto_n_random_bytes(12, IV),
|
||||||
|
crypto_data_encrypt("this text is to be encrypted", Algorithm,
|
||||||
|
Key, IV, CipherText, [tag(Tag)]),
|
||||||
|
crypto_data_decrypt(CipherText, Algorithm,
|
||||||
|
Key, IV, RecoveredText, [tag(Tag)]).
|
||||||
|
|
||||||
|
Yielding:
|
||||||
|
|
||||||
|
Algorithm = 'chacha20-poly1305',
|
||||||
|
Key = [113,247,153,134,177,220,13,193,50,150|...],
|
||||||
|
IV = [135,20,149,153,63,35,68,114,247,171|...],
|
||||||
|
CipherText = "\x94\0Ej\x94\®Â\x95\óÑÆXÃn¾ð©b\x1c\ ...",
|
||||||
|
RecoveredText = "this text is to be ...",
|
||||||
|
Tag = [152,117,152,17,162,75,150,206,144,40|...]
|
||||||
|
|
||||||
|
In this example, we use crypto_n_random_bytes/2 to generate a key
|
||||||
|
and nonce from cryptographically secure random numbers. For
|
||||||
|
repeated applications, you must ensure that a nonce is only used
|
||||||
|
_once_ together with the same key. Note that for _authenticated_
|
||||||
|
encryption schemes, the _tag_ that was computed during encryption
|
||||||
|
is necessary for decryption. It is safe to store and transfer the
|
||||||
|
tag in plain text.
|
||||||
|
|
||||||
|
See also crypto_data_decrypt/6, and hex_bytes/2 for conversion
|
||||||
|
between bytes and hex encoding.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
|
||||||
|
option(encoding(Encoding), Options, utf8),
|
||||||
|
encoding_bytes(Encoding, PlainText0, PlainText),
|
||||||
|
option(tag(Tag), Options, _),
|
||||||
|
( nonvar(Tag) ->
|
||||||
|
must_be_bytes(Tag, crypto_data_encrypt/6)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
must_be_bytes(Key, crypto_data_encrypt/6),
|
||||||
|
must_be_bytes(IV, crypto_data_encrypt/6),
|
||||||
|
must_be(atom, Algorithm),
|
||||||
|
( Algorithm = 'chacha20-poly1305' -> true
|
||||||
|
; domain_error('chacha20-poly1305', Algorithm, crypto_data_encrypt/6)
|
||||||
|
),
|
||||||
|
'$crypto_data_encrypt'(PlainText, Key, IV, Tag, CipherText).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_data_decrypt(+CipherText,
|
||||||
|
+Algorithm,
|
||||||
|
+Key,
|
||||||
|
+IV,
|
||||||
|
-PlainText,
|
||||||
|
+Options).
|
||||||
|
|
||||||
|
Decrypt the given CipherText, using the symmetric algorithm
|
||||||
|
Algorithm, key Key, and initialization vector IV, to give
|
||||||
|
PlainText. CipherText must be a list of bytes or characters, and
|
||||||
|
Key and IV must be lists of bytes. PlainText is created as a list
|
||||||
|
of characters.
|
||||||
|
|
||||||
|
Currently, the only supported algorithm is 'chacha20-poly1305',
|
||||||
|
a very secure, fast and versatile authenticated encryption method.
|
||||||
|
|
||||||
|
Options is a list of:
|
||||||
|
|
||||||
|
- encoding(+Encoding)
|
||||||
|
Encoding to use for PlainText. The default is utf8. The
|
||||||
|
alternative is octet, which is used if the data are raw bytes.
|
||||||
|
|
||||||
|
- tag(+Tag)
|
||||||
|
For authenticated encryption schemes, the tag must be specified as
|
||||||
|
a list of bytes exactly as they were generated upon encryption.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||||
|
option(tag(Tag), Options, []),
|
||||||
|
must_be_bytes(Tag, crypto_data_decrypt/6),
|
||||||
|
must_be_bytes(Key, crypto_data_decrypt/6),
|
||||||
|
must_be_bytes(IV, crypto_data_decrypt/6),
|
||||||
|
must_be(atom, Algorithm),
|
||||||
|
option(encoding(Encoding), Options, utf8),
|
||||||
|
must_be(list, CipherText0),
|
||||||
|
encoding_bytes(octet, CipherText0, CipherText1),
|
||||||
|
append(CipherText1, Tag, CipherText),
|
||||||
|
( Algorithm = 'chacha20-poly1305' -> true
|
||||||
|
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
|
||||||
|
),
|
||||||
|
'$crypto_data_decrypt'(CipherText, Key, IV, Encoding, PlainText).
|
||||||
|
|
||||||
|
encoding_bytes(octet, Bs0, Bs) :-
|
||||||
|
( maplist(integer, Bs0) ->
|
||||||
|
Bs0 = Bs
|
||||||
|
; maplist(char_code, Bs0, Bs)
|
||||||
|
),
|
||||||
|
must_be_bytes(Bs, crypto_encoding).
|
||||||
|
encoding_bytes(utf8, Cs, Bs) :-
|
||||||
|
( maplist(atom, Cs) ->
|
||||||
|
chars_bytes_(Cs, Bs, crypto_encoding)
|
||||||
|
; domain_error(encryption_encoding, Cs, crypto)
|
||||||
|
).
|
||||||
|
|
||||||
|
char_code(Char, Code) :- atom_codes(Char, [Code]).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Modular multiplicative inverse.
|
Modular multiplicative inverse.
|
||||||
|
|
||||||
|
|||||||
@@ -275,8 +275,7 @@ cells(Fs0, Args, Tab, Es) -->
|
|||||||
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
|
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
|
||||||
|
|
||||||
n_newlines(0) --> !.
|
n_newlines(0) --> !.
|
||||||
n_newlines(1) --> !, [newline].
|
n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N).
|
||||||
n_newlines(N0) --> { N0 > 1, N is N0 - 1 }, [newline], n_newlines(N).
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
?- phrase(upto_what(Cs, ~), "abc~test", Rest).
|
?- phrase(upto_what(Cs, ~), "abc~test", Rest).
|
||||||
@@ -545,7 +544,7 @@ listing(PI) :-
|
|||||||
; type_error(predicate_indicator, PI, listing/1)
|
; type_error(predicate_indicator, PI, listing/1)
|
||||||
),
|
),
|
||||||
functor(Head, Name, Arity),
|
functor(Head, Name, Arity),
|
||||||
\+ \+ clause(Head, Body), % only true if there is at least one clause
|
\+ \+ clause(Head, _), % only true if there is at least one clause
|
||||||
( clause(Head, Body),
|
( clause(Head, Body),
|
||||||
( Body == true ->
|
( Body == true ->
|
||||||
portray_clause(Head)
|
portray_clause(Head)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
|
|||||||
use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
|
use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
|
||||||
|
|
||||||
use ring::rand::{SecureRandom, SystemRandom};
|
use ring::rand::{SecureRandom, SystemRandom};
|
||||||
use ring::{digest,hkdf,pbkdf2};
|
use ring::{digest,hkdf,pbkdf2,aead,error};
|
||||||
use ripemd160::{Ripemd160, Digest};
|
use ripemd160::{Ripemd160, Digest};
|
||||||
|
|
||||||
pub fn get_key() -> KeyEvent {
|
pub fn get_key() -> KeyEvent {
|
||||||
@@ -5326,6 +5326,85 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify(self[temp_v!(4)], ints_list);
|
self.unify(self[temp_v!(4)], ints_list);
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::CryptoDataEncrypt => {
|
||||||
|
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
||||||
|
let data = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||||
|
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
||||||
|
let key = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||||
|
let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
||||||
|
let iv = self.integers_to_bytevec(temp_v!(3), stub3);
|
||||||
|
|
||||||
|
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||||
|
let nonce_sequence = OneNonceSequence::new(aead::Nonce::try_assume_unique_for_key(&iv).unwrap());
|
||||||
|
let mut key: aead::SealingKey<OneNonceSequence> = aead::BoundKey::new(unbound_key, nonce_sequence);
|
||||||
|
|
||||||
|
let mut in_out = data.clone();
|
||||||
|
let tag =
|
||||||
|
match key.seal_in_place_separate_tag(aead::Aad::empty(), &mut in_out) {
|
||||||
|
Ok(d) => { d }
|
||||||
|
_ => { self.fail = true; return Ok(()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
let tag_list =
|
||||||
|
Addr::HeapCell(self.heap.to_list(tag.as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b))))));
|
||||||
|
|
||||||
|
let complete_string = {
|
||||||
|
let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
|
||||||
|
self.heap.put_complete_string(&buffer)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.unify(self[temp_v!(4)], tag_list);
|
||||||
|
self.unify(self[temp_v!(5)], complete_string);
|
||||||
|
}
|
||||||
|
&SystemClauseType::CryptoDataDecrypt => {
|
||||||
|
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
||||||
|
let data = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||||
|
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
||||||
|
let key = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||||
|
let stub3 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
||||||
|
let iv = self.integers_to_bytevec(temp_v!(3), stub3);
|
||||||
|
|
||||||
|
let encoding = match self.store(self.deref(self[temp_v!(4)])) {
|
||||||
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
|
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
||||||
|
atom.as_str()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||||
|
let nonce_sequence = OneNonceSequence::new(aead::Nonce::try_assume_unique_for_key(&iv).unwrap());
|
||||||
|
let mut key: aead::OpeningKey<OneNonceSequence> = aead::BoundKey::new(unbound_key, nonce_sequence);
|
||||||
|
|
||||||
|
let mut in_out = data.clone();
|
||||||
|
|
||||||
|
let complete_string = {
|
||||||
|
let decrypted_data =
|
||||||
|
match key.open_in_place(aead::Aad::empty(), &mut in_out) {
|
||||||
|
Ok(d) => { d }
|
||||||
|
_ => { self.fail = true; return Ok(()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
let buffer = match encoding {
|
||||||
|
"octet" => { String::from_iter(decrypted_data.iter().map(|b| *b as char)) }
|
||||||
|
"utf8" => { match String::from_utf8(decrypted_data.to_vec()) {
|
||||||
|
Ok(str) => { str }
|
||||||
|
_ => { self.fail = true; return Ok(()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
};
|
||||||
|
|
||||||
|
self.heap.put_complete_string(&buffer)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.unify(self[temp_v!(5)], complete_string);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return_from_clause!(self.last_call, self)
|
return_from_clause!(self.last_call, self)
|
||||||
@@ -5350,3 +5429,17 @@ impl hkdf::KeyType for MyKey<usize> {
|
|||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct OneNonceSequence(Option<aead::Nonce>);
|
||||||
|
|
||||||
|
impl OneNonceSequence {
|
||||||
|
fn new(nonce: aead::Nonce) -> Self {
|
||||||
|
Self(Some(nonce))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl aead::NonceSequence for OneNonceSequence {
|
||||||
|
fn advance(&mut self) -> Result<aead::Nonce, error::Unspecified> {
|
||||||
|
self.0.take().ok_or(error::Unspecified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user