ADDED: Public key signatures and signature verification with Ed25519
This commit is contained in:
@@ -380,6 +380,7 @@ The modules that ship with Scryer Prolog are also called
|
||||
* [`crypto`](src/prolog/lib/crypto.pl)
|
||||
Cryptographically secure random numbers and hashes, HMAC-based
|
||||
key derivation (HKDF), password-based key derivation (PBKDF2),
|
||||
public key signatures and signature verification with Ed25519,
|
||||
authenticated encryption, and reasoning about elliptic curves.
|
||||
|
||||
To read contents of external files, use `phrase_from_file/2` from
|
||||
|
||||
@@ -291,7 +291,9 @@ pub enum SystemClauseType {
|
||||
CryptoDataHKDF,
|
||||
CryptoPasswordHash,
|
||||
CryptoDataEncrypt,
|
||||
CryptoDataDecrypt
|
||||
CryptoDataDecrypt,
|
||||
Ed25519Sign,
|
||||
Ed25519Verify
|
||||
}
|
||||
|
||||
impl SystemClauseType {
|
||||
@@ -480,6 +482,8 @@ impl SystemClauseType {
|
||||
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
||||
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
||||
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
|
||||
&SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
|
||||
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,6 +652,8 @@ impl SystemClauseType {
|
||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||
("$crypto_data_decrypt", 5) => Some(SystemClauseType::CryptoDataDecrypt),
|
||||
("$ed25519_sign", 3) => Some(SystemClauseType::Ed25519Sign),
|
||||
("$ed25519_verify", 3) => Some(SystemClauseType::Ed25519Verify),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
and strings have the advantage that the atom table remains unmodified.
|
||||
|
||||
Especially for cryptographic applications, it as an advantage that
|
||||
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,
|
||||
@@ -21,6 +21,8 @@
|
||||
crypto_password_hash/3, % +Password, -Hash, +Options
|
||||
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
||||
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
||||
ed25519_sign/4, % +PrivateKey, +Data, -Signature, +Options
|
||||
ed25519_verify/4, % +PublicKey, +Data, -Signature, +Options
|
||||
crypto_name_curve/2, % +Name, -Curve
|
||||
crypto_curve_order/2, % +Curve, -Order
|
||||
crypto_curve_generator/2, % +Curve, -Generator
|
||||
@@ -624,6 +626,44 @@ encoding_bytes(utf8, Cs, Bs) :-
|
||||
; domain_error(encryption_encoding, Cs, crypto)
|
||||
).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Digital signatures with Ed25519
|
||||
===============================
|
||||
|
||||
ed25519_sign(+Key, +Data, -Signature, +Options)
|
||||
|
||||
Key and Data must be lists of characters. Key is a private key in
|
||||
PKCS#8 (v1 or v2) DER format. Sign Data with Key, yielding
|
||||
Signature as a list of hexadecimal characters.
|
||||
|
||||
|
||||
ed25519_verify(+Key, +Data, +Signature, +Options)
|
||||
|
||||
Key and Data must be lists of characters. Key is a public key in
|
||||
PKCS#8 DER format. Succeeds if Data was signed with the private key
|
||||
corresponding to Key, where Signature is a list of hexadecimal
|
||||
characters as generated by ed25519_sign/4. Fails otherwise.
|
||||
|
||||
|
||||
Currently, the only option for both predicates is:
|
||||
|
||||
- encoding(+Encoding)
|
||||
The default encoding of Data is utf8. The alternative is octet,
|
||||
which treats Data as a list of raw bytes.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
ed25519_sign(Key0, Data0, Signature, Options) :-
|
||||
options_data_bytes(Options, Data0, Data),
|
||||
encoding_bytes(octet, Key0, Key),
|
||||
'$ed25519_sign'(Key, Data, Signature0),
|
||||
hex_bytes(Signature, Signature0).
|
||||
|
||||
ed25519_verify(Key0, Data0, Signature0, Options) :-
|
||||
options_data_bytes(Options, Data0, Data),
|
||||
encoding_bytes(octet, Key0, Key),
|
||||
hex_bytes(Signature0, Signature),
|
||||
'$ed25519_verify'(Key, Data, Signature).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Modular multiplicative inverse.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
|
||||
use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
|
||||
|
||||
use ring::rand::{SecureRandom, SystemRandom};
|
||||
use ring::{digest,hkdf,pbkdf2,aead,error};
|
||||
use ring::{digest,hkdf,pbkdf2,aead,error,signature};
|
||||
use ripemd160::{Ripemd160, Digest};
|
||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
||||
use blake2::{Blake2s, Blake2b};
|
||||
@@ -5448,6 +5448,38 @@ impl MachineState {
|
||||
|
||||
self.unify(self[temp_v!(5)], complete_string);
|
||||
}
|
||||
&SystemClauseType::Ed25519Sign => {
|
||||
let stub1 = MachineError::functor_stub(clause_name!("ed25519_sign"), 4);
|
||||
let key = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||
let stub2 = MachineError::functor_stub(clause_name!("ed25519_sign"), 4);
|
||||
let data = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||
|
||||
let key_pair = match signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(&key) {
|
||||
Ok(kp) => { kp }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
};
|
||||
|
||||
let sig = key_pair.sign(&data);
|
||||
|
||||
let sig_list =
|
||||
Addr::HeapCell(self.heap.to_list(sig.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))));
|
||||
|
||||
self.unify(self[temp_v!(3)], sig_list);
|
||||
}
|
||||
&SystemClauseType::Ed25519Verify => {
|
||||
let stub1 = MachineError::functor_stub(clause_name!("ed25519_verify"), 4);
|
||||
let key = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||
let stub2 = MachineError::functor_stub(clause_name!("ed25519_verify"), 4);
|
||||
let data = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||
let stub3 = MachineError::functor_stub(clause_name!("ed25519_verify"), 4);
|
||||
let signature = self.integers_to_bytevec(temp_v!(3), stub3);
|
||||
|
||||
let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
|
||||
match peer_public_key.verify(&data, &signature) {
|
||||
Ok(_) => { }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return_from_clause!(self.last_call, self)
|
||||
|
||||
Reference in New Issue
Block a user