diff options
author | Moxie Marlinspike <moxie@thoughtcrime.org> | 2014-11-24 12:54:30 -0800 |
---|---|---|
committer | Moxie Marlinspike <moxie@thoughtcrime.org> | 2014-11-24 12:54:30 -0800 |
commit | 60800e155612bea797eed93c67046a23d26054cc (patch) | |
tree | d88368c1c26162e27e790195133ca2b526597afe /jni/ed25519/additions |
Break out into separate repo.
Diffstat (limited to 'jni/ed25519/additions')
-rw-r--r-- | jni/ed25519/additions/compare.c | 44 | ||||
-rw-r--r-- | jni/ed25519/additions/compare.h | 6 | ||||
-rw-r--r-- | jni/ed25519/additions/crypto_hash_sha512.h | 6 | ||||
-rw-r--r-- | jni/ed25519/additions/curve_sigs.c | 116 | ||||
-rw-r--r-- | jni/ed25519/additions/curve_sigs.h | 50 | ||||
-rw-r--r-- | jni/ed25519/additions/sign_modified.c | 47 | ||||
-rw-r--r-- | jni/ed25519/additions/zeroize.c | 17 | ||||
-rw-r--r-- | jni/ed25519/additions/zeroize.h | 12 |
8 files changed, 298 insertions, 0 deletions
diff --git a/jni/ed25519/additions/compare.c b/jni/ed25519/additions/compare.c new file mode 100644 index 00000000..8b1e3138 --- /dev/null +++ b/jni/ed25519/additions/compare.c @@ -0,0 +1,44 @@ +#include <string.h> +#include "compare.h" + +/* Const-time comparison from SUPERCOP, but here it's only used for + signature verification, so doesn't need to be const-time. But + copied the nacl version anyways. */ +int crypto_verify_32_ref(const unsigned char *x, const unsigned char *y) +{ + unsigned int differentbits = 0; +#define F(i) differentbits |= x[i] ^ y[i]; + F(0) + F(1) + F(2) + F(3) + F(4) + F(5) + F(6) + F(7) + F(8) + F(9) + F(10) + F(11) + F(12) + F(13) + F(14) + F(15) + F(16) + F(17) + F(18) + F(19) + F(20) + F(21) + F(22) + F(23) + F(24) + F(25) + F(26) + F(27) + F(28) + F(29) + F(30) + F(31) + return (1 & ((differentbits - 1) >> 8)) - 1; +} diff --git a/jni/ed25519/additions/compare.h b/jni/ed25519/additions/compare.h new file mode 100644 index 00000000..5a2fa910 --- /dev/null +++ b/jni/ed25519/additions/compare.h @@ -0,0 +1,6 @@ +#ifndef __COMPARE_H__ +#define __COMPARE_H__ + +int crypto_verify_32_ref(const unsigned char *b1, const unsigned char *b2); + +#endif diff --git a/jni/ed25519/additions/crypto_hash_sha512.h b/jni/ed25519/additions/crypto_hash_sha512.h new file mode 100644 index 00000000..a51a190d --- /dev/null +++ b/jni/ed25519/additions/crypto_hash_sha512.h @@ -0,0 +1,6 @@ +#ifndef crypto_hash_sha512_H +#define crypto_hash_sha512_H + +extern int crypto_hash_sha512(unsigned char *,const unsigned char *,unsigned long long); + +#endif diff --git a/jni/ed25519/additions/curve_sigs.c b/jni/ed25519/additions/curve_sigs.c new file mode 100644 index 00000000..51f2052d --- /dev/null +++ b/jni/ed25519/additions/curve_sigs.c @@ -0,0 +1,116 @@ +#include <string.h> +#include "ge.h" +#include "curve_sigs.h" +#include "crypto_sign.h" + +void curve25519_keygen(unsigned char* curve25519_pubkey_out, + const unsigned char* curve25519_privkey_in) +{ + ge_p3 ed; /* Ed25519 pubkey point */ + fe ed_y, ed_y_plus_one, one_minus_ed_y, inv_one_minus_ed_y; + fe mont_x; + + /* Perform a fixed-base multiplication of the Edwards base point, + (which is efficient due to precalculated tables), then convert + to the Curve25519 montgomery-format public key. In particular, + convert Curve25519's "montgomery" x-coordinate into an Ed25519 + "edwards" y-coordinate: + + mont_x = (ed_y + 1) / (1 - ed_y) + + with projective coordinates: + + mont_x = (ed_y + ed_z) / (ed_z - ed_y) + + NOTE: ed_y=1 is converted to mont_x=0 since fe_invert is mod-exp + */ + + ge_scalarmult_base(&ed, curve25519_privkey_in); + fe_add(ed_y_plus_one, ed.Y, ed.Z); + fe_sub(one_minus_ed_y, ed.Z, ed.Y); + fe_invert(inv_one_minus_ed_y, one_minus_ed_y); + fe_mul(mont_x, ed_y_plus_one, inv_one_minus_ed_y); + fe_tobytes(curve25519_pubkey_out, mont_x); +} + +int curve25519_sign(unsigned char* signature_out, + const unsigned char* curve25519_privkey, + const unsigned char* msg, const unsigned long msg_len, + const unsigned char* random) +{ + ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */ + unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */ + unsigned char sigbuf[MAX_MSG_LEN + 128]; /* working buffer */ + unsigned char sign_bit = 0; + + if (msg_len > MAX_MSG_LEN) { + memset(signature_out, 0, 64); + return -1; + } + + /* Convert the Curve25519 privkey to an Ed25519 public key */ + ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey); + ge_p3_tobytes(ed_pubkey, &ed_pubkey_point); + sign_bit = ed_pubkey[31] & 0x80; + + /* Perform an Ed25519 signature with explicit private key */ + crypto_sign_modified(sigbuf, msg, msg_len, curve25519_privkey, + ed_pubkey, random); + memmove(signature_out, sigbuf, 64); + + /* Encode the sign bit into signature (in unused high bit of S) */ + signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */ + signature_out[63] |= sign_bit; + return 0; +} + +int curve25519_verify(const unsigned char* signature, + const unsigned char* curve25519_pubkey, + const unsigned char* msg, const unsigned long msg_len) +{ + fe mont_x, mont_x_minus_one, mont_x_plus_one, inv_mont_x_plus_one; + fe one; + fe ed_y; + unsigned char ed_pubkey[32]; + unsigned long long some_retval; + unsigned char verifybuf[MAX_MSG_LEN + 64]; /* working buffer */ + unsigned char verifybuf2[MAX_MSG_LEN + 64]; /* working buffer #2 */ + + if (msg_len > MAX_MSG_LEN) { + return -1; + } + + /* Convert the Curve25519 public key into an Ed25519 public key. In + particular, convert Curve25519's "montgomery" x-coordinate into an + Ed25519 "edwards" y-coordinate: + + ed_y = (mont_x - 1) / (mont_x + 1) + + NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp + + Then move the sign bit into the pubkey from the signature. + */ + fe_frombytes(mont_x, curve25519_pubkey); + 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(ed_pubkey, ed_y); + + /* Copy the sign bit, and remove it from signature */ + ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */ + ed_pubkey[31] |= (signature[63] & 0x80); + memmove(verifybuf, signature, 64); + verifybuf[63] &= 0x7F; + + memmove(verifybuf+64, msg, msg_len); + + /* Then perform a normal Ed25519 verification, return 0 on success */ + /* The below call has a strange API: */ + /* verifybuf = R || S || message */ + /* verifybuf2 = internal to next call gets a copy of verifybuf, S gets + replaced with pubkey for hashing, then the whole thing gets zeroized + (if bad sig), or contains a copy of msg (good sig) */ + return crypto_sign_open(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey); +} diff --git a/jni/ed25519/additions/curve_sigs.h b/jni/ed25519/additions/curve_sigs.h new file mode 100644 index 00000000..cc462471 --- /dev/null +++ b/jni/ed25519/additions/curve_sigs.h @@ -0,0 +1,50 @@ + +#ifndef __CURVE_SIGS_H__ +#define __CURVE_SIGS_H__ + +#define MAX_MSG_LEN 256 + +void curve25519_keygen(unsigned char* curve25519_pubkey_out, /* 32 bytes */ + const unsigned char* curve25519_privkey_in); /* 32 bytes */ + +/* returns 0 on success */ +int curve25519_sign(unsigned char* signature_out, /* 64 bytes */ + const unsigned char* curve25519_privkey, /* 32 bytes */ + const unsigned char* msg, const unsigned long msg_len, + const unsigned char* random); /* 64 bytes */ + +/* returns 0 on success */ +int curve25519_verify(const unsigned char* signature, /* 64 bytes */ + const unsigned char* curve25519_pubkey, /* 32 bytes */ + const unsigned char* msg, const unsigned long msg_len); + +/* helper function - modified version of crypto_sign() to use + explicit private key. In particular: + + sk : private key + pk : public key + msg : message + prefix : 0xFE || [0xFF]*31 + random : 64 bytes random + q : main subgroup order + + The prefix is chosen to distinguish the two SHA512 uses below, since + prefix is an invalid encoding for R (it would encode a "field element" + of 2^255 - 2). 0xFF*32 is set aside for use in ECDH protocols, which + is why the first byte here ix 0xFE. + + sig_nonce = SHA512(prefix || sk || msg || random) % q + R = g^sig_nonce + M = SHA512(R || pk || m) + S = sig_nonce + (m * sk) + signature = (R || S) + */ +int crypto_sign_modified( + unsigned char *sm, + const unsigned char *m,unsigned long long mlen, + const unsigned char *sk, /* Curve/Ed25519 private key */ + const unsigned char *pk, /* Ed25519 public key */ + const unsigned char *random /* 64 bytes random to hash into nonce */ + ); + +#endif diff --git a/jni/ed25519/additions/sign_modified.c b/jni/ed25519/additions/sign_modified.c new file mode 100644 index 00000000..61332e70 --- /dev/null +++ b/jni/ed25519/additions/sign_modified.c @@ -0,0 +1,47 @@ +#include <string.h> +#include "crypto_sign.h" +#include "crypto_hash_sha512.h" +#include "ge.h" +#include "sc.h" +#include "zeroize.h" + +/* NEW: Compare to pristine crypto_sign() + Uses explicit private key for nonce derivation and as scalar, + instead of deriving both from a master key. +*/ +int crypto_sign_modified( + unsigned char *sm, + const unsigned char *m,unsigned long long mlen, + const unsigned char *sk, const unsigned char* pk, + const unsigned char* random +) +{ + unsigned char nonce[64]; + unsigned char hram[64]; + ge_p3 R; + int count=0; + + memmove(sm + 64,m,mlen); + memmove(sm + 32,sk,32); /* NEW: Use privkey directly for nonce derivation */ + + /* NEW : add prefix to separate hash uses - see .h */ + sm[0] = 0xFE; + for (count = 1; count < 32; count++) + sm[count] = 0xFF; + + /* NEW: add suffix of random data */ + memmove(sm + mlen + 64, random, 64); + + crypto_hash_sha512(nonce,sm,mlen + 128); + memmove(sm + 32,pk,32); + + sc_reduce(nonce); + ge_scalarmult_base(&R,nonce); + ge_p3_tobytes(sm,&R); + + crypto_hash_sha512(hram,sm,mlen + 64); + sc_reduce(hram); + sc_muladd(sm + 32,hram,sk,nonce); /* NEW: Use privkey directly */ + + return 0; +} diff --git a/jni/ed25519/additions/zeroize.c b/jni/ed25519/additions/zeroize.c new file mode 100644 index 00000000..37c1f708 --- /dev/null +++ b/jni/ed25519/additions/zeroize.c @@ -0,0 +1,17 @@ +#include "zeroize.h" + +void zeroize(unsigned char* b, size_t len) +{ + size_t count = 0; + unsigned long retval = 0; + volatile unsigned char *p = b; + + for (count = 0; count < len; count++) + p[count] = 0; +} + +void zeroize_stack() +{ + unsigned char m[ZEROIZE_STACK_SIZE]; + zeroize(m, sizeof m); +} diff --git a/jni/ed25519/additions/zeroize.h b/jni/ed25519/additions/zeroize.h new file mode 100644 index 00000000..80fcffb7 --- /dev/null +++ b/jni/ed25519/additions/zeroize.h @@ -0,0 +1,12 @@ +#ifndef __ZEROIZE_H__ +#define __ZEROIZE_H__ + +#include <stdlib.h> + +#define ZEROIZE_STACK_SIZE 2048 + +void zeroize(unsigned char* b, size_t len); + +void zeroize_stack(); + +#endif |