diff options
author | Richard van der Hoff <richard@matrix.org> | 2016-09-01 13:35:23 +0100 |
---|---|---|
committer | Richard van der Hoff <richard@matrix.org> | 2016-09-01 13:35:23 +0100 |
commit | 0c462cff112589fc52d13da6c919f881cb6d3f8c (patch) | |
tree | 9c71802ce0d583856b7cd47bfcf20cdfa05354ba /src | |
parent | f03febb772c47855ab748ed6dee2f29db9f9c5ba (diff) |
Fix Ed25519 keypair generation
Ed25519 private keys, it turns out, have 64 bytes, not 32.
We were previously generating only 32 bytes (which is all that is required to
generate the public key), and then using the public key as the upper 32 bytes
when generating the per-message session key. This meant that everything
appeared to work, but the security of the private key was severely compromised.
By way of fixes:
* Use the correct algorithm for generating the Ed25519 private key, and store
all 512 bits of it.
* Update the account pickle format and refuse to load the old format (since we
should consider it compromised).
* Bump the library version, and add a function to retrieve the library
version, so that applications can verify that they are linked against a
fixed version of the library.
* Remove the curve25519_{sign, verify} functions which were unused and of
dubious quality.
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cpp | 16 | ||||
-rw-r--r-- | src/crypto.cpp | 43 | ||||
-rw-r--r-- | src/ed25519.c | 2 | ||||
-rw-r--r-- | src/error.c | 1 | ||||
-rw-r--r-- | src/olm.cpp | 5 |
5 files changed, 23 insertions, 44 deletions
diff --git a/src/account.cpp b/src/account.cpp index c8e6e40..ec763f8 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -326,7 +326,9 @@ static std::uint8_t const * unpickle( } // namespace olm namespace { -static const std::uint32_t ACCOUNT_PICKLE_VERSION = 1; +// pickle version 1 used only 32 bytes for the ed25519 private key. +// Any keys thus used should be considered compromised. +static const std::uint32_t ACCOUNT_PICKLE_VERSION = 2; } @@ -360,9 +362,15 @@ std::uint8_t const * olm::unpickle( ) { uint32_t pickle_version; pos = olm::unpickle(pos, end, pickle_version); - if (pickle_version != ACCOUNT_PICKLE_VERSION) { - value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION; - return end; + switch (pickle_version) { + case ACCOUNT_PICKLE_VERSION: + break; + case 1: + value.last_error = OlmErrorCode::OLM_BAD_LEGACY_ACCOUNT_PICKLE; + return end; + default: + value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION; + return end; } pos = olm::unpickle(pos, end, value.identity_keys); pos = olm::unpickle(pos, end, value.one_time_keys); diff --git a/src/crypto.cpp b/src/crypto.cpp index 4fa92f1..83493be 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -25,7 +25,6 @@ extern "C" { } #include "ed25519/src/ed25519.h" -#include "ed25519_additions.h" #include "curve25519-donna.h" namespace { @@ -121,48 +120,14 @@ void olm::curve25519_shared_secret( } -void olm::curve25519_sign( - olm::Curve25519KeyPair const & our_key, - std::uint8_t const * message, std::size_t message_length, - std::uint8_t * output -) { - std::uint8_t private_key[KEY_LENGTH]; - std::uint8_t public_key[KEY_LENGTH]; - std::memcpy(private_key, our_key.private_key, KEY_LENGTH); - ::ed25519_keypair(private_key, public_key); - ::ed25519_sign( - output, - message, message_length, - public_key, private_key - ); - ::convert_ed25519_to_curve25519(public_key, output); -} - - -bool olm::curve25519_verify( - olm::Curve25519PublicKey const & their_key, - std::uint8_t const * message, std::size_t message_length, - std::uint8_t const * signature -) { - std::uint8_t public_key[KEY_LENGTH]; - std::uint8_t signature_buffer[SIGNATURE_LENGTH]; - std::memcpy(public_key, their_key.public_key, KEY_LENGTH); - std::memcpy(signature_buffer, signature, SIGNATURE_LENGTH); - ::convert_curve25519_to_ed25519(public_key, signature_buffer); - return 0 != ::ed25519_verify( - signature, - message, message_length, - public_key - ); -} - - void olm::ed25519_generate_key( std::uint8_t const * random_32_bytes, olm::Ed25519KeyPair & key_pair ) { - std::memcpy(key_pair.private_key, random_32_bytes, KEY_LENGTH); - ::ed25519_keypair(key_pair.private_key, key_pair.public_key); + ::ed25519_create_keypair( + key_pair.public_key, key_pair.private_key, + random_32_bytes + ); } diff --git a/src/ed25519.c b/src/ed25519.c index f4f910d..c7a1a8e 100644 --- a/src/ed25519.c +++ b/src/ed25519.c @@ -16,7 +16,7 @@ #include "ed25519/src/fe.c" #include "ed25519/src/sc.c" #include "ed25519/src/ge.c" +#include "ed25519/src/keypair.c" #include "ed25519/src/sha512.c" #include "ed25519/src/verify.c" #include "ed25519/src/sign.c" -#include "ed25519_additions.c" diff --git a/src/error.c b/src/error.c index bd8a39d..b742197 100644 --- a/src/error.c +++ b/src/error.c @@ -29,6 +29,7 @@ static const char * ERRORS[] = { "CORRUPTED_PICKLE", "BAD_SESSION_KEY", "UNKNOWN_MESSAGE_INDEX", + "BAD_LEGACY_ACCOUNT_PICKLE", }; const char * _olm_error_to_string(enum OlmErrorCode error) diff --git a/src/olm.cpp b/src/olm.cpp index 0a4a734..682a84c 100644 --- a/src/olm.cpp +++ b/src/olm.cpp @@ -98,6 +98,11 @@ std::size_t b64_input( extern "C" { +void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch) { + if (major != NULL) *major = OLMLIB_VERSION_MAJOR; + if (minor != NULL) *minor = OLMLIB_VERSION_MINOR; + if (patch != NULL) *patch = OLMLIB_VERSION_PATCH; +} size_t olm_error() { return std::size_t(-1); |