Skip to content

Commit

Permalink
Update to latest ref10-extract ed25519
Browse files Browse the repository at this point in the history
  • Loading branch information
moxie0 committed Oct 20, 2014
1 parent 5ea3b30 commit 1eb3884
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 54 deletions.
6 changes: 4 additions & 2 deletions libaxolotl/jni/curve25519-jni.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,19 @@ JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_c
}

JNIEXPORT jbyteArray JNICALL Java_org_whispersystems_libaxolotl_ecc_Curve25519_calculateSignature
(JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray message)
(JNIEnv *env, jclass clazz, jbyteArray random, jbyteArray privateKey, jbyteArray message)
{
jbyteArray signature = (*env)->NewByteArray(env, 64);
uint8_t* signatureBytes = (uint8_t*)(*env)->GetByteArrayElements(env, signature, 0);
uint8_t* randomBytes = (uint8_t*)(*env)->GetByteArrayElements(env, random, 0);
uint8_t* privateKeyBytes = (uint8_t*)(*env)->GetByteArrayElements(env, privateKey, 0);
uint8_t* messageBytes = (uint8_t*)(*env)->GetByteArrayElements(env, message, 0);
jsize messageLength = (*env)->GetArrayLength(env, message);

curve25519_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength);
curve25519_sign(signatureBytes, privateKeyBytes, messageBytes, messageLength, randomBytes);

(*env)->ReleaseByteArrayElements(env, signature, signatureBytes, 0);
(*env)->ReleaseByteArrayElements(env, random, randomBytes, 0);
(*env)->ReleaseByteArrayElements(env, privateKey, privateKeyBytes, 0);
(*env)->ReleaseByteArrayElements(env, message, messageBytes, 0);

Expand Down
57 changes: 30 additions & 27 deletions libaxolotl/jni/ed25519/additions/curve_sigs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
#include "crypto_sign.h"

void curve25519_keygen(unsigned char* curve25519_pubkey_out,
unsigned char* curve25519_privkey_in)
const unsigned char* curve25519_privkey_in)
{
ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */
unsigned char ed_pubkey[32]; /* privkey followed by pubkey */
fe ed_y, one, ed_y_plus_one, one_minus_ed_y, inv_one_minus_ed_y;
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,
Expand All @@ -17,49 +16,49 @@ void curve25519_keygen(unsigned char* curve25519_pubkey_out,
convert Curve25519's "montgomery" x-coordinate into an Ed25519
"edwards" y-coordinate:
mont_x = (ed_y +1 1) / (1 - ed_y)
*/
mont_x = (ed_y + 1) / (1 - ed_y)
with projective coordinates:
ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey_in);
ge_p3_tobytes(ed_pubkey, &ed_pubkey_point);
ed_pubkey[31] = ed_pubkey[31] & 0x7F; /* Mask off sign bit */
fe_frombytes(ed_y, ed_pubkey);
mont_x = (ed_y + ed_z) / (ed_z - ed_y)
*/

fe_1(one);
fe_add(ed_y_plus_one, ed_y, one);
fe_sub(one_minus_ed_y, one, ed_y);
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);
fe_tobytes(curve25519_pubkey_out, mont_x);
}

void curve25519_sign(unsigned char* signature_out,
unsigned char* curve25519_privkey,
unsigned char* msg, unsigned long msg_len)
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_keypair[64]; /* privkey followed by pubkey */
unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */
unsigned char sigbuf[msg_len + 64]; /* working buffer */
unsigned long long sigbuf_out_len = 0;
unsigned char sign_bit = 0;

/* Convert the Curve25519 privkey to an Ed25519 keypair */
memmove(ed_keypair, curve25519_privkey, 32);
/* Convert the Curve25519 privkey to an Ed25519 public key */
ge_scalarmult_base(&ed_pubkey_point, curve25519_privkey);
ge_p3_tobytes(ed_keypair + 32, &ed_pubkey_point);
sign_bit = ed_keypair[63] & 0x80;
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, &sigbuf_out_len, msg, msg_len, ed_keypair);
crypto_sign_modified(sigbuf, &sigbuf_out_len, 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] |= sign_bit;
}

int curve25519_verify(unsigned char* signature,
unsigned char* curve25519_pubkey,
unsigned char* msg, unsigned long msg_len)
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;
Expand Down Expand Up @@ -87,11 +86,15 @@ int curve25519_verify(unsigned char* signature,

/* Copy the sign bit, and remove it from signature */
ed_pubkey[31] |= (signature[63] & 0x80);
signature[63] &= 0x7F;

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 */
return crypto_sign_open(verifybuf2, &some_retval, verifybuf, 64 + msg_len, ed_pubkey);
}
41 changes: 31 additions & 10 deletions libaxolotl/jni/ed25519/additions/curve_sigs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,45 @@
#ifndef __CURVE_SIGS_H__
#define __CURVE_SIGS_H__

void curve25519_keygen(unsigned char* curve25519_pubkey_out,
unsigned char* curve25519_privkey_in);
void curve25519_keygen(unsigned char* curve25519_pubkey_out, /* 32 bytes */
const unsigned char* curve25519_privkey_in); /* 32 bytes */

void curve25519_sign(unsigned char* signature_out,
unsigned char* curve25519_privkey,
unsigned char* msg, unsigned long msg_len);
void 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(unsigned char* signature,
unsigned char* curve25519_pubkey,
unsigned char* msg, unsigned long msg_len);
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 */
explicit private key. In particular:
sk : private key
pk : public key
m : message
prefix : 0xFE || [0xFF]*31
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 = (random XOR SHA512(prefix || sk || m)) % 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,unsigned long long *smlen,
const unsigned char *m,unsigned long long mlen,
const unsigned char *sk
const unsigned char *sk, /* Curve/Ed25519 private key */
const unsigned char *pk, /* Ed25519 public key */
const unsigned char *random /* 64 bytes random to XOR into nonce */
);

#endif
3 changes: 2 additions & 1 deletion libaxolotl/jni/ed25519/additions/sha512.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "sha512.h"
#include "sph_sha2.h"
#include "zeroize.h"

int crypto_hash_sha512_ref(unsigned char *output ,const unsigned char *input,
unsigned long long len)
Expand All @@ -8,6 +9,6 @@ int crypto_hash_sha512_ref(unsigned char *output ,const unsigned char *input,
sph_sha512_init(&ctx);
sph_sha512(&ctx, input, len);
sph_sha512_close(&ctx, output);
zeroize((unsigned char*)&ctx, sizeof(ctx));
return 0;
}

27 changes: 21 additions & 6 deletions libaxolotl/jni/ed25519/additions/sign_modified.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#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,
Expand All @@ -11,23 +12,31 @@
int crypto_sign_modified(
unsigned char *sm,unsigned long long *smlen,
const unsigned char *m,unsigned long long mlen,
const unsigned char *sk
const unsigned char *sk, const unsigned char* pk,
const unsigned char* random
)
{
unsigned char pk[32];
unsigned char az[64];
unsigned char nonce[64];
unsigned char hram[64];
ge_p3 R;

memmove(pk,sk + 32,32);
int count=0;

*smlen = mlen + 64;
memmove(sm + 64,m,mlen);
memmove(sm + 32,sk,32); /* NEW: Use privkey directly for nonce derivation */
crypto_hash_sha512(nonce,sm + 32,mlen + 32);

/* NEW : add prefix to separate hash uses - see .h */
sm[0] = 0xFE;
for (count = 1; count < 32; count++)
sm[count] = 0xFF;

crypto_hash_sha512(nonce,sm,mlen + 64);
memmove(sm + 32,pk,32);

/* NEW: XOR random into nonce */
for (count=0; count < 64; count++)
nonce[count] ^= random[count];

sc_reduce(nonce);
ge_scalarmult_base(&R,nonce);
ge_p3_tobytes(sm,&R);
Expand All @@ -36,5 +45,11 @@ int crypto_sign_modified(
sc_reduce(hram);
sc_muladd(sm + 32,hram,sk,nonce); /* NEW: Use privkey directly */

/* NEW: Dummy call to hopefully erase any traces of privkey or
nonce left in the stack from prev call to this func. */
volatile unsigned char* p = sm+64;
sc_muladd(sm+64,hram,hram,hram);

zeroize(nonce, 64);
return 0;
}
10 changes: 10 additions & 0 deletions libaxolotl/jni/ed25519/additions/zeroize.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

void zeroize(unsigned char* b, unsigned long len)
{
unsigned long count = 0;
unsigned long retval = 0;
volatile unsigned char *p = b;

for (count = 0; count < len; count++)
p[count] = 0;
}
6 changes: 6 additions & 0 deletions libaxolotl/jni/ed25519/additions/zeroize.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __ZEROIZE_H__
#define __ZEROIZE_H__

void zeroize(unsigned char* b, unsigned long len);

#endif
76 changes: 70 additions & 6 deletions libaxolotl/jni/ed25519/main/main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <stdio.h>
#include <string.h>
#include "sha512.h"
#include "crypto_hash_sha512.h"
#include "curve_sigs.h"

int main(int argc, char* argv[])
Expand All @@ -10,6 +10,7 @@ int main(int argc, char* argv[])
unsigned char signature[64];
unsigned char msg[100];
unsigned long long msg_len = 100;
unsigned char random[64];

/* Initialize pubkey, privkey, msg */
memset(msg, 0, 100);
Expand All @@ -21,21 +22,84 @@ int main(int argc, char* argv[])

privkey[8] = 189; /* just so there's some bits set */


/* SHA512 test */
unsigned char sha512_input[112] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
unsigned char sha512_correct_output[64] =
{
0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
};
unsigned char sha512_actual_output[64];

crypto_hash_sha512_ref(sha512_actual_output, sha512_input, sizeof(sha512_input));
if (memcmp(sha512_actual_output, sha512_correct_output, 64) != 0)
printf("SHA512 bad #1\n");
else
printf("SHA512 good #1\n");

sha512_input[111] ^= 1;

crypto_hash_sha512_ref(sha512_actual_output, sha512_input, sizeof(sha512_input));
if (memcmp(sha512_actual_output, sha512_correct_output, 64) != 0)
printf("SHA512 good #2\n");
else
printf("SHA512 bad #2\n");

/* Signature test */
curve25519_keygen(pubkey, privkey);

curve25519_sign(signature, privkey, msg, msg_len);
curve25519_sign(signature, privkey, msg, msg_len, random);

if (curve25519_verify(signature, pubkey, msg, msg_len) == 0)
printf("success #1\n");
printf("Signature good #1\n");
else
printf("failure #1\n");
printf("Signature bad #1\n");

signature[0] ^= 1;

if (curve25519_verify(signature, pubkey, msg, msg_len) == 0)
printf("failure #2\n");
printf("Signature bad #2\n");
else
printf("success #2\n");
printf("Signature good #2\n");


printf("Random testing...\n");
for (int count = 0; count < 10000; count++) {
unsigned char b[64];
crypto_hash_sha512_ref(b, privkey, 32);
memmove(privkey, b, 32);
crypto_hash_sha512_ref(b, privkey, 32);
memmove(random, b, 64);

privkey[0] &= 248;
privkey[31] &= 63;
privkey[31] |= 64;

curve25519_keygen(pubkey, privkey);

curve25519_sign(signature, privkey, msg, msg_len, random);

if (curve25519_verify(signature, pubkey, msg, msg_len) != 0) {
printf("failure #1 %d\n", count);
return -1;
}

if (b[63] & 1)
signature[count % 64] ^= 1;
else
msg[count % 100] ^= 1;
if (curve25519_verify(signature, pubkey, msg, msg_len) == 0) {
printf("failure #2 %d\n", count);
return -1;
}
}
printf("OK\n");
return 1;
}
Binary file modified libaxolotl/libs/armeabi-v7a/libcurve25519.so
Binary file not shown.
Binary file modified libaxolotl/libs/armeabi/libcurve25519.so
Binary file not shown.
Binary file modified libaxolotl/libs/x86/libcurve25519.so
Binary file not shown.

0 comments on commit 1eb3884

Please sign in to comment.