You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2017/06/01 16:59:06 UTC

mina-sshd git commit: [SSHD-710] Cannot connect standard OpenSSH client/server using ed25519 keys

Repository: mina-sshd
Updated Branches:
  refs/heads/master b0c5ca22d -> 02f1d57be


[SSHD-710] Cannot connect standard OpenSSH client/server using ed25519 keys


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/02f1d57b
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/02f1d57b
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/02f1d57b

Branch: refs/heads/master
Commit: 02f1d57be9ca20d2a8ae6a3e741a94770f7c63fb
Parents: b0c5ca2
Author: Markus Woschank <ma...@gmail.com>
Authored: Thu Jun 1 16:31:54 2017 +0300
Committer: Lyor Goldstein <ly...@gmail.com>
Committed: Thu Jun 1 19:59:13 2017 +0300

----------------------------------------------------------------------
 .../eddsa/EdDSASecurityProviderUtils.java       |  2 +-
 .../OpenSSHEd25519PrivateKeyEntryDecoder.java   | 77 +++++++++++++++-----
 2 files changed, 60 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/02f1d57b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
index 24e7e5c..2ba5272 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProviderUtils.java
@@ -99,7 +99,7 @@ public final class EdDSASecurityProviderUtils {
         }
 
         EdDSAPrivateKey prvKey = (EdDSAPrivateKey) key;
-        EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getSeed(), prvKey.getParams());
+        EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getAbyte(), prvKey.getParams());
         KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA);
         return EdDSAPublicKey.class.cast(factory.generatePublic(keySpec));
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/02f1d57b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
index e83a328..4c511d5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
@@ -27,7 +27,9 @@ import java.security.InvalidKeyException;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.Locale;
 import java.util.Objects;
 
 import net.i2p.crypto.eddsa.EdDSAPrivateKey;
@@ -48,6 +50,9 @@ import org.apache.sshd.common.util.security.SecurityUtils;
  */
 public class OpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> {
     public static final OpenSSHEd25519PrivateKeyEntryDecoder INSTANCE = new OpenSSHEd25519PrivateKeyEntryDecoder();
+    private static final int PK_SIZE = 32;
+    private static final int SK_SIZE = 32;
+    private static final int KEYPAIR_SIZE = PK_SIZE + SK_SIZE;
 
     public OpenSSHEd25519PrivateKeyEntryDecoder() {
         super(EdDSAPublicKey.class, EdDSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_ED25519)));
@@ -63,32 +68,68 @@ public class OpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivateKeyEntr
         if (!SecurityUtils.isEDDSACurveSupported()) {
             throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " provider not supported");
         }
-
-        byte[] seed = KeyEntryResolver.readRLEBytes(keyData);   // a.k.a pk in OpenSSH C code
-        byte[] signature = KeyEntryResolver.readRLEBytes(keyData);   // a.k.a sk in OpenSSH C code
-        if (signature.length != seed.length * 2) {
-            throw new InvalidKeyException("Mismatched signature (" + signature.length + ") vs. seed (" + seed.length + ") length");
+        
+        // ed25519 bernstein naming: pk .. public key, sk .. secret key
+        // we expect to find two byte arrays with the following structure (type:size):
+        // [pk:32], [sk:32,pk:32]
+        
+        byte[] pk = KeyEntryResolver.readRLEBytes(keyData);
+        byte[] keypair = KeyEntryResolver.readRLEBytes(keyData);
+        
+        if (pk.length != PK_SIZE) {
+            throw new InvalidKeyException(String.format(Locale.ENGLISH, "Unexpected pk size: %s (expected %s)", pk.length, PK_SIZE));
         }
-
+        
+        if (keypair.length != KEYPAIR_SIZE) {
+            throw new InvalidKeyException(String.format(Locale.ENGLISH, "Unexpected keypair size: %s (expected %s)", keypair.length, KEYPAIR_SIZE));
+        }
+        
+        byte[] sk = Arrays.copyOf(keypair, SK_SIZE);
+        
+        // verify that the keypair contains the expected pk
+        // yes, it's stored redundant, this seems to mimic the output structure of the keypair generation interface
+        if (!Arrays.equals(pk, Arrays.copyOfRange(keypair, SK_SIZE, KEYPAIR_SIZE))) {
+            throw new InvalidKeyException("Keypair did not contain the public key.");
+        }
+        
+        // create the private key
         EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(EdDSASecurityProviderUtils.CURVE_ED25519_SHA512);
-        EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(seed, params);
-        return generatePrivateKey(keySpec);
+        EdDSAPrivateKey privateKey = generatePrivateKey(new EdDSAPrivateKeySpec(sk, params));
+        
+        // the private key class contains the calculated public key (Abyte)
+        // pointers to the corresponding code:
+        // EdDSAPrivateKeySpec.EdDSAPrivateKeySpec(byte[], EdDSAParameterSpec): A = spec.getB().scalarMultiply(a);
+        // EdDSAPrivateKey.EdDSAPrivateKey(EdDSAPrivateKeySpec): this.Abyte = this.A.toByteArray();
+        
+        // we can now verify the generated pk matches the one we read
+        if (!Arrays.equals(privateKey.getAbyte(), pk)) {
+            throw new InvalidKeyException("The provided pk does NOT match the computed pk for the given sk.");
+        }
+        
+        return privateKey;
     }
 
     @Override
     public String encodePrivateKey(OutputStream s, EdDSAPrivateKey key) throws IOException {
         Objects.requireNonNull(key, "No private key provided");
-
-        //  how
-        byte[] seed = key.getSeed();
-        Objects.requireNonNull(seed, "No ssed");
-        /* TODO see https://svn.nmap.org/ncrack/opensshlib/ed25519.c
-        byte[] signature = signEd25519KeyPair(seed);
-        KeyEntryResolver.writeRLEBytes(s, seed);
-        KeyEntryResolver.writeRLEBytes(s, signature);
+        
+        // ed25519 bernstein naming: pk .. public key, sk .. secret key
+        // we are expected to write the following arrays (type:size):
+        // [pk:32], [sk:32,pk:32]
+        
+        byte[] sk = key.getSeed();
+        byte[] pk = key.getAbyte();
+        
+        Objects.requireNonNull(sk, "No seed");
+        
+        byte[] keypair = new byte[KEYPAIR_SIZE];
+        System.arraycopy(sk, 0, keypair, 0, SK_SIZE);
+        System.arraycopy(pk, 0, keypair, SK_SIZE, PK_SIZE);
+        
+        KeyEntryResolver.writeRLEBytes(s, pk);
+        KeyEntryResolver.writeRLEBytes(s, keypair);
+        
         return KeyPairProvider.SSH_ED25519;
-        */
-        return null;
     }
 
     @Override