From 315caaba7e83eb6680a0407ea13e04b5f7739788 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Tue, 3 Mar 2015 11:18:07 +0000 Subject: Add functions for signing and verifying messages using curve25519 keys --- include/axolotl/crypto.hh | 19 ++++++++++++++ lib/ed25519/src/fe.c | 4 ++- lib/ed25519/src/sc.c | 5 ++++ lib/ed25519_additions.c | 43 ++++++++++++++++++++++++++++++ src/crypto.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++ src/libs.cpp | 8 ++++++ test.py | 4 +-- tests/test_crypto.cpp | 29 ++++++++++++++++++++ 8 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 lib/ed25519_additions.c diff --git a/include/axolotl/crypto.hh b/include/axolotl/crypto.hh index 162099f..d772f46 100644 --- a/include/axolotl/crypto.hh +++ b/include/axolotl/crypto.hh @@ -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]; diff --git a/lib/ed25519/src/fe.c b/lib/ed25519/src/fe.c index 448e3e9..07f9f05 100644 --- a/lib/ed25519/src/fe.c +++ b/lib/ed25519/src/fe.c @@ -1,6 +1,8 @@ #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 diff --git a/lib/ed25519/src/sc.c b/lib/ed25519/src/sc.c index ca5bad2..a883907 100644 --- a/lib/ed25519/src/sc.c +++ b/lib/ed25519/src/sc.c @@ -1,6 +1,9 @@ #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 diff --git a/lib/ed25519_additions.c b/lib/ed25519_additions.c new file mode 100644 index 0000000..5fa0c68 --- /dev/null +++ b/lib/ed25519_additions.c @@ -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); +} diff --git a/src/crypto.cpp b/src/crypto.cpp index 57f31cd..24a8136 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -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 ) { diff --git a/src/libs.cpp b/src/libs.cpp index 61bb86c..6757574 100644 --- a/src/libs.cpp +++ b/src/libs.cpp @@ -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" } diff --git a/test.py b/test.py index 336591c..06d4552 100755 --- a/test.py +++ b/test.py @@ -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]) diff --git a/tests/test_crypto.cpp b/tests/test_crypto.cpp index 1c068c4..3ec5360 100644 --- a/tests/test_crypto.cpp +++ b/tests/test_crypto.cpp @@ -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"); -- cgit v1.2.3