Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeys.java')
-rw-r--r--bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeys.java214
1 files changed, 214 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeys.java b/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeys.java
new file mode 100644
index 000000000..1e3284d14
--- /dev/null
+++ b/bundles/org.eclipse.equinox.console.ssh/src/org/eclipse/equinox/console/internal/ssh/AuthorizedKeys.java
@@ -0,0 +1,214 @@
+/**
+ * Copyright (c) 2011 Gunnar Wagenknecht and others.
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Gunnar Wagenknecht - initial API and implementation
+ */
+package org.eclipse.equinox.console.internal.ssh;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Scanner;
+
+import org.apache.mina.util.Base64;
+
+/**
+ * Reader for 'authorized_keys' file as typically found on Unix systems.
+ */
+public class AuthorizedKeys {
+
+ public static enum KeyType {
+ RSA, DSA
+ }
+
+ public static class ParseKeyException extends IOException {
+
+ /** serialVersionUID */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param message
+ * @param cause
+ */
+ public ParseKeyException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ }
+
+ private static final String PREFIX_KEY_TYPE = "ssh-";
+ private static final String PREFIX_KEY_TYPE_DSA = "ssh-dsa ";
+ private static final String PREFIX_KEY_TYPE_RSA = "ssh-rsa ";
+ private static final String NEWLINE = "\n";
+
+ private static byte[] asBytes(final String string) {
+ try {
+ return string.getBytes("UTF-8");
+ } catch (final UnsupportedEncodingException e) {
+ return string.getBytes();
+ }
+ }
+
+ private static String asString(final byte[] bytes) {
+ try {
+ return new String(bytes, "UTF-8");
+ } catch (final UnsupportedEncodingException e) {
+ return new String(bytes);
+ }
+ }
+
+ public static void main(final String[] args) {
+ try {
+ final List<PublicKey> keys = new AuthorizedKeys(args[0]).getKeys();
+ for (final PublicKey key : keys) {
+ System.out.println(key);
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private final List<PublicKey> keys;
+
+ /**
+ * Creates a new instance.
+ *
+ * @throws FileNotFoundException
+ */
+ public AuthorizedKeys(final String authorizedKeysFile) throws FileNotFoundException, IOException {
+ // read file line-by-line
+ final File file = new File(authorizedKeysFile);
+ final Scanner scanner = new Scanner(file);
+ scanner.useDelimiter(NEWLINE);
+ int lineNumber = 0;
+ final List<PublicKey> keys = new ArrayList<PublicKey>();
+
+ try {
+ while (scanner.hasNext()) {
+ lineNumber++;
+
+ // get line (without leading and trailing blanks)
+ final String line = scanner.next().trim();
+
+ // ignore blank line and comments
+ if ((line.length() == 0) || (line.charAt(0) == '#')) {
+ continue;
+ }
+
+ // read key
+ try {
+ keys.add(readPublicKey(line));
+ } catch (final Exception e) {
+ throw new ParseKeyException("Line " + lineNumber + ": " + e.getMessage(), e);
+ }
+ }
+ } finally {
+ scanner.close();
+ }
+
+ this.keys = Collections.unmodifiableList(keys);
+ }
+
+ /**
+ * Returns the keys.
+ *
+ * @return the keys
+ */
+ public List<PublicKey> getKeys() {
+ return keys;
+ }
+
+ private BigInteger readBigInteger(final ByteBuffer buffer) {
+ final int len = buffer.getInt();
+ final byte[] bytes = new byte[len];
+ buffer.get(bytes);
+ final BigInteger pubExp = new BigInteger(bytes);
+ return pubExp;
+ }
+
+ private PublicKey readPublicKey(String line) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
+ // [options] <type> <base64> <comment>
+ final KeyType type;
+ final byte[] key;
+
+ // skip options (if any)
+ if (!line.startsWith(PREFIX_KEY_TYPE)) {
+ final int keyTypeStart = line.indexOf(PREFIX_KEY_TYPE);
+ if (keyTypeStart == -1) {
+ throw new IOException("missing key type");
+ }
+ line = line.substring(keyTypeStart);
+ }
+
+ // key type
+ if (line.startsWith(PREFIX_KEY_TYPE_DSA)) {
+ line = line.substring(PREFIX_KEY_TYPE_DSA.length());
+ type = KeyType.DSA;
+ } else if (line.startsWith(PREFIX_KEY_TYPE_RSA)) {
+ line = line.substring(PREFIX_KEY_TYPE_RSA.length());
+ type = KeyType.RSA;
+ } else {
+ throw new IOException("unsupported key type");
+ }
+
+ // key
+ final int keyEndIdx = line.indexOf(' ');
+ if (keyEndIdx != -1) {
+ key = Base64.decodeBase64(asBytes(line.substring(0, keyEndIdx)));
+ line = line.substring(keyEndIdx + 1);
+ } else {
+ key = Base64.decodeBase64(asBytes(line));
+ }
+
+ // wrap key into byte buffer
+ final ByteBuffer buffer = ByteBuffer.wrap(key);
+
+ // skip key type
+ readString(buffer);
+
+ // parse key
+ switch (type) {
+ case RSA:
+ // exponent + modulus
+ final BigInteger pubExp = readBigInteger(buffer);
+ final BigInteger mod = readBigInteger(buffer);
+ return KeyFactory.getInstance(KeyType.RSA.name()).generatePublic(new RSAPublicKeySpec(mod, pubExp));
+ case DSA:
+ // p + q+ g + y
+ final BigInteger p = readBigInteger(buffer);
+ final BigInteger q = readBigInteger(buffer);
+ final BigInteger g = readBigInteger(buffer);
+ final BigInteger y = readBigInteger(buffer);
+ return KeyFactory.getInstance(KeyType.DSA.name()).generatePublic(new DSAPublicKeySpec(y, p, q, g));
+ default:
+ throw new IOException("not implemented: " + type);
+ }
+ }
+
+ private String readString(final ByteBuffer buffer) {
+ final int len = buffer.getInt();
+ final byte[] bytes = new byte[len];
+ buffer.get(bytes);
+ return asString(bytes);
+ }
+}

Back to the top