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
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
generation which uses standard OS cryptography APIs (`CryptGenRandom` on Windows, `/dev/urandom` on *nix). If you wish to be entirely
portable define `ED25519_NO_SEED`. This disables the `ed25519_create_seed`
function, so if your application requires key generation you must supply your
own seeding function (which is simply a 32 byte cryptographic random number generator).
generation which uses standard OS cryptography APIs (`CryptGenRandom` on
Windows, `/dev/urandom` on nix). If you wish to be entirely portable define
`ED25519_NO_SEED`. This disables the `ed25519_create_seed` function, so if your
application requires key generation you must supply your own seeding function
(which is simply a 256 byte cryptographic random number generator).
Performance
-----------
On a machine with an Intel Pentium B970 @ 2.3GHz I got the following speeds (running
on only one a single core):
On a Windows machine with an Intel Pentium B970 @ 2.3GHz I got the following
speeds (running on only one a single core):
Seed + key generation: 345us
Message signing (short message): 256us
Message verifying (short message): 777us
Seed + key generation: 489us
Message signing (short message): 251us
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
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
windows DLL is pre-built.
There are no defined types for seeds, private keys, public keys or signatures.
Instead simple `unsigned char` buffers are used with the following sizes:
There are no defined types for seeds, private keys, public keys, shared secrets
or signatures. Instead simple `unsigned char` buffers are used with the
following sizes:
```c
unsigned char seed[32];
@ -42,6 +48,7 @@ unsigned char signature[64];
unsigned char public_key[32];
unsigned char private_key[64];
unsigned char scalar[32];
unsigned char shared_secret[32];
```
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
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
randomness on a key pair while only knowing the public key, among other things.
Warning: the last bit of the scalar is ignored - if comparing scalars make sure
to clear it with `scalar[31] &= 127`.
randomness on a key pair by a third party while only knowing the public key,
among other things. Warning: the last bit of the scalar is ignored - if
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
-------
```c
unsigned char seed[32], public_key[32], private_key[64], signature[64];
const unsigned char message[] = "TEST MESSAGE";
@ -119,3 +138,7 @@ if (ed25519_verify(signature, message, strlen(message), public_key)) {
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);
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_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
#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[]) {
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];
clock_t start;
@ -56,6 +58,27 @@ int main(int argc, char *argv[]) {
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 */
printf("testing key generation performance: ");
start = clock();
@ -93,6 +116,15 @@ int main(int argc, char *argv[]) {
}
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);
return 0;