Commit 315caaba authored by Mark Haines's avatar Mark Haines
Browse files

Add functions for signing and verifying messages using curve25519 keys

parent 3ce450fc
......@@ -48,6 +48,25 @@ void curve25519_shared_secret(
);
/** Signs the message using our private key.
* The output buffer must be at least 64 bytes long. */
void curve25519_sign(
Curve25519KeyPair const & our_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t * output
);
/** Verify thei message using their public key.
* The signature input buffer must be 64 bytes long.
* Returns true if the signature is valid. */
bool curve25519_verify(
Curve25519PublicKey const & their_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature
);
struct Aes256Key {
static const int LENGTH = 32;
std::uint8_t key[32];
......
#include "fixedint.h"
#include "fe.h"
#ifndef ED25519_LOAD_BYTES
#define ED25519_LOAD_BYTES
/*
helper functions
......@@ -26,7 +28,7 @@ static uint64_t load_4(const unsigned char *in) {
return result;
}
#endif
/*
h = 0
......
#include "fixedint.h"
#include "sc.h"
#ifndef ED25519_LOAD_BYTES
#define ED25519_LOAD_BYTES
static uint64_t load_3(const unsigned char *in) {
uint64_t result;
......@@ -22,6 +25,8 @@ static uint64_t load_4(const unsigned char *in) {
return result;
}
#endif
/*
Input:
s[0]+256*s[1]+...+256^63*s[63] = s
......
void convert_curve25519_to_ed25519(
unsigned char * public_key,
unsigned char * signature
) {
fe mont_x, mont_x_minus_one, mont_x_plus_one, inv_mont_x_plus_one;
fe one;
fe ed_y;
fe_frombytes(mont_x, public_key);
fe_1(one);
fe_sub(mont_x_minus_one, mont_x, one);
fe_add(mont_x_plus_one, mont_x, one);
fe_invert(inv_mont_x_plus_one, mont_x_plus_one);
fe_mul(ed_y, mont_x_minus_one, inv_mont_x_plus_one);
fe_tobytes(public_key, ed_y);
public_key[31] &= 0x7F;
public_key[31] |= (signature[63] & 0x80);
signature[63] &= 0x7F;
}
void convert_ed25519_to_curve25519(
unsigned char const * public_key,
unsigned char * signature
) {
unsigned char sign_bit = public_key[31] & 0x80;
signature[63] &= 0x7F;
signature[63] |= sign_bit;
}
void ed25519_keypair(
unsigned char * private_key,
unsigned char * public_key
) {
ge_p3 A;
private_key[0] &= 248;
private_key[31] &= 63;
private_key[31] |= 64;
ge_scalarmult_base(&A, private_key);
ge_p3_tobytes(public_key, &A);
}
......@@ -28,6 +28,38 @@ int curve25519_donna(
#include "crypto-algorithms/aes.h"
#include "crypto-algorithms/sha256.h"
int ed25519_sign(
unsigned char *signature,
const unsigned char *message, size_t message_len,
const unsigned char *public_key,
const unsigned char *private_key
);
int ed25519_verify(
const unsigned char *signature,
const unsigned char *message, size_t message_len,
const unsigned char *public_key
);
void convert_curve25519_to_ed25519(
unsigned char * public_key,
unsigned char * signature
);
void convert_ed25519_to_curve25519(
unsigned char const * public_key,
unsigned char * signature
);
void ed25519_keypair(
unsigned char * private_key,
unsigned char * public_key
);
}
......@@ -124,6 +156,41 @@ void axolotl::curve25519_shared_secret(
}
void axolotl::curve25519_sign(
axolotl::Curve25519KeyPair const & our_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t * output
) {
std::uint8_t private_key[32];
std::uint8_t public_key[32];
std::memcpy(private_key, our_key.private_key, 32);
::ed25519_keypair(private_key, public_key);
::ed25519_sign(
output,
message, message_length,
public_key, private_key
);
::convert_ed25519_to_curve25519(public_key, output);
}
bool axolotl::curve25519_verify(
axolotl::Curve25519PublicKey const & their_key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature
) {
std::uint8_t public_key[32];
std::uint8_t signature_buffer[64];
std::memcpy(public_key, their_key.public_key, 32);
std::memcpy(signature_buffer, signature, 64);
::convert_curve25519_to_ed25519(public_key, signature_buffer);
return 0 != ::ed25519_verify(
signature,
message, message_length,
public_key
);
}
std::size_t axolotl::aes_encrypt_cbc_length(
std::size_t input_length
) {
......
......@@ -16,4 +16,12 @@ extern "C" {
#include "crypto-algorithms/sha256.c"
#include "crypto-algorithms/aes.c"
#include "curve25519-donna/curve25519-donna.c"
#define select ed25519_select
#include "ed25519/src/fe.c"
#include "ed25519/src/sc.c"
#include "ed25519/src/ge.c"
#include "ed25519/src/sha512.c"
#include "ed25519/src/verify.c"
#include "ed25519/src/sign.c"
#include "ed25519_additions.c"
}
......@@ -23,10 +23,10 @@ if not os.path.exists("build"):
test_files = glob.glob("tests/test_*.cpp")
source_files = glob.glob("src/*.cpp")
compile_args = "g++ -Itests/include -Iinclude -Ilib --std=c++11".split()
compile_args = "g++ -g -O0 -Itests/include -Iinclude -Ilib --std=c++11".split()
compile_args += source_files
for test_file in test_files:
exe_file = "build/" + test_file[:4]
exe_file = "build/" + test_file[5:-4]
subprocess.check_call(compile_args + [test_file, "-o", exe_file])
subprocess.check_call([exe_file])
......@@ -83,6 +83,35 @@ assert_equals(expected_agreement, actual_agreement, 32);
} /* Curve25529 Test Case 1 */
{ /* Signature Test Cast 1 */
TestCase test_case("Signature Test Case 1");
std::uint8_t private_key[33] = "This key is a string of 32 bytes";
std::uint8_t message[] = "message";
std::size_t message_length = sizeof(message) - 1;
axolotl::Curve25519KeyPair key_pair;
axolotl::generate_key(private_key, key_pair);
std::uint8_t signature[64];
axolotl::curve25519_sign(
key_pair, message, message_length, signature
);
bool result = axolotl::curve25519_verify(
key_pair, message, message_length, signature
);
assert_equals(true, result);
message[0] = 'n';
result = axolotl::curve25519_verify(
key_pair, message, message_length, signature
);
assert_equals(false, result);
} /* Signature Test Cast 1 */
{ /* AES Test Case 1 */
TestCase test_case("AES Test Case 1");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment