Add functions for signing and verifying messages using curve25519 keys

This commit is contained in:
Mark Haines 2015-03-03 11:18:07 +00:00
parent 3ce450fc19
commit 315caaba7e
8 changed files with 176 additions and 3 deletions

View file

@ -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 { struct Aes256Key {
static const int LENGTH = 32; static const int LENGTH = 32;
std::uint8_t key[32]; std::uint8_t key[32];

View file

@ -1,6 +1,8 @@
#include "fixedint.h" #include "fixedint.h"
#include "fe.h" #include "fe.h"
#ifndef ED25519_LOAD_BYTES
#define ED25519_LOAD_BYTES
/* /*
helper functions helper functions
@ -26,7 +28,7 @@ static uint64_t load_4(const unsigned char *in) {
return result; return result;
} }
#endif
/* /*
h = 0 h = 0

View file

@ -1,6 +1,9 @@
#include "fixedint.h" #include "fixedint.h"
#include "sc.h" #include "sc.h"
#ifndef ED25519_LOAD_BYTES
#define ED25519_LOAD_BYTES
static uint64_t load_3(const unsigned char *in) { static uint64_t load_3(const unsigned char *in) {
uint64_t result; uint64_t result;
@ -22,6 +25,8 @@ static uint64_t load_4(const unsigned char *in) {
return result; return result;
} }
#endif
/* /*
Input: Input:
s[0]+256*s[1]+...+256^63*s[63] = s s[0]+256*s[1]+...+256^63*s[63] = s

43
lib/ed25519_additions.c Normal file
View file

@ -0,0 +1,43 @@
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);
}

View file

@ -28,6 +28,38 @@ int curve25519_donna(
#include "crypto-algorithms/aes.h" #include "crypto-algorithms/aes.h"
#include "crypto-algorithms/sha256.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 axolotl::aes_encrypt_cbc_length(
std::size_t input_length std::size_t input_length
) { ) {

View file

@ -16,4 +16,12 @@ extern "C" {
#include "crypto-algorithms/sha256.c" #include "crypto-algorithms/sha256.c"
#include "crypto-algorithms/aes.c" #include "crypto-algorithms/aes.c"
#include "curve25519-donna/curve25519-donna.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"
} }

View file

@ -23,10 +23,10 @@ if not os.path.exists("build"):
test_files = glob.glob("tests/test_*.cpp") test_files = glob.glob("tests/test_*.cpp")
source_files = glob.glob("src/*.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 compile_args += source_files
for test_file in test_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(compile_args + [test_file, "-o", exe_file])
subprocess.check_call([exe_file]) subprocess.check_call([exe_file])

View file

@ -83,6 +83,35 @@ assert_equals(expected_agreement, actual_agreement, 32);
} /* Curve25529 Test Case 1 */ } /* 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 */ { /* AES Test Case 1 */
TestCase test_case("AES Test Case 1"); TestCase test_case("AES Test Case 1");