added key exchange

This commit is contained in:
Orson Peters 2013-03-24 22:37:43 +01:00
parent 2e17ca4ed8
commit ae9d05be04
5 changed files with 150 additions and 15 deletions

Binary file not shown.

View File

@ -2,24 +2,29 @@ Ed25519
======= =======
This is a portable implementation of [Ed25519](http://ed25519.cr.yp.to/) based This is a portable implementation of [Ed25519](http://ed25519.cr.yp.to/) based
on the SUPERCOP "ref10" implementation. All code is in the public domain. on the SUPERCOP "ref10" implementation. Additionally there is key exchanging
and scalar addition included to further aid building a PKI using Ed25519. All
code is in the public domain.
All code is pure ANSI C without any dependencies, except for the random seed All code is pure ANSI C without any dependencies, except for the random seed
generation which uses standard OS cryptography APIs (`CryptGenRandom` on Windows, `/dev/urandom` on *nix). If you wish to be entirely generation which uses standard OS cryptography APIs (`CryptGenRandom` on
portable define `ED25519_NO_SEED`. This disables the `ed25519_create_seed` Windows, `/dev/urandom` on nix). If you wish to be entirely portable define
function, so if your application requires key generation you must supply your `ED25519_NO_SEED`. This disables the `ed25519_create_seed` function, so if your
own seeding function (which is simply a 32 byte cryptographic random number generator). application requires key generation you must supply your own seeding function
(which is simply a 256 byte cryptographic random number generator).
Performance Performance
----------- -----------
On a machine with an Intel Pentium B970 @ 2.3GHz I got the following speeds (running On a Windows machine with an Intel Pentium B970 @ 2.3GHz I got the following
on only one a single core): speeds (running on only one a single core):
Seed + key generation: 345us Seed + key generation: 489us
Message signing (short message): 256us Message signing (short message): 251us
Message verifying (short message): 777us Message verifying (short message): 772us
Scalar addition: 358us
Key exchange: 724us
The speeds on other machines may vary. Sign/verify times will be higher with The speeds on other machines may vary. Sign/verify times will be higher with
longer messages. longer messages.
@ -33,8 +38,9 @@ Simply add all .c and .h files in the `src/` folder to your project and include
library, only copy `ed25519.h` and define `ED25519_DLL` before importing. A library, only copy `ed25519.h` and define `ED25519_DLL` before importing. A
windows DLL is pre-built. windows DLL is pre-built.
There are no defined types for seeds, private keys, public keys or signatures. There are no defined types for seeds, private keys, public keys, shared secrets
Instead simple `unsigned char` buffers are used with the following sizes: or signatures. Instead simple `unsigned char` buffers are used with the
following sizes:
```c ```c
unsigned char seed[32]; unsigned char seed[32];
@ -42,6 +48,7 @@ unsigned char signature[64];
unsigned char public_key[32]; unsigned char public_key[32];
unsigned char private_key[64]; unsigned char private_key[64];
unsigned char scalar[32]; unsigned char scalar[32];
unsigned char shared_secret[32];
``` ```
API API
@ -91,12 +98,24 @@ Adds `scalar` to the given key pair where scalar is a 32 byte buffer (possibly
generated with `ed25519_create_seed`), generating a new key pair. You can generated with `ed25519_create_seed`), generating a new key pair. You can
calculate the public key sum without knowing the private key and vice versa by calculate the public key sum without knowing the private key and vice versa by
passing in `NULL` for the key you don't know. This is useful for enforcing passing in `NULL` for the key you don't know. This is useful for enforcing
randomness on a key pair while only knowing the public key, among other things. randomness on a key pair by a third party while only knowing the public key,
Warning: the last bit of the scalar is ignored - if comparing scalars make sure among other things. Warning: the last bit of the scalar is ignored - if
to clear it with `scalar[31] &= 127`. comparing scalars make sure to clear it with `scalar[31] &= 127`.
```c
void ed25519_key_exchange(unsigned char *shared_secret,
const unsigned char *public_key, const unsigned char *private_key);
```
Performs a key exchange on the given public key and private key, producing a
shared secret. It is recommended to hash the shared secret before using it.
`shared_secret` must be a 32 byte writable buffer where the shared secret will
be stored.
Example Example
------- -------
```c ```c
unsigned char seed[32], public_key[32], private_key[64], signature[64]; unsigned char seed[32], public_key[32], private_key[64], signature[64];
const unsigned char message[] = "TEST MESSAGE"; const unsigned char message[] = "TEST MESSAGE";
@ -119,3 +138,7 @@ if (ed25519_verify(signature, message, strlen(message), public_key)) {
printf("invalid signature\n"); printf("invalid signature\n");
} }
``` ```
License
-------
All code is in the public domain.

View File

@ -28,6 +28,7 @@ void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key); void ED25519_DECLSPEC 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_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key); int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key);
void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar); void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
#ifdef __cplusplus #ifdef __cplusplus

79
src/key_exchange.c Normal file
View File

@ -0,0 +1,79 @@
#include "ed25519.h"
#include "fe.h"
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
unsigned char e[32];
unsigned int i;
fe x1;
fe x2;
fe z2;
fe x3;
fe z3;
fe tmp0;
fe tmp1;
int pos;
unsigned int swap;
unsigned int b;
/* copy the private key and make sure it's valid */
for (i = 0; i < 32; ++i) {
e[i] = private_key[i];
}
e[0] &= 248;
e[31] &= 63;
e[31] |= 64;
/* unpack the public key and convert edwards to montgomery */
/* due to CodesInChaos */
fe_frombytes(x1, public_key);
fe_1(tmp1);
fe_add(tmp0, x1, tmp1);
fe_sub(tmp1, tmp1, x1);
fe_invert(tmp1, tmp1);
fe_mul(x1, tmp0, tmp1);
fe_1(x2);
fe_0(z2);
fe_copy(x3, x1);
fe_1(z3);
swap = 0;
for (pos = 254; pos >= 0; --pos) {
b = e[pos / 8] >> (pos & 7);
b &= 1;
swap ^= b;
fe_cswap(x2, x3, swap);
fe_cswap(z2, z3, swap);
swap = b;
/* from montgomery.h */
fe_sub(tmp0, x3, z3);
fe_sub(tmp1, x2, z2);
fe_add(x2, x2, z2);
fe_add(z2, x3, z3);
fe_mul(z3, tmp0, x2);
fe_mul(z2, z2, tmp1);
fe_sq(tmp0, tmp1);
fe_sq(tmp1, x2);
fe_add(x3, z3, z2);
fe_sub(z2, z3, z2);
fe_mul(x2, tmp1, tmp0);
fe_sub(tmp1, tmp1, tmp0);
fe_sq(z2, z2);
fe_mul121666(z3, tmp1);
fe_sq(x3, x3);
fe_add(tmp0, tmp0, z3);
fe_mul(z3, x1, z2);
fe_mul(z2, tmp1, tmp0);
}
fe_cswap(x2, x3, swap);
fe_cswap(z2, z3, swap);
fe_invert(z2, z2);
fe_mul(x2, x2, z2);
fe_tobytes(shared_secret, x2);
}

32
test.c
View File

@ -14,6 +14,8 @@ const char message[] = "Hello, world!";
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
unsigned char public_key[32], private_key[64], seed[32], scalar[32]; unsigned char public_key[32], private_key[64], seed[32], scalar[32];
unsigned char other_public_key[32], other_private_key[64];
unsigned char shared_secret[32], other_shared_secret[32];
unsigned char signature[64]; unsigned char signature[64];
clock_t start; clock_t start;
@ -56,6 +58,27 @@ int main(int argc, char *argv[]) {
printf("correctly detected signature change\n"); printf("correctly detected signature change\n");
} }
/* generate two keypairs for testing key exchange */
ed25519_create_seed(seed);
ed25519_create_keypair(public_key, private_key, seed);
ed25519_create_seed(seed);
ed25519_create_keypair(other_public_key, other_private_key, seed);
/* create two shared secrets - from both perspectives - and check if they're equal */
ed25519_key_exchange(shared_secret, other_public_key, private_key);
ed25519_key_exchange(other_shared_secret, public_key, other_private_key);
for (i = 0; i < 32; ++i) {
if (shared_secret[i] != other_shared_secret[i]) {
printf("key exchange was incorrect\n");
break;
}
}
if (i == 32) {
printf("key exchange was correct\n");
}
/* test performance */ /* test performance */
printf("testing key generation performance: "); printf("testing key generation performance: ");
start = clock(); start = clock();
@ -93,6 +116,15 @@ int main(int argc, char *argv[]) {
} }
end = clock(); end = clock();
printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
printf("testing key exchange performance: ");
start = clock();
for (i = 0; i < 10000; ++i) {
ed25519_key_exchange(shared_secret, other_public_key, private_key);
}
end = clock();
printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000);
return 0; return 0;