aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUES61
-rw-r--r--src/main/java/org/gnunet/util/HashCode.java40
-rw-r--r--src/main/java/org/gnunet/util/crypto/Curve25519.java69
-rw-r--r--src/main/java/org/gnunet/util/crypto/DsaPrng.java24
-rw-r--r--src/main/java/org/gnunet/util/crypto/EcdhePrivateKey.java87
-rw-r--r--src/main/java/org/gnunet/util/crypto/EcdhePublicKey.java77
-rw-r--r--src/main/java/org/gnunet/util/crypto/EcdsaPrivateKey.java112
-rw-r--r--src/main/java/org/gnunet/util/crypto/EcdsaPublicKey.java71
-rw-r--r--src/main/java/org/gnunet/util/crypto/EcdsaSignature.java53
-rw-r--r--src/main/java/org/gnunet/util/crypto/EcdsaSignedMessage.java2
-rw-r--r--src/main/java/org/gnunet/util/crypto/Ed25519.java224
-rw-r--r--src/main/java/org/gnunet/util/crypto/EddsaPrivateKey.java65
-rw-r--r--src/main/java/org/gnunet/util/crypto/EddsaPublicKey.java103
-rw-r--r--src/main/java/org/gnunet/util/crypto/EddsaSignature.java36
-rw-r--r--src/main/java/org/gnunet/util/crypto/EddsaSignedMessage.java20
-rw-r--r--src/main/java/org/gnunet/voting/Ballot.java10
-rw-r--r--src/main/java/org/gnunet/voting/CertifyGroupTool.java2
-rw-r--r--src/main/java/org/gnunet/voting/GroupCert.java4
-rw-r--r--src/test/java/org/gnunet/util/EcdheTest.java79
-rw-r--r--src/test/java/org/gnunet/util/EcdsaTest.java45
-rw-r--r--src/test/java/org/gnunet/util/Ed25519Test.java142
-rw-r--r--src/test/java/org/gnunet/util/EddsaTest.java11
22 files changed, 1082 insertions, 255 deletions
diff --git a/ISSUES b/ISSUES
index e7248b1..ecac928 100644
--- a/ISSUES
+++ b/ISSUES
@@ -1,44 +1,37 @@
1set: 1general crypto implementation:
2 * generation collection and other stuff in set is implemented now 2 * key generation problem (setting/clearing bits) has been fixed in libgcrypt, but what about NaCl incompatibility?
3 * some structural changes were necessary to implement everything 3 (NaCl uses Curve25519/montgomery coordinates for ECDH, Ed25519/twisted edwards coordinates for EdDSA;
4 GNUnet with libgcrypt uses Ed25519 coordinates for everything; also in NaCl ecdhe pubkeys are just the x-coordinate)
5 * libgcrypt does not use montgomery x-addition (=> slower)
6 * MPI_EC_MONTGOMERY exists, but is not implemented yet
7 * reasons for not using NaCl and its optimized crypto-code?
8 * I guess (unclear) licensing?
9 * I _think_ the
4 10
5 * GNUNET_CONTAINER_HashMapIterator vs GNUNET_CONTAINER_MultiHashMapIterator 11java crypto implementation:
6 * very confusing name clash 12 implementing crypto is INCREDIBLY frustrating
7 13
8 * there's now also an external iterator for multihashmap32 14 * original ed25519 java implementation had a pretty nice bug that occured with p=1/256 ...
9 15
10 * documentation: I'll meet with cfuchs on wednesday 16 * 'gnunet-ecc -E' generates some random reference values
11 17
18 * gnunet-java now "implements" all three pk cryptosystems in pure java
19 * all but ECDSA pass sanity checks
20 * I'm relatively confident in Ed25519, it gives the same results as the python ref implementation
21 * aB key generation does not give the same results as GNUnet?
12 22
13doxygen: 23set documentation:
14 * would it be possible to remove e.g. the call graphs to make 24https://gnunet.org/content/gnunets-set-subsystem
15 the doxygen on gnunet.org more accessible? 25
16 * see e.g. https://gnunet.org/doxygen/de/d22/crypto__hkdf_8c.html 26
27embeding curve points / using ECC for secret sharing:
28 * problem: with the usual message-embeding injections we lose homomorphic properties
29 * I found (=read somewhere ;) a scheme for elgamal with ecc, but i'm not 100%
30 sure all the ZKPs will still work ...
17 31
18 32
19secretsharing: 33secretsharing:
20 * if you want a shorter name: vss (verifyable secret sharing) 34 * see document I mailed you ...
21 * discuss api 35
22 * how should shares be serialized
23 * ... and should they contain the list of peers?
24 * => maybe a configuration file / string?
25 * Should broadcast steps in the secret sharing protocol
26 be replaced by a consensus on signed commitments?
27 * this way all peers will have the same result
28 * what if one of the authorities does not send some of the signed share parts s_{i,j}? who / how to blame?
29 * one idea is to use consensus with encrypted signeds{i,j}, so only the receiver can open it and
30 it can be known who sent their share parts
31 * but: what if the encrypted value is wrong? there's no way to demonstrate this without revealing the
32 private key => can we somehow use ecdh+key derivation for that, so that the key can still
33 be revealed to blame somebody?
34 * round1: each peer puts a freshly generated, signed ecdh key in consensus
35 * in the share part exchange round: if a share part is wrong (signature verification or F_{i,j} verification fails),
36 the authority that finds out puts a complaint element in the consensus, revealing its private ecdh key
37 * the other authorities check the complaint for validity
38 * if the complaint is valid, the offending authority is excluded
39 * if the complaint is invalid, the complainer is excluded
40 * what parameters should be the default?
41 * q (where q divides (p-1)) determines the size of the group, so how large do we want it?
42 (for practical purposes and security)
43 36
44 37
diff --git a/src/main/java/org/gnunet/util/HashCode.java b/src/main/java/org/gnunet/util/HashCode.java
index 389217f..a93a867 100644
--- a/src/main/java/org/gnunet/util/HashCode.java
+++ b/src/main/java/org/gnunet/util/HashCode.java
@@ -39,12 +39,48 @@ public class HashCode implements Message {
39 @FixedSizeIntegerArray(length = 64, signed = false, bitSize = 8) 39 @FixedSizeIntegerArray(length = 64, signed = false, bitSize = 8)
40 public byte[] data; // should be immutable, final, can't be due to construct 40 public byte[] data; // should be immutable, final, can't be due to construct
41 41
42 42 /**
43 * Create a hash code initialized to zero.
44 */
43 public HashCode() { 45 public HashCode() {
44 data = new byte[64]; 46 data = new byte[64];
45 } 47 }
46 48
47 public HashCode(byte[] hash) { 49 /**
50 * Create a HashCode from an existing SHA-512 hash code value.
51 *
52 * @param hash SHA-512 hash code value
53 * @return a HashCode
54 */
55 public static HashCode fromHashCode(byte[] hash) {
56 return new HashCode(hash);
57 }
58
59 /**
60 * Create a HashCode from data to be hashed.
61 *
62 * @param data data to hash
63 * @return a HashCode
64 */
65 public static HashCode hash(byte[] data) {
66 MessageDigest digest;
67 try {
68 digest = MessageDigest.getInstance("SHA-512");
69 } catch (NoSuchAlgorithmException e) {
70 throw new RuntimeException("crypto algorithm 'SHA-512' required but not provided");
71 }
72 byte[] hb = digest.digest(data);
73 HashCode h = new HashCode(hb);
74 return h;
75 }
76
77 /**
78 * Private constructor for HashCode from the hash code value. Made
79 * private because there are two ways to create hash codes from byte arrays.
80 *
81 * @param hash hash code value to store in the HashCode
82 */
83 private HashCode(byte[] hash) {
48 if (hash.length != 64) { 84 if (hash.length != 64) {
49 throw new AssertionError("HashCode has to have length 64"); 85 throw new AssertionError("HashCode has to have length 64");
50 } 86 }
diff --git a/src/main/java/org/gnunet/util/crypto/Curve25519.java b/src/main/java/org/gnunet/util/crypto/Curve25519.java
deleted file mode 100644
index 86e6949..0000000
--- a/src/main/java/org/gnunet/util/crypto/Curve25519.java
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.util.crypto;
22
23
24import java.math.BigInteger;
25
26/**
27 * Java-only implementation of arithmetic on DJBs Curve25519.
28 * The curve is a Montgomery curve, and we use coordinates in
29 * Montgomery form.
30 * Very, very slow.
31 */
32public class Curve25519 {
33 private BigInteger X;
34 private BigInteger Z;
35
36 private BigInteger B = new BigInteger("486662");
37
38 // curve parameter q = 255^(-19)
39 private static final BigInteger q = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819949");
40
41
42 public Curve25519(BigInteger X, BigInteger Z) {
43 this.X = X;
44 this.Z = Z;
45 }
46
47 public Curve25519 scalarmult(BigInteger e) {
48 if (e.equals(BigInteger.ZERO)) {
49 return new Curve25519(BigInteger.ZERO, BigInteger.ONE);
50 }
51 Curve25519 Q = scalarmult(e.shiftRight(1));
52 Q = Q.add(Q);
53 if (e.testBit(0)) Q = Q.add(this);
54 return Q;
55 }
56
57 /**
58 * Addition law for montgomery curve in montgomery coordinates.
59 *
60 * @param other
61 * @return
62 */
63 public Curve25519 add(Curve25519 other) {
64 return null;
65 }
66
67
68
69}
diff --git a/src/main/java/org/gnunet/util/crypto/DsaPrng.java b/src/main/java/org/gnunet/util/crypto/DsaPrng.java
index c26848e..259aaa6 100644
--- a/src/main/java/org/gnunet/util/crypto/DsaPrng.java
+++ b/src/main/java/org/gnunet/util/crypto/DsaPrng.java
@@ -32,15 +32,21 @@ import java.util.Arrays;
32 32
33/** 33/**
34 * Deterministic generator for the 'k'-value of DSA, conforming to RFC 6979. 34 * Deterministic generator for the 'k'-value of DSA, conforming to RFC 6979.
35 * SHA-1 is used as H. 35 * SHA-512 is used as H.
36 */ 36 */
37public class DsaPrng { 37public class DsaPrng {
38 private static final int qlen = 32;
39 private Mac mac; 38 private Mac mac;
40 private byte[] V = new byte[64]; 39 private byte[] V = new byte[64];
41 private byte[] K = new byte[64]; 40 private byte[] K = new byte[64];
41 private static final int qlen = 32;
42 42
43 public byte[] hmacK(byte[]... args) { 43 /**
44 * Compute the HMAC of the fiven data with our current K-value.
45 *
46 * @param args data
47 * @return result of the hmac
48 */
49 private byte[] hmacK(byte[]... args) {
44 try { 50 try {
45 mac.init(new SecretKeySpec(K, "HmacSHA1")); 51 mac.init(new SecretKeySpec(K, "HmacSHA1"));
46 } catch (InvalidKeyException e) { 52 } catch (InvalidKeyException e) {
@@ -52,6 +58,12 @@ public class DsaPrng {
52 return mac.doFinal(); 58 return mac.doFinal();
53 } 59 }
54 60
61 /**
62 * Create an instance of the deterministic random number generator for the DSA 'k' vale.
63 *
64 * @param key private key
65 * @param message message
66 */
55 public DsaPrng(byte[] key, byte[] message) { 67 public DsaPrng(byte[] key, byte[] message) {
56 try { 68 try {
57 mac = Mac.getInstance("HmacSHA1"); 69 mac = Mac.getInstance("HmacSHA1");
@@ -73,6 +85,12 @@ public class DsaPrng {
73 V = hmacK(V); 85 V = hmacK(V);
74 } 86 }
75 87
88 /**
89 * Get the next deterministically generated candidate for
90 * the k value used in DSA.
91 *
92 * @return the next candidate value for 'k'
93 */
76 public BigInteger nextK() { 94 public BigInteger nextK() {
77 byte[] T = new byte[0]; 95 byte[] T = new byte[0];
78 while (T.length < qlen) { 96 while (T.length < qlen) {
diff --git a/src/main/java/org/gnunet/util/crypto/EcdhePrivateKey.java b/src/main/java/org/gnunet/util/crypto/EcdhePrivateKey.java
index e3cd861..9f4672e 100644
--- a/src/main/java/org/gnunet/util/crypto/EcdhePrivateKey.java
+++ b/src/main/java/org/gnunet/util/crypto/EcdhePrivateKey.java
@@ -1,4 +1,89 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
1package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
2 22
3public class EcdhePrivateKey { 23import org.gnunet.construct.FixedSizeIntegerArray;
24import org.gnunet.construct.Message;
25import org.gnunet.util.HashCode;
26
27import java.math.BigInteger;
28import java.security.SecureRandom;
29
30/**
31 * Private key for elliptic curve Diffie Hellman exchange.
32 */
33public class EcdhePrivateKey implements Message {
34 /**
35 * Private key byte string, in little endian form.
36 */
37 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
38 public byte[] d;
39
40 /**
41 * Create an ecdh private key without allocating the key data.
42 */
43 public EcdhePrivateKey() {
44 // empty constructor for org.gnunet.construct.*
45 }
46
47 /**
48 * Get the public key for this private key.
49 *
50 * @return the public key for this private key
51 */
52 public EcdhePublicKey getPublicKey() {
53 BigInteger dCoeff = Ed25519.decodeScalar(d);
54 Ed25519 A = Ed25519.B.scalarmult(dCoeff);
55 return new EcdhePublicKey(A);
56 }
57
58 /*
59 * Derive key material from the give public key and a this private ECDHE key.
60 *
61 * @param publicKey public key to use for the ECDH
62 * @return key material
63 */
64 public HashCode ecdh(EcdhePublicKey publicKey) {
65 BigInteger dCoeff = Ed25519.decodeScalar(d);
66 Ed25519 Q = publicKey.asPoint().scalarmult(dCoeff);
67 // hash big endian representation of the x-coordinate.
68 return HashCode.hash(Q.P0.toByteArray());
69 }
70
71 /**
72 * Create a random private key.
73 *
74 * @return a random private key
75 */
76 public static EcdhePrivateKey createRandom() {
77 SecureRandom sr = new SecureRandom();
78 EcdhePrivateKey privateKey = new EcdhePrivateKey();
79 privateKey.d = new byte[32];
80 sr.nextBytes(privateKey.d);
81 // clear bits so that d mod 8 = 0
82 privateKey.d[0] &= (byte) 248;
83 // make sure the key fits in 255 bits
84 privateKey.d[31] &= (byte) 127;
85 // make sure key does not have lots of leading zeros
86 privateKey.d[31] |= (byte) 64;
87 return privateKey;
88 }
4} 89}
diff --git a/src/main/java/org/gnunet/util/crypto/EcdhePublicKey.java b/src/main/java/org/gnunet/util/crypto/EcdhePublicKey.java
index 3943137..844bddf 100644
--- a/src/main/java/org/gnunet/util/crypto/EcdhePublicKey.java
+++ b/src/main/java/org/gnunet/util/crypto/EcdhePublicKey.java
@@ -1,20 +1,83 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
1package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
2 22
3import org.gnunet.construct.FixedSizeIntegerArray; 23import org.gnunet.construct.FixedSizeIntegerArray;
24import org.gnunet.util.Strings;
4 25
26/**
27 * Public key for elliptic curve diffie hellman exchange.
28 */
5public class EcdhePublicKey { 29public class EcdhePublicKey {
6 /** 30 /**
7 * x-coordinate of the point on the curve. 31 * Point on the curve, in Ed25519-compressed form.
8 * The number is stored as little endian.
9 */ 32 */
10 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32) 33 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
11 public byte[] x; 34 public byte[] y;
12 35
13 /** 36 /**
14 * y-coordinate of the point on the curve. 37 * Create a public key without allocating the key's data.
15 * The number is stored as little endian. 38 * Necessary for constructing the key with 'org.gnunet.construct.*'.
16 */ 39 */
17 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32) 40 public EcdhePublicKey() {
18 public byte[] y; 41 // empty
42 }
43
44 /**
45 * Create a public key from the given point on the Ed25519 curve.
46 *
47 * @param a point to create the public key from
48 */
49 public EcdhePublicKey(Ed25519 a) {
50 y = a.encode();
51 }
19 52
53 /**
54 * Convert the public key to a point on the Ed25519 curve.
55 *
56 * @return point corresponding to this public key
57 */
58 public Ed25519 asPoint() {
59 return Ed25519.decode(y);
60 }
61
62 /**
63 * Get a GNUnet-style string representation of this key.
64 *
65 * @return the GNUnet-style string representation of this key.
66 */
67 @Override
68 public String toString() {
69 return Strings.dataToString(y);
70 }
71
72 /**
73 * Load an ECDHE key from a string.
74 *
75 * @param s string with the key data
76 * @return a public key
77 */
78 public EcdhePublicKey fromString(String s) {
79 EcdhePublicKey publicKey = new EcdhePublicKey();
80 Strings.stringToData(s, publicKey.y);
81 return publicKey;
82 }
20} 83}
diff --git a/src/main/java/org/gnunet/util/crypto/EcdsaPrivateKey.java b/src/main/java/org/gnunet/util/crypto/EcdsaPrivateKey.java
index 43bd55a..2ac3fa8 100644
--- a/src/main/java/org/gnunet/util/crypto/EcdsaPrivateKey.java
+++ b/src/main/java/org/gnunet/util/crypto/EcdsaPrivateKey.java
@@ -1,41 +1,121 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
1package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
2 22
3import org.gnunet.construct.FixedSizeIntegerArray; 23import org.gnunet.construct.FixedSizeIntegerArray;
4import org.gnunet.construct.Message; 24import org.gnunet.construct.Message;
25import org.gnunet.util.HashCode;
5 26
27import java.math.BigInteger;
6import java.security.SecureRandom; 28import java.security.SecureRandom;
7 29
30/**
31 * Private key for elliptic curve DSA.
32 */
8public class EcdsaPrivateKey implements Message { 33public class EcdsaPrivateKey implements Message {
34 /**
35 * Private key byte string, in little endian form.
36 */
9 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32) 37 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
10 public byte[] d; 38 public byte[] d;
11 39
40 /**
41 * Create a private key without allocating the key data.
42 */
43 public EcdsaPrivateKey() {
44 // empty, needed by org.gnunet.construct.*
45 }
46
47 /**
48 * Get the anonymous private key. Corresponds to '1'.
49 *
50 * @return the anonymous private ECDSA key
51 */
12 public static EcdsaPrivateKey getAnonymous() { 52 public static EcdsaPrivateKey getAnonymous() {
13 return null; 53 EcdsaPrivateKey privateKey = new EcdsaPrivateKey();
54 privateKey.d = new byte[32];
55 privateKey.d[31] = 1;
56 return privateKey;
14 } 57 }
15 58
59 /**
60 * Sign the given data with this private key. Must include a purpose to mitigate
61 * replay / copy and paste attacks.
62 *
63 * @param purpose purpose for the signature
64 * @param data data to sign
65 * @return the signature over both the data and the purpose
66 */
16 public EcdsaSignature sign(int purpose, byte[] data) { 67 public EcdsaSignature sign(int purpose, byte[] data) {
17 EcdsaSignature signature = new EcdsaSignature(); 68 return sign(getPublicKey(), purpose, data);
18 return signature;
19 } 69 }
20 70
21 public static EcdsaPrivateKey fromFile(String privKeyFilename) { 71 /**
22 return null; 72 * Sign the given data with this private key. Must include a purpose to mitigate
73 * replay / copy and paste attacks.
74 *
75 * @param publicKey public key corresponding to this private key, supplying this parameter
76 * leads to better performance as the public key does not have to be derived
77 * @param purpose purpose for the signature
78 * @param data data to sign
79 * @return the signature over both the data and the purpose
80 */
81 public EcdsaSignature sign(EcdsaPublicKey publicKey, int purpose, byte[] data) {
82 EcdsaSignature signature = new EcdsaSignature();
83 DsaPrng prng = new DsaPrng(d, data);
84 HashCode h = HashCode.hash(data);
85 byte[] zData = new byte[32];
86 System.arraycopy(h.data, 0, zData, 0, 32);
87 BigInteger z = new BigInteger(1, zData);
88 BigInteger dCoeff = Ed25519.decodeScalar(d);
89 while (true) {
90 BigInteger k = prng.nextK();
91 Ed25519 P = Ed25519.B.scalarmult(k);
92 BigInteger r = P.P0.mod(Ed25519.q);
93 if (r.equals(BigInteger.ZERO))
94 continue;
95 BigInteger s = k.modInverse(Ed25519.q).multiply(z.add(r.multiply(dCoeff)));
96 if (!r.equals(BigInteger.ZERO)) {
97 signature.r = Ed25519.encodeScalar(r);
98 signature.s = Ed25519.encodeScalar(s);
99 return signature;
100 }
101 }
23 } 102 }
24 103
104 /**
105 * Get the public key for this private key.
106 *
107 * @return the public key for this private key
108 */
25 public EcdsaPublicKey getPublicKey() { 109 public EcdsaPublicKey getPublicKey() {
26 // FIXME: this is not the real implementation, 110 Ed25519 A = Ed25519.B.scalarmult(Ed25519.decodeScalar(d));
27 // beware that this dummy implementation leaks the key! 111 return new EcdsaPublicKey(A);
28 EcdsaPublicKey publicKey = new EcdsaPublicKey();
29 byte[] v = new byte[32];
30 System.arraycopy(d, 0, v, 0, 8);
31 System.arraycopy(d, 0, v, 8, 8);
32 System.arraycopy(d, 0, v, 16, 8);
33 System.arraycopy(d, 0, v, 24, 8);
34 System.arraycopy(v, 0, publicKey.x, 0, 32);
35 System.arraycopy(v, 0, publicKey.y, 0, 32);
36 return publicKey;
37 } 112 }
38 113
114 /**
115 * Create a randomly generated private ecdsa key.
116 *
117 * @return a freshly generated key
118 */
39 public static EcdsaPrivateKey createRandom() { 119 public static EcdsaPrivateKey createRandom() {
40 SecureRandom sr = new SecureRandom(); 120 SecureRandom sr = new SecureRandom();
41 EcdsaPrivateKey privateKey = new EcdsaPrivateKey(); 121 EcdsaPrivateKey privateKey = new EcdsaPrivateKey();
diff --git a/src/main/java/org/gnunet/util/crypto/EcdsaPublicKey.java b/src/main/java/org/gnunet/util/crypto/EcdsaPublicKey.java
index 7468109..ce0c981 100644
--- a/src/main/java/org/gnunet/util/crypto/EcdsaPublicKey.java
+++ b/src/main/java/org/gnunet/util/crypto/EcdsaPublicKey.java
@@ -1,3 +1,23 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
1package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
2 22
3import org.gnunet.construct.FixedSizeIntegerArray; 23import org.gnunet.construct.FixedSizeIntegerArray;
@@ -12,12 +32,6 @@ import java.util.Arrays;
12public class EcdsaPublicKey implements Message { 32public class EcdsaPublicKey implements Message {
13 private static final Logger logger = LoggerFactory 33 private static final Logger logger = LoggerFactory
14 .getLogger(EcdsaPublicKey.class); 34 .getLogger(EcdsaPublicKey.class);
15 /**
16 * x-coordinate of the point on the curve.
17 * The number is stored as little endian.
18 */
19 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
20 public byte[] x;
21 35
22 /** 36 /**
23 * y-coordinate of the point on the curve. 37 * y-coordinate of the point on the curve.
@@ -26,28 +40,32 @@ public class EcdsaPublicKey implements Message {
26 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32) 40 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
27 public byte[] y; 41 public byte[] y;
28 42
43 /**
44 * Create an ECDSA public key from a curve point.
45 *
46 * @param a curve point.
47 */
29 public EcdsaPublicKey(Ed25519 a) { 48 public EcdsaPublicKey(Ed25519 a) {
30 49 y = a.encode();
31 } 50 }
32 51
52 /**
53 * Create a public key without allocating space for the key data.
54 * Necessary for constructing this class with org.gnunet.construct.*
55 */
33 public EcdsaPublicKey() { 56 public EcdsaPublicKey() {
34 x = new byte[32]; 57 // empty
35 y = new byte[32];
36 } 58 }
37 59
38 public static EcdsaPublicKey fromStringUncompressed(String s) { 60 /**
39 if (s.length() != org.gnunet.util.Strings.getEncodedStringLength(64)) { 61 * Load an ECDSA key from a string.
40 logger.debug("invalid key length"); 62 *
41 return null; 63 * @param s string with the key data
42 } 64 * @return a public key
43 byte[] data = new byte[64]; 65 */
44 if (!Strings.stringToData(s, data)) { 66 public static EcdsaPublicKey fromString(String s) {
45 logger.debug("invalid key format");
46 return null;
47 }
48 EcdsaPublicKey publicKey = new EcdsaPublicKey(); 67 EcdsaPublicKey publicKey = new EcdsaPublicKey();
49 System.arraycopy(data, 0, publicKey.x, 0, 32); 68 Strings.stringToData(s, publicKey.y);
50 System.arraycopy(data, 32, publicKey.y, 0, 32);
51 return publicKey; 69 return publicKey;
52 } 70 }
53 71
@@ -60,17 +78,13 @@ public class EcdsaPublicKey implements Message {
60 public static EcdsaPublicKey random() { 78 public static EcdsaPublicKey random() {
61 SecureRandom sr = new SecureRandom(); 79 SecureRandom sr = new SecureRandom();
62 EcdsaPublicKey publicKey = new EcdsaPublicKey(); 80 EcdsaPublicKey publicKey = new EcdsaPublicKey();
63 sr.nextBytes(publicKey.x);
64 sr.nextBytes(publicKey.y); 81 sr.nextBytes(publicKey.y);
65 return publicKey; 82 return publicKey;
66 } 83 }
67 84
68 @Override 85 @Override
69 public String toString() { 86 public String toString() {
70 byte[] keyData = new byte[64]; 87 return Strings.dataToString(y);
71 System.arraycopy(x, 0, keyData, 0, 32);
72 System.arraycopy(y, 0, keyData, 32, 32);
73 return Strings.dataToString(keyData);
74 } 88 }
75 89
76 @Override 90 @Override
@@ -80,7 +94,6 @@ public class EcdsaPublicKey implements Message {
80 94
81 EcdsaPublicKey publicKey = (EcdsaPublicKey) o; 95 EcdsaPublicKey publicKey = (EcdsaPublicKey) o;
82 96
83 if (!Arrays.equals(x, publicKey.x)) return false;
84 if (!Arrays.equals(y, publicKey.y)) return false; 97 if (!Arrays.equals(y, publicKey.y)) return false;
85 98
86 return true; 99 return true;
@@ -88,8 +101,8 @@ public class EcdsaPublicKey implements Message {
88 101
89 @Override 102 @Override
90 public int hashCode() { 103 public int hashCode() {
91 int result = Arrays.hashCode(x); 104 int result = Arrays.hashCode(y);
92 result = 31 * result + Arrays.hashCode(y);
93 return result; 105 return result;
94 } 106 }
107
95} 108}
diff --git a/src/main/java/org/gnunet/util/crypto/EcdsaSignature.java b/src/main/java/org/gnunet/util/crypto/EcdsaSignature.java
index b668a3f..76a5e22 100644
--- a/src/main/java/org/gnunet/util/crypto/EcdsaSignature.java
+++ b/src/main/java/org/gnunet/util/crypto/EcdsaSignature.java
@@ -23,11 +23,15 @@ package org.gnunet.util.crypto;
23 23
24import org.gnunet.construct.FixedSizeIntegerArray; 24import org.gnunet.construct.FixedSizeIntegerArray;
25import org.gnunet.construct.Message; 25import org.gnunet.construct.Message;
26import org.gnunet.util.HashCode;
26import org.gnunet.util.Strings; 27import org.gnunet.util.Strings;
27 28
28import java.math.BigInteger; 29import java.math.BigInteger;
29import java.nio.ByteBuffer; 30import java.security.SecureRandom;
30 31
32/**
33 * ECDSA Signature.
34 */
31public class EcdsaSignature implements Message { 35public class EcdsaSignature implements Message {
32 /** 36 /**
33 * R value of the signature in compressed form. 37 * R value of the signature in compressed form.
@@ -48,13 +52,38 @@ public class EcdsaSignature implements Message {
48 this.s = new byte[32]; 52 this.s = new byte[32];
49 } 53 }
50 54
55 /**
56 * Verify that this signature has been created by the given public key and signs the
57 * given data and purpose.
58 *
59 * @param m message that was signed
60 * @param purpose purpose of the signature
61 * @param publicKey public key to check for
62 * @return whether the signature is valid
63 */
51 public boolean verify(byte[] m, int purpose, EcdsaPublicKey publicKey) { 64 public boolean verify(byte[] m, int purpose, EcdsaPublicKey publicKey) {
52 return false; 65 HashCode h = HashCode.hash(m);
66 byte[] zData = new byte[32];
67 System.arraycopy(h.data, 0, zData, 0, 32);
68 BigInteger z = new BigInteger(1, zData);
69 BigInteger sCoeff = Ed25519.decodeScalar(s);
70 BigInteger rCoeff = Ed25519.decodeScalar(r);
71 BigInteger w = sCoeff.modInverse(Ed25519.q);
72 BigInteger u1 = z.multiply(w).mod(Ed25519.q);
73 BigInteger u2 = rCoeff.multiply(w).mod(Ed25519.q);
74 Ed25519 P = Ed25519.B.scalarmult(u1).add(Ed25519.B.scalarmult(u2));
75 return P.P0.equals(rCoeff.mod(Ed25519.q));
53 } 76 }
54 77
78 /**
79 * Load a signature from a string.
80 *
81 * @param value serialized signature
82 * @return signature
83 */
55 public static EcdsaSignature fromString(String value) { 84 public static EcdsaSignature fromString(String value) {
56 byte[] data = new byte[64]; 85 byte[] data = new byte[64];
57 if (!Strings.stringToData(value, data)) { 86 if (! Strings.stringToData(value, data)) {
58 throw new AssertionError(); 87 throw new AssertionError();
59 } 88 }
60 EcdsaSignature sig = new EcdsaSignature(); 89 EcdsaSignature sig = new EcdsaSignature();
@@ -63,6 +92,12 @@ public class EcdsaSignature implements Message {
63 return sig; 92 return sig;
64 } 93 }
65 94
95
96 /**
97 * Serialize the signature to a string.
98 *
99 * @return serialized signature
100 */
66 @Override 101 @Override
67 public String toString() { 102 public String toString() {
68 byte[] sigData = new byte[64]; 103 byte[] sigData = new byte[64];
@@ -72,4 +107,16 @@ public class EcdsaSignature implements Message {
72 } 107 }
73 108
74 109
110 /**
111 * Return a signature that is invalid with very, very high probability.
112 *
113 * @return signature with random garbage
114 */
115 public static EcdsaSignature randomGarbage() {
116 EcdsaSignature sig = new EcdsaSignature();
117 SecureRandom r = new SecureRandom();
118 r.nextBytes(sig.r);
119 r.nextBytes(sig.s);
120 return sig;
121 }
75} 122}
diff --git a/src/main/java/org/gnunet/util/crypto/EcdsaSignedMessage.java b/src/main/java/org/gnunet/util/crypto/EcdsaSignedMessage.java
index 0cb293a..bfc3fe4 100644
--- a/src/main/java/org/gnunet/util/crypto/EcdsaSignedMessage.java
+++ b/src/main/java/org/gnunet/util/crypto/EcdsaSignedMessage.java
@@ -26,7 +26,7 @@ import org.gnunet.construct.NestedMessage;
26import org.gnunet.construct.UInt32; 26import org.gnunet.construct.UInt32;
27 27
28/** 28/**
29 * A message together with a signature on the message and it's purpose. 29 * A message together with a signature on the message and its purpose.
30 */ 30 */
31public class EcdsaSignedMessage<M extends Message> implements Message { 31public class EcdsaSignedMessage<M extends Message> implements Message {
32 @NestedMessage 32 @NestedMessage
diff --git a/src/main/java/org/gnunet/util/crypto/Ed25519.java b/src/main/java/org/gnunet/util/crypto/Ed25519.java
index 0947de4..caa2ec8 100644
--- a/src/main/java/org/gnunet/util/crypto/Ed25519.java
+++ b/src/main/java/org/gnunet/util/crypto/Ed25519.java
@@ -1,48 +1,148 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
1package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
2 22
3 23
4import java.math.BigInteger; 24import java.math.BigInteger;
5import java.security.MessageDigest; 25import java.security.MessageDigest;
6import java.security.NoSuchAlgorithmException; 26import java.security.NoSuchAlgorithmException;
27import java.util.Arrays;
7 28
8/** 29/**
9 * Java-only implementation of arithmetic on DJBs Ed25519. 30 * Java-only implementation of arithmetic on DJBs Ed25519.
10 * Very, very slow. 31 * Very, very slow.
11 */ 32 */
12public class Ed25519 { 33public class Ed25519 {
13 // curve parameter b 34 /**
14 static final int b = 256; 35 * curve parameter b
15 // curve parameter q = 255^(-19) 36 */
16 private static final BigInteger q = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819949"); 37 public static final int b = 256;
17 // q-3 38 /**
18 private static final BigInteger qm2 = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819947"); 39 * curve parameter q = 2^255-19
19 // q-3 40 */
20 private static final BigInteger qp3 = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819952"); 41 public static final BigInteger q = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819949");
42 /**
43 * q-2
44 */
45 private static final BigInteger qm2 = q.subtract(BigInteger.valueOf(2));
46 /**
47 * q+3
48 */
49 private static final BigInteger qp3 = q.add(BigInteger.valueOf(3));
50 /**
51 * ???
52 */
21 static final BigInteger l = new BigInteger("7237005577332262213973186563042994240857116359379907606001950938285454250989"); 53 static final BigInteger l = new BigInteger("7237005577332262213973186563042994240857116359379907606001950938285454250989");
54 /**
55 * ???
56 */
22 private static final BigInteger d = new BigInteger("-4513249062541557337682894930092624173785641285191125241628941591882900924598840740"); 57 private static final BigInteger d = new BigInteger("-4513249062541557337682894930092624173785641285191125241628941591882900924598840740");
58 /**
59 * ???
60 */
23 private static final BigInteger I = new BigInteger("19681161376707505956807079304988542015446066515923890162744021073123829784752"); 61 private static final BigInteger I = new BigInteger("19681161376707505956807079304988542015446066515923890162744021073123829784752");
24 private static final BigInteger By = new BigInteger("46316835694926478169428394003475163141307993866256225615783033603165251855960"); 62 /**
63 * x-coordinate of the base point
64 */
25 private static final BigInteger Bx = new BigInteger("15112221349535400772501151409588531511454012693041857206046113283949847762202"); 65 private static final BigInteger Bx = new BigInteger("15112221349535400772501151409588531511454012693041857206046113283949847762202");
26 static final Ed25519 B = new Ed25519(Bx.mod(q),By.mod(q)); 66 /**
27 // 2^255 67 * x-coordinate of the base point.
28 private static final BigInteger un = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819967"); 68 * Corresponds to '9' on Curve25519 in montgomery form
69 */
70 private static final BigInteger By = new BigInteger("46316835694926478169428394003475163141307993866256225615783033603165251855960");
71 /**
72 * base point
73 */
74 public static final Ed25519 B = new Ed25519(Bx.mod(q),By.mod(q));
29 75
76 /**
77 * Mask where only the first 255 bits are set.
78 */
79 private static final BigInteger mask255 = BigInteger.ONE.shiftLeft(255).subtract(BigInteger.ONE);
30 80
81 /**
82 * First coordinate (x) of this point.
83 */
31 BigInteger P0; 84 BigInteger P0;
85
86 /**
87 * Second coordinate (y) of this point.
88 */
32 BigInteger P1; 89 BigInteger P1;
33 90
91 /**
92 * Create a curve point from its coordinates.
93 * @param P0 x-coordinate
94 * @param P1 y-coordinate
95 */
34 public Ed25519(BigInteger P0, BigInteger P1) { 96 public Ed25519(BigInteger P0, BigInteger P1) {
35 this.P0 = P0; 97 this.P0 = P0;
36 this.P1 = P1; 98 this.P1 = P1;
37 } 99 }
38 100
39 public static Ed25519 decompress(BigInteger y) { 101 /**
102 * Create a curve point from its string representation
103 *
104 * @param s the string representation
105 * @return a curve point corresponsing to 's'
106 */
107 public static Ed25519 decode(byte[] s) {
108 BigInteger y = decodeScalar(s);
109 BigInteger x = recoverX(y);
110 if ((x.testBit(0)?1:0) != bit(s, b-1)) {
111 x = q.subtract(x);
112 }
113 Ed25519 v = new Ed25519(x, y);
114 if (!v.isOnCurve()) {
115 throw new AssertionError("not on curve");
116 }
117 return v;
118 }
119
120 /**
121 * Get the i'th bit of a byte array
122 *
123 * @param h byte array
124 * @param i bit index
125 * @return value of the i'th bit in h
126 */
127 private static int bit(byte[] h, int i) {
128 return h[i/8] >> (i%8) & 1;
129 }
130
131 /**
132 * Recover the (positive) x-coordinate from y.
133 *
134 * @param y the y coordinate
135 * @return positive x-coordinate
136 */
137 public static BigInteger recoverX(BigInteger y) {
40 BigInteger y2 = y.multiply(y); 138 BigInteger y2 = y.multiply(y);
41 BigInteger xx = (y2.subtract(BigInteger.ONE)).multiply(inv(d.multiply(y2).add(BigInteger.ONE))); 139 BigInteger xx = (y2.subtract(BigInteger.ONE)).multiply(inv(d.multiply(y2).add(BigInteger.ONE)));
42 BigInteger x = xx.modPow(qp3.divide(BigInteger.valueOf(8)), q); 140 BigInteger x = xx.modPow(qp3.divide(BigInteger.valueOf(8)), q);
43 if (!x.multiply(x).subtract(xx).mod(q).equals(BigInteger.ZERO)) x = (x.multiply(I).mod(q)); 141 if (!x.multiply(x).subtract(xx).mod(q).equals(BigInteger.ZERO))
44 if (!x.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) x = q.subtract(x); 142 x = (x.multiply(I).mod(q));
45 return new Ed25519(x, y); 143 if (!x.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO))
144 x = q.subtract(x);
145 return x;
46 } 146 }
47 147
48 /** 148 /**
@@ -72,6 +172,12 @@ public class Ed25519 {
72 return new Ed25519(x3.mod(q), y3.mod(q)); 172 return new Ed25519(x3.mod(q), y3.mod(q));
73 } 173 }
74 174
175 /**
176 * Multiply this point by a scalar value.
177 *
178 * @param e scalar factor
179 * @return this*e
180 */
75 public Ed25519 scalarmult(BigInteger e) { 181 public Ed25519 scalarmult(BigInteger e) {
76 if (e.equals(BigInteger.ZERO)) { 182 if (e.equals(BigInteger.ZERO)) {
77 return new Ed25519(BigInteger.ZERO, BigInteger.ONE); 183 return new Ed25519(BigInteger.ZERO, BigInteger.ONE);
@@ -82,32 +188,59 @@ public class Ed25519 {
82 return Q; 188 return Q;
83 } 189 }
84 190
191 /**
192 * Decode an integer from it's little endian byte array form.
193 * Takes a 32-byte array. The highest order bit is masked out.
194 *
195 * @param s string representation of a scalar
196 * @return scalar represented by 's'
197 */
85 public static BigInteger decodeScalar(byte[] s) { 198 public static BigInteger decodeScalar(byte[] s) {
199 if (s.length != 32) {
200 throw new AssertionError();
201 }
202 // convert 's' to big endian
86 byte[] out = new byte[s.length]; 203 byte[] out = new byte[s.length];
87 for (int i=0; i < s.length;i++) { 204 for (int i=0; i < s.length;i++) {
88 out[i] = s[s.length-1-i]; 205 out[i] = s[s.length-1-i];
89 } 206 }
90 return new BigInteger(out).and(un); 207 return new BigInteger(1, out).and(mask255);
91 } 208 }
92 209
210 /**
211 * Encode a scalar to little endian byte array form.
212 * The resulting array is always 32 bytes large.
213 *
214 * @param n scalar to encode
215 * @return byte representation of 'n'
216 */
93 public static byte[] encodeScalar(BigInteger n) { 217 public static byte[] encodeScalar(BigInteger n) {
94 byte[] in = n.toByteArray(); 218 byte[] in = n.and(mask255).toByteArray();
95 // reverse the array 219 if (in.length > 32) {
96 for (int i = 0; i < in.length / 2; i++) { 220 throw new AssertionError("size too big: " + in.length);
97 byte tmp = in[i]; 221 }
98 in[i] = in[in.length - i - 1]; 222 byte[] full = new byte[32];
99 in[in.length - i - 1] = tmp; 223 // reverse 'in' and copy to the beginning of 'full'
224 for (int i = 0; i < in.length; i++) {
225 full[in.length - i - 1] = in[i];
100 } 226 }
101 return in; 227 return full;
102 } 228 }
103 229
230 /**
231 * Compress end encode a point on the curve.
232 *
233 * @return compressed and encoded point
234 */
104 public byte[] encode() { 235 public byte[] encode() {
105 byte[] out = encodeScalar(P1); 236 byte[] out = encodeScalar(P1);
106 out[out.length-1] |= (P0.testBit(0) ? 0x80 : 0); 237 System.out.println("encodeScalar " + P1);
238 System.out.println("out1 " + Arrays.toString(out));
239 out[out.length-1] |= (P0.testBit(0) ? (byte) 0x80 : 0);
240 System.out.println("out2 " + Arrays.toString(out));
107 return out; 241 return out;
108 } 242 }
109 243
110
111 /** 244 /**
112 * Hash the data in m and return 2^h(m) 245 * Hash the data in m and return 2^h(m)
113 * 246 *
@@ -122,6 +255,7 @@ public class Ed25519 {
122 throw new RuntimeException("crypto algorithm required but not provided"); 255 throw new RuntimeException("crypto algorithm required but not provided");
123 } 256 }
124 final byte[] h = sha512.digest(m); 257 final byte[] h = sha512.digest(m);
258 // reverse h
125 for (int i = 0; i < 32; i++) { 259 for (int i = 0; i < 32; i++) {
126 byte tmp = h[i]; 260 byte tmp = h[i];
127 h[i] = h[63 - i]; 261 h[i] = h[63 - i];
@@ -130,4 +264,42 @@ public class Ed25519 {
130 return new BigInteger(1, h); 264 return new BigInteger(1, h);
131 } 265 }
132 266
267 /**
268 * Check whether this point is on the curve, and thus valid.
269 *
270 * @return whether is point is on the curve
271 */
272 public boolean isOnCurve() {
273 BigInteger x = P0;
274 BigInteger y = P1;
275 BigInteger xx = x.multiply(x);
276 BigInteger yy = y.multiply(y);
277 BigInteger dxxyy = d.multiply(yy).multiply(xx);
278 return xx.negate().add(yy).subtract(BigInteger.ONE).subtract(dxxyy).mod(q).equals(BigInteger.ZERO);
279 }
280
281 @Override
282 public String toString() {
283 return "(" + P0.toString() + ", " + P1.toString() + ")";
284 }
285
286 @Override
287 public boolean equals(Object o) {
288 if (this == o) return true;
289 if (o == null || getClass() != o.getClass()) return false;
290
291 Ed25519 ed25519 = (Ed25519) o;
292
293 if (!P0.equals(ed25519.P0)) return false;
294 if (!P1.equals(ed25519.P1)) return false;
295
296 return true;
297 }
298
299 @Override
300 public int hashCode() {
301 int result = P0.hashCode();
302 result = 31 * result + P1.hashCode();
303 return result;
304 }
133} 305}
diff --git a/src/main/java/org/gnunet/util/crypto/EddsaPrivateKey.java b/src/main/java/org/gnunet/util/crypto/EddsaPrivateKey.java
index 21aa647..2d1dbcb 100644
--- a/src/main/java/org/gnunet/util/crypto/EddsaPrivateKey.java
+++ b/src/main/java/org/gnunet/util/crypto/EddsaPrivateKey.java
@@ -1,3 +1,22 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
1package org.gnunet.util.crypto; 20package org.gnunet.util.crypto;
2 21
3import org.gnunet.construct.FixedSizeIntegerArray; 22import org.gnunet.construct.FixedSizeIntegerArray;
@@ -17,7 +36,21 @@ public class EddsaPrivateKey implements Message {
17 return sign(getPublicKey(), purpose, m); 36 return sign(getPublicKey(), purpose, m);
18 } 37 }
19 38
39
40 /**
41 * Sign the given data with this private key. Must include a purpose to mitigate
42 * replay / copy and paste attacks.
43 *
44 * @param publicKey public key corresponding to this private key, supplying this parameter
45 * leads to better performance as the public key does not have to be derived
46 * @param purpose purpose for the signature
47 * @param m data to sign
48 * @return the signature over both the data and the purpose
49 */
20 public EddsaSignature sign(EddsaPublicKey publicKey, int purpose, byte[] m) { 50 public EddsaSignature sign(EddsaPublicKey publicKey, int purpose, byte[] m) {
51 if (!publicKey.asPoint().isOnCurve()) {
52 throw new AssertionError();
53 }
21 MessageDigest sha512; 54 MessageDigest sha512;
22 try { 55 try {
23 sha512 = MessageDigest.getInstance("SHA-512"); 56 sha512 = MessageDigest.getInstance("SHA-512");
@@ -40,6 +73,12 @@ public class EddsaPrivateKey implements Message {
40 73
41 BigInteger S = r.add(Ed25519.Hint(buf.array()).multiply(a)).mod(Ed25519.l); 74 BigInteger S = r.add(Ed25519.Hint(buf.array()).multiply(a)).mod(Ed25519.l);
42 75
76 if (!R.isOnCurve()) {
77 throw new AssertionError();
78 }
79 if (!publicKey.asPoint().isOnCurve()) {
80 throw new AssertionError();
81 }
43 return new EddsaSignature(R, S); 82 return new EddsaSignature(R, S);
44 } 83 }
45 84
@@ -55,6 +94,12 @@ public class EddsaPrivateKey implements Message {
55 } 94 }
56 95
57 96
97 /**
98 * Compute the coefficient that is used to derive the public key.
99 * See 'Daniel J. Bernstein et al, High-speed high-security signatures' for details.
100 *
101 * @return the public key coefficient
102 */
58 private BigInteger computePublicKeyCoefficient() { 103 private BigInteger computePublicKeyCoefficient() {
59 MessageDigest sha512; 104 MessageDigest sha512;
60 try { 105 try {
@@ -71,12 +116,30 @@ public class EddsaPrivateKey implements Message {
71 return a; 116 return a;
72 } 117 }
73 118
119 /**
120 * Get the public key for this private key.
121 *
122 * @return the public key for this private key
123 */
74 public EddsaPublicKey getPublicKey() { 124 public EddsaPublicKey getPublicKey() {
75 BigInteger a = computePublicKeyCoefficient(); 125 BigInteger a = computePublicKeyCoefficient();
76 Ed25519 A = Ed25519.B.scalarmult(a); 126 Ed25519 A = Ed25519.B.scalarmult(a);
77 return new EddsaPublicKey(A); 127 if (!A.isOnCurve()) {
128 throw new AssertionError();
129 }
130 EddsaPublicKey publicKey = new EddsaPublicKey(A);
131
132 if (!A.equals(publicKey.asPoint())) {
133 throw new AssertionError();
134 }
135 return publicKey;
78 } 136 }
79 137
138 /**
139 * Create a random private key.
140 *
141 * @return a random private key
142 */
80 public static EddsaPrivateKey createRandom() { 143 public static EddsaPrivateKey createRandom() {
81 SecureRandom sr = new SecureRandom(); 144 SecureRandom sr = new SecureRandom();
82 EddsaPrivateKey privateKey = new EddsaPrivateKey(); 145 EddsaPrivateKey privateKey = new EddsaPrivateKey();
diff --git a/src/main/java/org/gnunet/util/crypto/EddsaPublicKey.java b/src/main/java/org/gnunet/util/crypto/EddsaPublicKey.java
index b548cf7..aa43a0b 100644
--- a/src/main/java/org/gnunet/util/crypto/EddsaPublicKey.java
+++ b/src/main/java/org/gnunet/util/crypto/EddsaPublicKey.java
@@ -1,33 +1,114 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
1package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
2 22
3import org.gnunet.construct.FixedSizeIntegerArray; 23import org.gnunet.construct.FixedSizeIntegerArray;
4import org.gnunet.construct.Message; 24import org.gnunet.construct.Message;
25import org.gnunet.util.Strings;
5 26
27import java.security.SecureRandom;
28import java.util.Arrays;
29
30/**
31 * EdDSA public key.
32 */
6public class EddsaPublicKey implements Message { 33public class EddsaPublicKey implements Message {
7 /** 34 /**
8 * x-coordinate of the point on the curve. 35 * y-coordinate of the point on the curve, in Ed25519-compressed form.
9 * The number is stored as little endian. 36 * The number is stored as little endian.
10 */ 37 */
11 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32) 38 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
12 public byte[] x; 39 public byte[] y;
13 40
14 /** 41 /**
15 * y-coordinate of the point on the curve. 42 * Create a public key without allocating space for the key data.
16 * The number is stored as little endian. 43 * Necessary for constructing this class with org.gnunet.construct.*
17 */ 44 */
18 @FixedSizeIntegerArray(bitSize = 8, signed = false, length = 32)
19 public byte[] y;
20
21 public EddsaPublicKey() { 45 public EddsaPublicKey() {
22 // default constructor for Construct 46 // default constructor for Construct
23 } 47 }
24 48
25 public EddsaPublicKey(Ed25519 a) { 49 public EddsaPublicKey(Ed25519 a) {
26 x = Ed25519.encodeScalar(a.P0); 50 y = a.encode();
27 y = Ed25519.encodeScalar(a.P1); 51 }
52
53 /**
54 * Convert this public key to a point on the Ed25519 curve.
55 *
56 * @return a point corresponding to this key
57 */
58 Ed25519 asPoint() {
59 return Ed25519.decode(y);
60 }
61
62 /**
63 * Load an ECDSA key from a string.
64 *
65 * @param s string with the key data
66 * @return a public key
67 */
68 public EcdhePublicKey fromString(String s) {
69 EcdhePublicKey publicKey = new EcdhePublicKey();
70 Strings.stringToData(s, publicKey.y);
71 return publicKey;
72 }
73
74 /**
75 * Create a random public key. The generated key might not even be valid
76 * (i.e. not on the curve), thus this method should only be used for testing.
77 *
78 * @return a random, possibly invalid public key
79 */
80 public static EcdsaPublicKey random() {
81 SecureRandom sr = new SecureRandom();
82 EcdsaPublicKey publicKey = new EcdsaPublicKey();
83 sr.nextBytes(publicKey.y);
84 return publicKey;
85 }
86
87 /**
88 * Converrt this public key to a string
89 *
90 * @return a string representing this public key
91 */
92 @Override
93 public String toString() {
94 return Strings.dataToString(y);
95 }
96
97 @Override
98 public boolean equals(Object o) {
99 if (this == o) return true;
100 if (o == null || getClass() != o.getClass()) return false;
101
102 EcdsaPublicKey publicKey = (EcdsaPublicKey) o;
103
104 if (!Arrays.equals(y, publicKey.y)) return false;
105
106 return true;
28 } 107 }
29 108
30 public Ed25519 asPoint() { 109 @Override
31 return new Ed25519(Ed25519.decodeScalar(x), Ed25519.decodeScalar(y)); 110 public int hashCode() {
111 int result = Arrays.hashCode(y);
112 return result;
32 } 113 }
33} 114}
diff --git a/src/main/java/org/gnunet/util/crypto/EddsaSignature.java b/src/main/java/org/gnunet/util/crypto/EddsaSignature.java
index 25eea34..fa16a9c 100644
--- a/src/main/java/org/gnunet/util/crypto/EddsaSignature.java
+++ b/src/main/java/org/gnunet/util/crypto/EddsaSignature.java
@@ -18,26 +18,6 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21/*
22 This file is part of GNUnet.
23 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
24
25 GNUnet is free software; you can redistribute it and/or modify
26 it under the terms of the GNU General Public License as published
27 by the Free Software Foundation; either version 3, or (at your
28 option) any later version.
29
30 GNUnet is distributed in the hope that it will be useful, but
31 WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 General Public License for more details.
34
35 You should have received a copy of the GNU General Public License
36 along with GNUnet; see the file COPYING. If not, write to the
37 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
38 Boston, MA 02111-1307, USA.
39 */
40
41package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
42 22
43 23
@@ -75,7 +55,7 @@ public class EddsaSignature implements Message {
75 } 55 }
76 56
77 public boolean verify(byte[] m, int purpose, EddsaPublicKey publicKey) { 57 public boolean verify(byte[] m, int purpose, EddsaPublicKey publicKey) {
78 Ed25519 R = Ed25519.decompress(Ed25519.decodeScalar(r)); 58 Ed25519 R = Ed25519.decode(r);
79 Ed25519 A = publicKey.asPoint(); 59 Ed25519 A = publicKey.asPoint();
80 BigInteger S = Ed25519.decodeScalar(s); 60 BigInteger S = Ed25519.decodeScalar(s);
81 ByteBuffer Stemp = ByteBuffer.allocate(32 + 32 + m.length); 61 ByteBuffer Stemp = ByteBuffer.allocate(32 + 32 + m.length);
@@ -83,7 +63,19 @@ public class EddsaSignature implements Message {
83 BigInteger h = Ed25519.Hint(Stemp.array()); 63 BigInteger h = Ed25519.Hint(Stemp.array());
84 Ed25519 ra = Ed25519.B.scalarmult(S); 64 Ed25519 ra = Ed25519.B.scalarmult(S);
85 Ed25519 rb = R.add(A.scalarmult(h)); 65 Ed25519 rb = R.add(A.scalarmult(h));
86 return rb.equals(rb); 66 if (!A.isOnCurve()) {
67 throw new AssertionError();
68 }
69 if (!R.isOnCurve()) {
70 throw new AssertionError();
71 }
72 if (!ra.isOnCurve()) {
73 throw new AssertionError();
74 }
75 if (!rb.isOnCurve()) {
76 throw new AssertionError();
77 }
78 return ra.equals(rb);
87 } 79 }
88 80
89 public static EddsaSignature fromString(String value) { 81 public static EddsaSignature fromString(String value) {
diff --git a/src/main/java/org/gnunet/util/crypto/EddsaSignedMessage.java b/src/main/java/org/gnunet/util/crypto/EddsaSignedMessage.java
index 27f969a..01f0ea1 100644
--- a/src/main/java/org/gnunet/util/crypto/EddsaSignedMessage.java
+++ b/src/main/java/org/gnunet/util/crypto/EddsaSignedMessage.java
@@ -18,26 +18,6 @@
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21/*
22 This file is part of GNUnet.
23 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
24
25 GNUnet is free software; you can redistribute it and/or modify
26 it under the terms of the GNU General Public License as published
27 by the Free Software Foundation; either version 3, or (at your
28 option) any later version.
29
30 GNUnet is distributed in the hope that it will be useful, but
31 WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 General Public License for more details.
34
35 You should have received a copy of the GNU General Public License
36 along with GNUnet; see the file COPYING. If not, write to the
37 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
38 Boston, MA 02111-1307, USA.
39 */
40
41package org.gnunet.util.crypto; 21package org.gnunet.util.crypto;
42 22
43import org.gnunet.construct.Construct; 23import org.gnunet.construct.Construct;
diff --git a/src/main/java/org/gnunet/voting/Ballot.java b/src/main/java/org/gnunet/voting/Ballot.java
index 72d444f..e300010 100644
--- a/src/main/java/org/gnunet/voting/Ballot.java
+++ b/src/main/java/org/gnunet/voting/Ballot.java
@@ -180,13 +180,13 @@ public class Ballot {
180 if (!optCaPub.isPresent()) { 180 if (!optCaPub.isPresent()) {
181 throw new InvalidBallotException("no CA pub key given"); 181 throw new InvalidBallotException("no CA pub key given");
182 } 182 }
183 caPub = EcdsaPublicKey.fromStringUncompressed(optCaPub.get()); 183 caPub = EcdsaPublicKey.fromString(optCaPub.get());
184 if (null == caPub) { 184 if (null == caPub) {
185 throw new InvalidBallotException("CA pub key invalid"); 185 throw new InvalidBallotException("CA pub key invalid");
186 } 186 }
187 Optional<String> optIssuerPub = cfg.getValueString("election", "ISSUER_PUB"); 187 Optional<String> optIssuerPub = cfg.getValueString("election", "ISSUER_PUB");
188 if (optIssuerPub.isPresent()) { 188 if (optIssuerPub.isPresent()) {
189 issuerPub = EcdsaPublicKey.fromStringUncompressed(optIssuerPub.get()); 189 issuerPub = EcdsaPublicKey.fromString(optIssuerPub.get());
190 Optional<String> optIssuerSig = cfg.getValueString("election", "ISSUER_SIG"); 190 Optional<String> optIssuerSig = cfg.getValueString("election", "ISSUER_SIG");
191 if (!optIssuerSig.isPresent()) { 191 if (!optIssuerSig.isPresent()) {
192 throw new InvalidBallotException("issuer public key present, but no signature"); 192 throw new InvalidBallotException("issuer public key present, but no signature");
@@ -227,7 +227,7 @@ public class Ballot {
227 227
228 Optional<String> optVoterPub = cfg.getValueString("vote", "VOTER_PUB"); 228 Optional<String> optVoterPub = cfg.getValueString("vote", "VOTER_PUB");
229 if (optVoterPub.isPresent()) { 229 if (optVoterPub.isPresent()) {
230 voterPub = EcdsaPublicKey.fromStringUncompressed(optVoterPub.get()); 230 voterPub = EcdsaPublicKey.fromString(optVoterPub.get());
231 if (null == voterPub) { 231 if (null == voterPub) {
232 throw new InvalidBallotException("voter public key present but invalid"); 232 throw new InvalidBallotException("voter public key present but invalid");
233 } 233 }
@@ -268,15 +268,13 @@ public class Ballot {
268 digest.update(x.getKey().getBytes()); 268 digest.update(x.getKey().getBytes());
269 digest.update(x.getValue().data); 269 digest.update(x.getValue().data);
270 } 270 }
271 digest.update(issuerPub.x);
272 digest.update(issuerPub.y); 271 digest.update(issuerPub.y);
273 digest.update(caPub.x);
274 digest.update(caPub.y); 272 digest.update(caPub.y);
275 digest.update(Longs.toByteArray(startTime.getSeconds())); 273 digest.update(Longs.toByteArray(startTime.getSeconds()));
276 digest.update(Longs.toByteArray(endTime.getSeconds())); 274 digest.update(Longs.toByteArray(endTime.getSeconds()));
277 digest.update(Longs.toByteArray(closingTime.getSeconds())); 275 digest.update(Longs.toByteArray(closingTime.getSeconds()));
278 digest.update(Longs.toByteArray(queryTime.getSeconds())); 276 digest.update(Longs.toByteArray(queryTime.getSeconds()));
279 return new HashCode(digest.digest()); 277 return HashCode.fromHashCode(digest.digest());
280 } 278 }
281 279
282 /** 280 /**
diff --git a/src/main/java/org/gnunet/voting/CertifyGroupTool.java b/src/main/java/org/gnunet/voting/CertifyGroupTool.java
index b8d267a..ec82eba 100644
--- a/src/main/java/org/gnunet/voting/CertifyGroupTool.java
+++ b/src/main/java/org/gnunet/voting/CertifyGroupTool.java
@@ -109,7 +109,7 @@ public class CertifyGroupTool extends Program {
109 setReturnValue(1); 109 setReturnValue(1);
110 return; 110 return;
111 } 111 }
112 final EcdsaPublicKey memberPubKey = EcdsaPublicKey.fromStringUncompressed(memberPubKeyString); 112 final EcdsaPublicKey memberPubKey = EcdsaPublicKey.fromString(memberPubKeyString);
113 if (null == memberPubKey) { 113 if (null == memberPubKey) {
114 System.err.println("not a valid pubkey: '" + memberPubKeyString + "'"); 114 System.err.println("not a valid pubkey: '" + memberPubKeyString + "'");
115 setReturnValue(1); 115 setReturnValue(1);
diff --git a/src/main/java/org/gnunet/voting/GroupCert.java b/src/main/java/org/gnunet/voting/GroupCert.java
index 2e64101..296aae7 100644
--- a/src/main/java/org/gnunet/voting/GroupCert.java
+++ b/src/main/java/org/gnunet/voting/GroupCert.java
@@ -114,11 +114,11 @@ public class GroupCert {
114 throw new InvalidGroupCertException("invalid signature in group cert"); 114 throw new InvalidGroupCertException("invalid signature in group cert");
115 } 115 }
116 groupCert.expiration = AbsoluteTime.fromSeconds(optExpiration.get()); 116 groupCert.expiration = AbsoluteTime.fromSeconds(optExpiration.get());
117 groupCert.signerPublicKey = EcdsaPublicKey.fromStringUncompressed(optCa.get()); 117 groupCert.signerPublicKey = EcdsaPublicKey.fromString(optCa.get());
118 if (null == groupCert.signerPublicKey) { 118 if (null == groupCert.signerPublicKey) {
119 throw new InvalidGroupCertException("invalid CA in group cert"); 119 throw new InvalidGroupCertException("invalid CA in group cert");
120 } 120 }
121 groupCert.member = EcdsaPublicKey.fromStringUncompressed(optMember.get()); 121 groupCert.member = EcdsaPublicKey.fromString(optMember.get());
122 if (null == groupCert.member) { 122 if (null == groupCert.member) {
123 throw new InvalidGroupCertException("invalid member in group cert"); 123 throw new InvalidGroupCertException("invalid member in group cert");
124 } 124 }
diff --git a/src/test/java/org/gnunet/util/EcdheTest.java b/src/test/java/org/gnunet/util/EcdheTest.java
new file mode 100644
index 0000000..4d789e2
--- /dev/null
+++ b/src/test/java/org/gnunet/util/EcdheTest.java
@@ -0,0 +1,79 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.util;
22
23import org.gnunet.util.crypto.EcdhePrivateKey;
24import org.gnunet.util.crypto.EcdhePublicKey;
25import org.junit.Assert;
26import org.junit.Test;
27
28/**
29 * Test ECDHE.
30 */
31public class EcdheTest {
32
33 /**
34 * Test whether the key is correctly restored when serializing it.
35 */
36 @Test
37 public void test_compress() {
38 EcdhePrivateKey privKey1 = EcdhePrivateKey.createRandom();
39 EcdhePublicKey pubKey1 = privKey1.getPublicKey();
40 EcdhePublicKey pubKey2 = new EcdhePublicKey(pubKey1.asPoint());
41 Assert.assertArrayEquals(pubKey1.y, pubKey2.y);
42 }
43
44 /**
45 * Test a single ecdh operation.
46 */
47 @Test
48 public void test_simple() {
49 EcdhePrivateKey privKey1 = EcdhePrivateKey.createRandom();
50 EcdhePrivateKey privKey2 = EcdhePrivateKey.createRandom();
51 EcdhePublicKey pubKey1 = privKey1.getPublicKey();
52 EcdhePublicKey pubKey2 = privKey2.getPublicKey();
53
54 HashCode h1 = privKey1.ecdh(pubKey2);
55 HashCode h2 = privKey2.ecdh(pubKey1);
56
57 Assert.assertArrayEquals(h1.data, h2.data);
58 }
59
60 /**
61 * Test with values from the C GNUnet implementation.
62 * Generated with 'gnunet-ecc -E'
63 */
64 @Test
65 public void test_gnunet_values() {
66 EcdhePrivateKey privKey1 = new EcdhePrivateKey();
67 privKey1.d = new byte[32];
68 EcdhePrivateKey privKey2 = new EcdhePrivateKey();
69 privKey2.d = new byte[32];
70 Strings.stringToData("FH7DONLOP82RMELK26NDEP8655HQFU9LUO36LNO1ENOJ5KOSRR00", privKey1.d);
71 Strings.stringToData("LAJES5PBR68MJQP067I7DLJO3RUGG0EUHSOAVOFIDF24KBDE0SEG", privKey2.d);
72
73 EcdhePublicKey pubKey1 = privKey1.getPublicKey();
74 EcdhePublicKey pubKey2 = privKey2.getPublicKey();
75
76 Assert.assertEquals("VU5U4KNC3OH5RUL6M5T6BPH52BFBICEG5Q60A43V97HQV1VD3AG0", pubKey1.toString());
77 Assert.assertEquals("8DSB6D0OKS1SD71BKRTVT8OK18Q73Q7MUALJ76V9DQJO6J0170RG", pubKey2.toString());
78 }
79}
diff --git a/src/test/java/org/gnunet/util/EcdsaTest.java b/src/test/java/org/gnunet/util/EcdsaTest.java
new file mode 100644
index 0000000..898bc9a
--- /dev/null
+++ b/src/test/java/org/gnunet/util/EcdsaTest.java
@@ -0,0 +1,45 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.util;
22
23import org.gnunet.util.crypto.*;
24import org.junit.Assert;
25import org.junit.Test;
26
27public class EcdsaTest {
28 @Test
29 public void test_sign_success() {
30 byte[] data = "GNUnet".getBytes();
31 EcdsaPrivateKey privateKey = EcdsaPrivateKey.createRandom();
32 EcdsaPublicKey publicKey = privateKey.getPublicKey();
33 EcdsaSignature signature = privateKey.sign(publicKey, 0, data);
34 Assert.assertTrue(signature.verify(data, 0, publicKey));
35 }
36
37 @Test
38 public void test_sign_failure() {
39 byte[] data = "GNUnet".getBytes();
40 EcdsaPrivateKey privateKey = EcdsaPrivateKey.createRandom();
41 EcdsaPublicKey publicKey = privateKey.getPublicKey();
42 EcdsaSignature signature = EcdsaSignature.randomGarbage();
43 Assert.assertFalse(signature.verify(data, 0, publicKey));
44 }
45}
diff --git a/src/test/java/org/gnunet/util/Ed25519Test.java b/src/test/java/org/gnunet/util/Ed25519Test.java
new file mode 100644
index 0000000..4ae39a7
--- /dev/null
+++ b/src/test/java/org/gnunet/util/Ed25519Test.java
@@ -0,0 +1,142 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21package org.gnunet.util;
22
23import org.gnunet.util.crypto.Ed25519;
24import org.junit.Assert;
25import org.junit.Test;
26
27import java.math.BigInteger;
28import java.util.Random;
29
30public class Ed25519Test {
31
32 /**
33 * Simple test for commutativity.
34 */
35 @Test
36 public void test_commutative() {
37 Ed25519 p1 = Ed25519.B.scalarmult(BigInteger.valueOf(42)).scalarmult(BigInteger.valueOf(100));
38 Ed25519 p2 = Ed25519.B.scalarmult(BigInteger.valueOf(100)).scalarmult(BigInteger.valueOf(42));
39
40 byte[] data1 = p1.encode();
41 byte[] data2 = p2.encode();
42 Assert.assertArrayEquals(data1, data2);
43 }
44
45
46 /**
47 * Raw ECDH check.
48 */
49 //@Test
50 public void test_ecdh() {
51 for (int i = 0; i < 5; ++i) {
52 System.out.println("try " + i);
53 byte[] d1 = new byte[32];
54 byte[] d2 = new byte[32];
55 Random r = new Random();
56 r.nextBytes(d1);
57 r.nextBytes(d2);
58 d1[0] &= 248;
59 d1[31] &= 127;
60 d1[31] |= 64;
61 d2[0] &= 248;
62 d2[31] &= 127;
63 d2[31] |= 64;
64
65
66 Ed25519 pk1 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d1));
67 Ed25519 pk2 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d2));
68 byte[] pk1Data = pk1.encode();
69 byte[] pk2Data = pk2.encode();
70
71 Assert.assertEquals(pk1, Ed25519.decode(pk1Data));
72 Assert.assertEquals(pk2, Ed25519.decode(pk2Data));
73
74
75
76 byte[] data1 = Ed25519.decode(pk1Data).scalarmult(Ed25519.decodeScalar(d2)).encode();
77 byte[] data2 = Ed25519.decode(pk2Data).scalarmult(Ed25519.decodeScalar(d1)).encode();
78
79
80
81 /*
82 Ed25519 p1 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d1)).scalarmult(Ed25519.decodeScalar(d2));
83 Ed25519 p2 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d2)).scalarmult(Ed25519.decodeScalar(d1));
84 byte[] data1 = p1.encode();
85 byte[] data2 = p2.encode();
86 */
87
88 Assert.assertArrayEquals(data1, data2);
89 }
90 }
91
92 /**
93 * Test if decode is the inverse of encode.
94 */
95 //@Test
96 public void test_encode_inverse() {
97 Random r = new Random();
98 for (int i = 0; i < 100; i++) {
99 byte[] d1 = new byte[32];
100 r.nextBytes(d1);
101 d1[31] &= 127;
102 Ed25519 p1 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d1));
103 // encode and decode the same value!
104 byte[] data1 = p1.encode();
105 Ed25519 p2 = Ed25519.decode(data1);
106 Assert.assertEquals(p1, p2);
107 Assert.assertArrayEquals(p1.encode(), p2.encode());
108 }
109 }
110
111 @Test
112 public void test_encode_inverse_simple() {
113 Ed25519 p1 = Ed25519.B;
114 // encode and decode the same value!
115 byte[] data1 = p1.encode();
116 for (int i = 0; i < 32; i++) {
117 System.out.print(data1[i] + " ");
118 }
119 System.out.println();
120 Ed25519 p2 = Ed25519.decode(data1);
121 Assert.assertArrayEquals(p1.encode(), p2.encode());
122 Assert.assertEquals(p1, p2);
123 }
124
125 /**
126 *
127 */
128 @Test
129 public void test_encode_scalar() {
130 Random r = new Random();
131 for (int i = 0; i < 10; i++) {
132 byte[] d1 = new byte[32];
133 r.nextBytes(d1);
134 d1[31] &= 127;
135 BigInteger s1 = Ed25519.decodeScalar(d1);
136 byte[] d2 = Ed25519.encodeScalar(s1);
137 BigInteger s2 = Ed25519.decodeScalar(d2);
138 Assert.assertEquals(s1, s2);
139 Assert.assertArrayEquals(d1, d2);
140 }
141 }
142}
diff --git a/src/test/java/org/gnunet/util/EddsaTest.java b/src/test/java/org/gnunet/util/EddsaTest.java
index 302751b..4296440 100644
--- a/src/test/java/org/gnunet/util/EddsaTest.java
+++ b/src/test/java/org/gnunet/util/EddsaTest.java
@@ -30,10 +30,19 @@ import org.junit.Test;
30public class EddsaTest { 30public class EddsaTest {
31 @Test 31 @Test
32 public void test_eddsa_sign_success() { 32 public void test_eddsa_sign_success() {
33 byte[] data = "foo".getBytes(); 33 byte[] data = "GNUnet".getBytes();
34 EddsaPrivateKey privateKey = EddsaPrivateKey.createRandom(); 34 EddsaPrivateKey privateKey = EddsaPrivateKey.createRandom();
35 EddsaPublicKey publicKey = privateKey.getPublicKey(); 35 EddsaPublicKey publicKey = privateKey.getPublicKey();
36 EddsaSignature signature = privateKey.sign(publicKey, 0, data); 36 EddsaSignature signature = privateKey.sign(publicKey, 0, data);
37 Assert.assertTrue(signature.verify(data, 0, publicKey)); 37 Assert.assertTrue(signature.verify(data, 0, publicKey));
38 } 38 }
39
40 @Test
41 public void test_eddsa_sign_failure() {
42 byte[] data = "GNUnet".getBytes();
43 EddsaPrivateKey privateKey = EddsaPrivateKey.createRandom();
44 EddsaPublicKey publicKey = privateKey.getPublicKey();
45 EddsaSignature signature = EddsaSignature.randomGarbage();
46 Assert.assertFalse(signature.verify(data, 0, publicKey));
47 }
39} 48}