aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2015-04-04 17:17:58 -0700
committerKenny Root <kenny@the-b.org>2016-01-24 20:03:50 -0800
commit1538c32d65152d1792e6d2404f2018c9db29ab19 (patch)
tree7b24d08594569ab5a78c34be6f70496c86bbc337
parent4e80ba5fbec4e68749b395c489148fa5d704b87b (diff)
downloadsshlib-1538c32d65152d1792e6d2404f2018c9db29ab19.tar.gz
sshlib-1538c32d65152d1792e6d2404f2018c9db29ab19.tar.bz2
sshlib-1538c32d65152d1792e6d2404f2018c9db29ab19.zip
Add Ed25519 host key support
-rw-r--r--sshlib/build.gradle2
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/KnownHosts.java25
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java36
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519Key.java45
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PrivateKey.java35
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PublicKey.java35
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java13
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/signature/Ed25519Verify.java140
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/transport/KexManager.java12
-rw-r--r--sshlib/src/test/java/com/trilead/ssh2/signature/Ed25519VerifyTest.java70
10 files changed, 409 insertions, 4 deletions
diff --git a/sshlib/build.gradle b/sshlib/build.gradle
index fb266ff..5949330 100644
--- a/sshlib/build.gradle
+++ b/sshlib/build.gradle
@@ -15,7 +15,7 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.jcraft:jzlib:1.1.3'
compile 'org.connectbot:simplesocks:1.0.1'
- compile 'org.zeromq:curve25519-java:0.1.0'
+ compile 'net.vrallev.ecc:ecc-25519-java:1.0.1'
testCompile 'junit:junit:4.12'
}
diff --git a/sshlib/src/main/java/com/trilead/ssh2/KnownHosts.java b/sshlib/src/main/java/com/trilead/ssh2/KnownHosts.java
index 4e75de1..1a5f0a8 100644
--- a/sshlib/src/main/java/com/trilead/ssh2/KnownHosts.java
+++ b/sshlib/src/main/java/com/trilead/ssh2/KnownHosts.java
@@ -28,8 +28,10 @@ import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.trilead.ssh2.crypto.Base64;
+import com.trilead.ssh2.crypto.key.Ed25519PublicKey;
import com.trilead.ssh2.signature.DSASHA1Verify;
import com.trilead.ssh2.signature.ECDSASHA2Verify;
+import com.trilead.ssh2.signature.Ed25519Verify;
import com.trilead.ssh2.signature.RSASHA1Verify;
@@ -121,12 +123,22 @@ public class KnownHosts
{
ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey);
- synchronized (publicKeys) {
+ synchronized (publicKeys)
+ {
publicKeys.add(new KnownHostsEntry(hostnames, epk));
}
}
+ else if (Ed25519Verify.ED25519_ID.equals(serverHostKeyAlgorithm))
+ {
+ Ed25519PublicKey edpk = Ed25519Verify.decodeSSHEd25519PublicKey(serverHostKey);
+
+ synchronized (publicKeys)
+ {
+ publicKeys.add(new KnownHostsEntry(hostnames, edpk));
+ }
+ }
else
- throw new IOException("Unknwon host key type (" + serverHostKeyAlgorithm + ")");
+ throw new IOException("Unknown host key type (" + serverHostKeyAlgorithm + ")");
}
/**
@@ -604,6 +616,10 @@ public class KnownHosts
{
remoteKey = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey);
}
+ else if (Ed25519Verify.ED25519_ID.equals(serverHostKeyAlgorithm))
+ {
+ remoteKey = Ed25519Verify.decodeSSHEd25519PublicKey(serverHostKey);
+ }
else
throw new IllegalArgumentException("Unknown hostkey type " + serverHostKeyAlgorithm);
@@ -719,7 +735,10 @@ public class KnownHosts
throw new IllegalArgumentException("Unknown hash type " + type);
}
- if (keyType.startsWith("ecdsa-sha2-"))
+ if (Ed25519Verify.ED25519_ID.equals(keyType))
+ {
+ }
+ else if (keyType.startsWith("ecdsa-sha2-"))
{
}
else if ("ssh-rsa".equals(keyType))
diff --git a/sshlib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java b/sshlib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java
index e551495..dfafcbd 100644
--- a/sshlib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java
+++ b/sshlib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java
@@ -15,6 +15,8 @@ import java.util.Vector;
import com.trilead.ssh2.InteractiveCallback;
import com.trilead.ssh2.crypto.PEMDecoder;
+import com.trilead.ssh2.crypto.key.Ed25519PrivateKey;
+import com.trilead.ssh2.crypto.key.Ed25519PublicKey;
import com.trilead.ssh2.packets.PacketServiceAccept;
import com.trilead.ssh2.packets.PacketServiceRequest;
import com.trilead.ssh2.packets.PacketUserauthBanner;
@@ -29,6 +31,7 @@ import com.trilead.ssh2.packets.Packets;
import com.trilead.ssh2.packets.TypesWriter;
import com.trilead.ssh2.signature.DSASHA1Verify;
import com.trilead.ssh2.signature.ECDSASHA2Verify;
+import com.trilead.ssh2.signature.Ed25519Verify;
import com.trilead.ssh2.signature.RSASHA1Verify;
import com.trilead.ssh2.transport.MessageHandler;
import com.trilead.ssh2.transport.TransportManager;
@@ -276,6 +279,39 @@ public class AuthenticationManager implements MessageHandler
tm.sendMessage(ua.getPayload());
}
+ else if (key instanceof Ed25519PrivateKey)
+ {
+ Ed25519PrivateKey pk = (Ed25519PrivateKey) key;
+
+ final String algo = Ed25519Verify.ED25519_ID;
+
+ byte[] pk_enc = Ed25519Verify.encodeSSHEd25519PublicKey((Ed25519PublicKey) pair.getPublic());
+
+ TypesWriter tw = new TypesWriter();
+ {
+ byte[] H = tm.getSessionIdentifier();
+
+ tw.writeString(H, 0, H.length);
+ tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);
+ tw.writeString(user);
+ tw.writeString("ssh-connection");
+ tw.writeString("publickey");
+ tw.writeBoolean(true);
+ tw.writeString(algo);
+ tw.writeString(pk_enc, 0, pk_enc.length);
+ }
+
+ byte[] msg = tw.getBytes();
+
+ byte[] ds = Ed25519Verify.generateSignature(msg, pk);
+
+ byte[] ed_sig_enc = Ed25519Verify.encodeSSHEd25519Signature(ds);
+
+ PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user,
+ algo, pk_enc, ed_sig_enc);
+
+ tm.sendMessage(ua.getPayload());
+ }
else
{
throw new IOException("Unknown private key type returned by the PEM decoder.");
diff --git a/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519Key.java b/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519Key.java
new file mode 100644
index 0000000..5c9e549
--- /dev/null
+++ b/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519Key.java
@@ -0,0 +1,45 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2015 Kenny Root
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.trilead.ssh2.crypto.key;
+
+import java.security.Key;
+
+/**
+ * Java representation of a native Ed25519 key.
+ *
+ * @author Kenny Root
+ */
+public class Ed25519Key implements Key {
+ private final byte[] keyBytes;
+
+ protected Ed25519Key(byte[] keyBytes) {
+ this.keyBytes = keyBytes;
+ }
+
+ public String getAlgorithm() {
+ return "Ed25519";
+ }
+
+ public String getFormat() {
+ return "RAW";
+ }
+
+ public byte[] getEncoded() {
+ return keyBytes;
+ }
+}
diff --git a/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PrivateKey.java b/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PrivateKey.java
new file mode 100644
index 0000000..05ab4ee
--- /dev/null
+++ b/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PrivateKey.java
@@ -0,0 +1,35 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2015 Kenny Root
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.trilead.ssh2.crypto.key;
+
+import java.security.PrivateKey;
+
+/**
+ * Java representation of a native Ed25519 key.
+ *
+ * @author Kenny Root
+ */
+public class Ed25519PrivateKey extends Ed25519Key implements PrivateKey {
+ private Ed25519PrivateKey(byte[] keyBytes) {
+ super(keyBytes);
+ }
+
+ public static Ed25519PrivateKey getInstance(byte[] keyBytes) {
+ return new Ed25519PrivateKey(keyBytes);
+ }
+}
diff --git a/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PublicKey.java b/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PublicKey.java
new file mode 100644
index 0000000..a4e2092
--- /dev/null
+++ b/sshlib/src/main/java/com/trilead/ssh2/crypto/key/Ed25519PublicKey.java
@@ -0,0 +1,35 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2015 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.trilead.ssh2.crypto.key;
+
+import java.security.PublicKey;
+
+/**
+ * Java representation of a native Ed25519 key.
+ *
+ * @author Kenny Root
+ */
+public class Ed25519PublicKey extends Ed25519Key implements PublicKey {
+ private Ed25519PublicKey(byte[] keyBytes) {
+ super(keyBytes);
+ }
+
+ public static Ed25519PublicKey getInstance(byte[] keyBytes) {
+ return new Ed25519PublicKey(keyBytes);
+ }
+}
diff --git a/sshlib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java b/sshlib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java
index 89cacfb..638a7d3 100644
--- a/sshlib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java
+++ b/sshlib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java
@@ -1,5 +1,18 @@
/**
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2014 Kenny Root
*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.trilead.ssh2.signature;
diff --git a/sshlib/src/main/java/com/trilead/ssh2/signature/Ed25519Verify.java b/sshlib/src/main/java/com/trilead/ssh2/signature/Ed25519Verify.java
new file mode 100644
index 0000000..e6dd036
--- /dev/null
+++ b/sshlib/src/main/java/com/trilead/ssh2/signature/Ed25519Verify.java
@@ -0,0 +1,140 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2015 Kenny Root
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.trilead.ssh2.signature;
+
+import com.trilead.ssh2.crypto.key.Ed25519PrivateKey;
+import com.trilead.ssh2.crypto.key.Ed25519PublicKey;
+import com.trilead.ssh2.log.Logger;
+import com.trilead.ssh2.packets.TypesReader;
+import com.trilead.ssh2.packets.TypesWriter;
+import net.i2p.crypto.eddsa.EdDSAEngine;
+import net.i2p.crypto.eddsa.EdDSAPrivateKey;
+import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
+import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
+import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
+import net.vrallev.java.ecc.Ecc25519Helper;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+
+/**
+ * @author Kenny Root
+ */
+public class Ed25519Verify {
+ private static final Logger log = Logger.getLogger(Ed25519Verify.class);
+
+ /** Identifies this as an Ed25519 key in the protocol. */
+ public static final String ED25519_ID = "ssh-ed25519";
+
+ private static final int ED25519_PK_SIZE_BYTES = 32;
+ private static final int ED25519_SIG_SIZE_BYTES = 64;
+
+ public static byte[] encodeSSHEd25519PublicKey(Ed25519PublicKey key) {
+ TypesWriter tw = new TypesWriter();
+
+ tw.writeString(ED25519_ID);
+ tw.writeBytes(key.getEncoded());
+
+ return tw.getBytes();
+ }
+
+ public static Ed25519PublicKey decodeSSHEd25519PublicKey(byte[] key) throws IOException {
+ TypesReader tr = new TypesReader(key);
+
+ String key_format = tr.readString();
+ if (key_format.equals(ED25519_ID) == false) {
+ throw new IOException("This is not an Ed25519 key");
+ }
+
+ byte[] keyBytes = tr.readByteString();
+
+ if (tr.remain() != 0) {
+ throw new IOException("Padding in Ed25519 public key! " + tr.remain() + " bytes left.");
+ }
+
+ if (keyBytes.length != ED25519_PK_SIZE_BYTES) {
+ throw new IOException("Ed25519 was not of correct length: " + keyBytes.length + " vs " + ED25519_PK_SIZE_BYTES);
+ }
+
+ return Ed25519PublicKey.getInstance(keyBytes);
+ }
+
+ public static byte[] generateSignature(byte[] msg, Ed25519PrivateKey privateKey) throws IOException {
+ byte[] privateKeyBytes = privateKey.getEncoded();
+
+ EdDSANamedCurveSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512);
+ EdDSAPrivateKeySpec privKeySpec = new EdDSAPrivateKeySpec(privateKeyBytes, spec);
+
+ try {
+ EdDSAEngine engine = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
+ engine.initSign(new EdDSAPrivateKey(privKeySpec));
+ engine.update(msg);
+ return engine.sign();
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException(e);
+ } catch (SignatureException e) {
+ throw new IOException(e);
+ } catch (InvalidKeyException e) {
+ throw new IOException(e);
+ }
+ }
+
+ public static boolean verifySignature(byte[] msg, byte[] sig, Ed25519PublicKey publicKey) throws IOException {
+ byte[] publicKeyBytes = publicKey.getEncoded();
+ if (publicKeyBytes.length != ED25519_PK_SIZE_BYTES) {
+ throw new IOException("Invalid Ed25519 key length " + publicKeyBytes.length);
+ }
+ Ecc25519Helper helper = new Ecc25519Helper();
+ return helper.isValidSignature(msg, sig, publicKeyBytes);
+ }
+
+ public static byte[] encodeSSHEd25519Signature(byte[] sig) {
+ TypesWriter tw = new TypesWriter();
+
+ tw.writeString(ED25519_ID);
+ tw.writeBytes(sig);
+
+ return tw.getBytes();
+ }
+
+ public static byte[] decodeSSHEd25519Signature(byte[] sig) throws IOException {
+ byte[] rsArray;
+
+ TypesReader tr = new TypesReader(sig);
+
+ String sig_format = tr.readString();
+ if (sig_format.equals(ED25519_ID) == false) {
+ throw new IOException("Peer sent wrong signature format");
+ }
+
+ rsArray = tr.readByteString();
+
+ if (tr.remain() != 0) {
+ throw new IOException("Padding in Ed25519 signature!");
+ }
+
+ if (rsArray.length > ED25519_SIG_SIZE_BYTES) {
+ throw new IOException("Ed25519 signature was " + rsArray.length + " bytes (" + ED25519_PK_SIZE_BYTES + " expected)");
+ }
+
+ return rsArray;
+ }
+}
diff --git a/sshlib/src/main/java/com/trilead/ssh2/transport/KexManager.java b/sshlib/src/main/java/com/trilead/ssh2/transport/KexManager.java
index 741268b..ab6d0b6 100644
--- a/sshlib/src/main/java/com/trilead/ssh2/transport/KexManager.java
+++ b/sshlib/src/main/java/com/trilead/ssh2/transport/KexManager.java
@@ -25,6 +25,7 @@ import com.trilead.ssh2.crypto.dh.Curve25519Exchange;
import com.trilead.ssh2.crypto.dh.DhGroupExchange;
import com.trilead.ssh2.crypto.dh.GenericDhExchange;
import com.trilead.ssh2.crypto.digest.MAC;
+import com.trilead.ssh2.crypto.key.Ed25519PublicKey;
import com.trilead.ssh2.log.Logger;
import com.trilead.ssh2.packets.PacketKexDHInit;
import com.trilead.ssh2.packets.PacketKexDHReply;
@@ -38,6 +39,7 @@ import com.trilead.ssh2.packets.PacketNewKeys;
import com.trilead.ssh2.packets.Packets;
import com.trilead.ssh2.signature.DSASHA1Verify;
import com.trilead.ssh2.signature.ECDSASHA2Verify;
+import com.trilead.ssh2.signature.Ed25519Verify;
import com.trilead.ssh2.signature.RSASHA1Verify;
@@ -65,6 +67,7 @@ public class KexManager
private static final Set<String> HOSTKEY_ALGS = new LinkedHashSet<String>();
static {
+ HOSTKEY_ALGS.add(Ed25519Verify.ED25519_ID);
if (supportsEc) {
HOSTKEY_ALGS.add("ecdsa-sha2-nistp256");
HOSTKEY_ALGS.add("ecdsa-sha2-nistp384");
@@ -380,6 +383,15 @@ public class KexManager
private boolean verifySignature(byte[] sig, byte[] hostkey) throws IOException
{
+ if (kxs.np.server_host_key_algo.equals(Ed25519Verify.ED25519_ID)) {
+ byte[] eds = Ed25519Verify.decodeSSHEd25519Signature(sig);
+ Ed25519PublicKey edpk = Ed25519Verify.decodeSSHEd25519PublicKey(hostkey);
+
+ log.log(50, "Verifying ed25519 signature");
+
+ return Ed25519Verify.verifySignature(kxs.H, eds, edpk);
+
+ }
if (kxs.np.server_host_key_algo.startsWith("ecdsa-sha2-"))
{
byte[] rs = ECDSASHA2Verify.decodeSSHECDSASignature(sig);
diff --git a/sshlib/src/test/java/com/trilead/ssh2/signature/Ed25519VerifyTest.java b/sshlib/src/test/java/com/trilead/ssh2/signature/Ed25519VerifyTest.java
new file mode 100644
index 0000000..f256f91
--- /dev/null
+++ b/sshlib/src/test/java/com/trilead/ssh2/signature/Ed25519VerifyTest.java
@@ -0,0 +1,70 @@
+package com.trilead.ssh2.signature;
+
+import com.trilead.ssh2.crypto.key.Ed25519PrivateKey;
+import com.trilead.ssh2.crypto.key.Ed25519PublicKey;
+import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
+import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
+import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
+import org.junit.Test;
+
+import javax.xml.bind.DatatypeConverter;
+import java.security.MessageDigest;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by kenny on 1/24/16.
+ */
+public class Ed25519VerifyTest {
+ /* Test vectors from draft-josefsson-eddsa-ed25519-03 */
+ private static final byte[] SECRET_KEY = toByteArray("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42");
+ private static final byte[] PUBLIC_KEY = toByteArray("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf");
+ private static final byte[] MESSAGE = toByteArray("616263");
+ private static final byte[] SIGNATURE = toByteArray("dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704");
+
+ private static byte[] toByteArray(String s) {
+ return DatatypeConverter.parseHexBinary(s);
+ }
+
+ @Test
+ public void verifies() throws Exception {
+ Ed25519PublicKey pubKey = Ed25519PublicKey.getInstance(PUBLIC_KEY);
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+ assertTrue(Ed25519Verify.verifySignature(md.digest(MESSAGE), SIGNATURE, pubKey));
+ }
+
+ @Test
+ public void noVerificationForInvalidData() throws Exception {
+ Ed25519PublicKey pubKey = Ed25519PublicKey.getInstance(PUBLIC_KEY);
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+ assertFalse(Ed25519Verify.verifySignature(md.digest(new byte[1]), SIGNATURE, pubKey));
+ }
+
+ @Test
+ public void signs() throws Exception {
+ Ed25519PrivateKey privKey = Ed25519PrivateKey.getInstance(SECRET_KEY);
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+ assertArrayEquals(SIGNATURE, Ed25519Verify.generateSignature(md.digest(MESSAGE), privKey));
+ }
+
+ @Test
+ public void publicKeyCalculatedCorrectly() throws Exception {
+ EdDSANamedCurveSpec spec = EdDSANamedCurveTable.getByName("ed25519-sha-512");
+ EdDSAPrivateKeySpec privKeySpec = new EdDSAPrivateKeySpec(SECRET_KEY, spec);
+ byte[] pubKeyBytes = privKeySpec.getA().toByteArray();
+ assertArrayEquals(PUBLIC_KEY, pubKeyBytes);
+ }
+
+ @Test
+ public void loopbackSuccess() throws Exception {
+ Ed25519PrivateKey privKey = Ed25519PrivateKey.getInstance(SECRET_KEY);
+ Ed25519PublicKey pubKey = Ed25519PublicKey.getInstance(PUBLIC_KEY);
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+
+ byte[] message = new byte[] { (byte) 0xA5, (byte) 0x5A };
+ byte[] digest = md.digest(message);
+
+ byte[] sig = Ed25519Verify.generateSignature(digest, privKey);
+ assertTrue(Ed25519Verify.verifySignature(digest, sig, pubKey));
+ }
+} \ No newline at end of file