mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Update to latest ref10-extract ed25519
This commit is contained in:
parent
5ea3b3038e
commit
1eb3884b7a
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
@ -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:
|
||||
|
||||
mont_x = (ed_y + ed_z) / (ed_z - ed_y)
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
@ -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);
|
||||
@ -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
libaxolotl/jni/ed25519/additions/zeroize.c
Normal file
10
libaxolotl/jni/ed25519/additions/zeroize.c
Normal file
@ -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
libaxolotl/jni/ed25519/additions/zeroize.h
Normal file
6
libaxolotl/jni/ed25519/additions/zeroize.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __ZEROIZE_H__
|
||||
#define __ZEROIZE_H__
|
||||
|
||||
void zeroize(unsigned char* b, unsigned long len);
|
||||
|
||||
#endif
|
@ -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[])
|
||||
@ -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);
|
||||
@ -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 not shown.
Binary file not shown.
Binary file not shown.
@ -39,7 +39,7 @@ public class Curve25519 {
|
||||
private static native byte[] generatePublicKey(byte[] privateKey);
|
||||
private static native byte[] generatePrivateKey(byte[] random, boolean ephemeral);
|
||||
|
||||
private static native byte[] calculateSignature(byte[] privateKey, byte[] message);
|
||||
private static native byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message);
|
||||
private static native boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);
|
||||
|
||||
public static ECKeyPair generateKeyPair(boolean ephemeral) {
|
||||
@ -55,7 +55,8 @@ public class Curve25519 {
|
||||
}
|
||||
|
||||
static byte[] calculateSignature(ECPrivateKey privateKey, byte[] message) {
|
||||
return calculateSignature(((DjbECPrivateKey)privateKey).getPrivateKey(), message);
|
||||
byte[] random = getRandom(32);
|
||||
return calculateSignature(random, ((DjbECPrivateKey)privateKey).getPrivateKey(), message);
|
||||
}
|
||||
|
||||
static boolean verifySignature(ECPublicKey publicKey, byte[] message, byte[] signature) {
|
||||
@ -83,4 +84,15 @@ public class Curve25519 {
|
||||
return generatePrivateKey(privateKey, ephemeral);
|
||||
}
|
||||
|
||||
private static byte[] getRandom(int size) {
|
||||
try {
|
||||
byte[] random = new byte[size];
|
||||
SecureRandom.getInstance("SHA1PRNG").nextBytes(random);
|
||||
|
||||
return random;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user