ADDED: library(crypto): ECDH key exchange over Curve25519 (X25519)

This commit is contained in:
Markus Triska
2020-07-29 23:14:16 +02:00
parent 386f7cf65d
commit 32c612b747
5 changed files with 86 additions and 2 deletions

View File

@@ -47,3 +47,4 @@ chrono = "0.4.11"
select = "0.4.3" select = "0.4.3"
roxmltree = "0.11.0" roxmltree = "0.11.0"
base64 = "0.12.3" base64 = "0.12.3"
sodiumoxide = "0.2.6"

View File

@@ -456,8 +456,8 @@ The modules that ship with Scryer Prolog are also called
Cryptographically secure random numbers and hashes, HMAC-based key Cryptographically secure random numbers and hashes, HMAC-based key
derivation (HKDF), password-based key derivation (PBKDF2), derivation (HKDF), password-based key derivation (PBKDF2),
public key signatures and signature verification with Ed25519, public key signatures and signature verification with Ed25519,
authenticated symmetric encryption with ChaCha20-Poly1305, and ECDH key exchange over Curve25519 (X25519), authenticated symmetric
reasoning about elliptic curves. encryption with ChaCha20-Poly1305, and reasoning about elliptic curves.
To use predicates provided by the `lists` library, write: To use predicates provided by the `lists` library, write:

View File

@@ -309,6 +309,7 @@ pub enum SystemClauseType {
Ed25519Verify, Ed25519Verify,
Ed25519NewKeyPair, Ed25519NewKeyPair,
Ed25519KeyPairPublicKey, Ed25519KeyPairPublicKey,
Curve25519ScalarMult,
LoadHTML, LoadHTML,
LoadXML, LoadXML,
GetEnv, GetEnv,
@@ -522,6 +523,7 @@ impl SystemClauseType {
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"), &SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"), &SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"), &SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
&SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
&SystemClauseType::LoadHTML => clause_name!("$load_html"), &SystemClauseType::LoadHTML => clause_name!("$load_html"),
&SystemClauseType::LoadXML => clause_name!("$load_xml"), &SystemClauseType::LoadXML => clause_name!("$load_xml"),
&SystemClauseType::GetEnv => clause_name!("$getenv"), &SystemClauseType::GetEnv => clause_name!("$getenv"),
@@ -715,6 +717,7 @@ impl SystemClauseType {
("$ed25519_verify", 5) => Some(SystemClauseType::Ed25519Verify), ("$ed25519_verify", 5) => Some(SystemClauseType::Ed25519Verify),
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair), ("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
("$ed25519_keypair_public_key", 3) => Some(SystemClauseType::Ed25519KeyPairPublicKey), ("$ed25519_keypair_public_key", 3) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult),
("$load_html", 3) => Some(SystemClauseType::LoadHTML), ("$load_html", 3) => Some(SystemClauseType::LoadHTML),
("$load_xml", 3) => Some(SystemClauseType::LoadXML), ("$load_xml", 3) => Some(SystemClauseType::LoadXML),
("$getenv", 2) => Some(SystemClauseType::GetEnv), ("$getenv", 2) => Some(SystemClauseType::GetEnv),

View File

@@ -29,6 +29,8 @@
ed25519_keypair_public_key/2, % +KeyPair, +PublicKey ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
ed25519_verify/4, % +PublicKey, +Data, +Signature, +Options ed25519_verify/4, % +PublicKey, +Data, +Signature, +Options
curve25519_generator/1, % -Generator
curve25519_scalar_mult/3, % +Scalar, +Point, -Result
crypto_name_curve/2, % +Name, -Curve crypto_name_curve/2, % +Name, -Curve
crypto_curve_order/2, % +Curve, -Order crypto_curve_order/2, % +Curve, -Order
crypto_curve_generator/2, % +Curve, -Generator crypto_curve_generator/2, % +Curve, -Generator
@@ -43,6 +45,7 @@
:- use_module(library(arithmetic)). :- use_module(library(arithmetic)).
:- use_module(library(format)). :- use_module(library(format)).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(si)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hex_bytes(?Hex, ?Bytes) is det. hex_bytes(?Hex, ?Bytes) is det.
@@ -648,6 +651,62 @@ ed25519_verify(Key, Data0, Signature0, Options) :-
hex_bytes(Signature0, Signature), hex_bytes(Signature0, Signature),
'$ed25519_verify'(Key, octet, Data, Encoding, Signature). '$ed25519_verify'(Key, octet, Data, Encoding, Signature).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
X25519: ECDH key exchange over Curve25519
=========================================
Points on Curve25519 are represented as lists of characters that denote
the u-coordinate of the Montgomery curve.
- curve25519_generator(-Gs)
Gs is the generator point of Curve25519.
- curve25519_scalar_mult(+Scalar, +Ps, -Rs)
Scalar must be an integer between 0 and 2^256-1,
or a list of 32 bytes, and Ps must be a point on the curve.
Computes the point Rs = Scalar*Ps as mandated by X25519.
Alice and Bob can use this to establish a shared secret as follows,
where Gs is the generator point of Curve25519:
1. Alice creates a random integer a and sends As = a*Gs to Bob.
2. Bob creates a random integer b and sends Bs = b*Gs to Alice.
3. Alice computes Rs = a*Bs.
4. Bob computes Rs = b*As.
5. Alice and Bob use crypto_data_hkdf/4 on Rs with suitable
(same) parameters to obtain lists of bytes that can be used as
keys and initialization vectors for symmetric encryption.
If a and b are kept secret, this method is considered very secure.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
curve25519_generator(Gs) :-
length(Gs0, 32),
Gs0 = [9|Zs],
maplist(=(0), Zs),
maplist(char_code, Gs, Gs0).
curve25519_scalar_mult(Scalar, Point, Result) :-
( integer_si(Scalar) ->
Scalar #>= 0,
Scalar #< 2^256,
length(ScalarBytes, 32),
bytes_integer(ScalarBytes, Scalar)
; ScalarBytes = Scalar,
must_be_bytes(ScalarBytes, curve25519_scalar_mult/3),
length(ScalarBytes, 32)
),
maplist(char_code, Point, PointBytes),
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
bytes_integer(Bs, N) :-
foldl(pow, Bs, 0-0, N-_).
pow(B, N0-I0, N-I) :-
B in 0..255,
N #= N0 + B*256^I0,
I #= I0 + 1.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Operations on Elliptic Curves Operations on Elliptic Curves
============================= =============================
@@ -663,6 +722,7 @@ ed25519_verify(Key, Data0, Signature0, Options) :-
crypto_curve_scalar_mult(C, Random, PublicKey, S), crypto_curve_scalar_mult(C, Random, PublicKey, S),
crypto_curve_scalar_mult(C, PrivateKey, R, S). crypto_curve_scalar_mult(C, PrivateKey, R, S).
For better security, new code should use Curve25519 instead.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -51,6 +51,8 @@ use crate::openssl::ec::{EcGroup, EcPoint};
use crate::openssl::bn::{BigNum, BigNumContext}; use crate::openssl::bn::{BigNum, BigNumContext};
use crate::openssl::nid::Nid; use crate::openssl::nid::Nid;
use sodiumoxide::crypto::scalarmult::curve25519::*;
use crate::native_tls::TlsConnector; use crate::native_tls::TlsConnector;
extern crate select; extern crate select;
@@ -5706,6 +5708,24 @@ impl MachineState {
_ => { self.fail = true; return Ok(()); } _ => { self.fail = true; return Ok(()); }
} }
} }
&SystemClauseType::Curve25519ScalarMult => {
let stub1 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3);
let scalar_bytes = self.integers_to_bytevec(temp_v!(1), stub1);
let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
let stub2 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3);
let point_bytes = self.integers_to_bytevec(temp_v!(2), stub2);
let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
let result = scalarmult(&scalar, &point).unwrap();
let mut string = String::new();
for c in result[..].iter() {
string.push(*c as char);
}
let cstr = self.heap.put_complete_string(&string);
self.unify(self[temp_v!(3)], cstr);
}
&SystemClauseType::LoadHTML => { &SystemClauseType::LoadHTML => {
let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
let doc = select::document::Document::from_read(string.as_bytes()).unwrap(); let doc = select::document::Document::from_read(string.as_bytes()).unwrap();