aboutsummaryrefslogtreecommitdiffstats
path: root/jni/ed25519/additions
diff options
context:
space:
mode:
authorMoxie Marlinspike <moxie@thoughtcrime.org>2014-11-24 12:54:30 -0800
committerMoxie Marlinspike <moxie@thoughtcrime.org>2014-11-24 12:54:30 -0800
commit60800e155612bea797eed93c67046a23d26054cc (patch)
treed88368c1c26162e27e790195133ca2b526597afe /jni/ed25519/additions
Break out into separate repo.
Diffstat (limited to 'jni/ed25519/additions')
-rw-r--r--jni/ed25519/additions/compare.c44
-rw-r--r--jni/ed25519/additions/compare.h6
-rw-r--r--jni/ed25519/additions/crypto_hash_sha512.h6
-rw-r--r--jni/ed25519/additions/curve_sigs.c116
-rw-r--r--jni/ed25519/additions/curve_sigs.h50
-rw-r--r--jni/ed25519/additions/sign_modified.c47
-rw-r--r--jni/ed25519/additions/zeroize.c17
-rw-r--r--jni/ed25519/additions/zeroize.h12
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