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 2018/09/06 16:03:51 UTC
[41/51] [abbrv] mina-sshd git commit: [SSHD-842] Split common
utilities code from sshd-core into sshd-common (new artifact)
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/mac/BaseMac.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/mac/BaseMac.java b/sshd-common/src/main/java/org/apache/sshd/common/mac/BaseMac.java
new file mode 100644
index 0000000..e1681d4
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/mac/BaseMac.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.mac;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.sshd.common.util.security.SecurityUtils;
+
+/**
+ * Base class for <code>Mac</code> implementations based on the JCE provider.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class BaseMac implements Mac {
+
+ private final String algorithm;
+ private final int defbsize;
+ private final int bsize;
+ private final byte[] tmp;
+ private javax.crypto.Mac mac;
+ private String s;
+
+ public BaseMac(String algorithm, int bsize, int defbsize) {
+ this.algorithm = algorithm;
+ this.bsize = bsize;
+ this.defbsize = defbsize;
+ this.tmp = new byte[defbsize];
+ }
+
+ @Override
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public final int getBlockSize() {
+ return bsize;
+ }
+
+ @Override
+ public final int getDefaultBlockSize() {
+ return defbsize;
+ }
+
+ @Override
+ public void init(byte[] key) throws Exception {
+ if (key.length > defbsize) {
+ byte[] tmp = new byte[defbsize];
+ System.arraycopy(key, 0, tmp, 0, defbsize);
+ key = tmp;
+ }
+
+ SecretKeySpec skey = new SecretKeySpec(key, algorithm);
+ mac = SecurityUtils.getMac(algorithm);
+ mac.init(skey);
+ }
+
+ @Override
+ public void updateUInt(long i) {
+ tmp[0] = (byte) (i >>> 24);
+ tmp[1] = (byte) (i >>> 16);
+ tmp[2] = (byte) (i >>> 8);
+ tmp[3] = (byte) i;
+ update(tmp, 0, 4);
+ }
+
+ @Override
+ public void update(byte buf[], int offset, int len) {
+ mac.update(buf, offset, len);
+ }
+
+ @Override
+ public void doFinal(byte[] buf, int offset) throws Exception {
+ int blockSize = getBlockSize();
+ int defaultSize = getDefaultBlockSize();
+ if (blockSize != defaultSize) {
+ mac.doFinal(tmp, 0);
+ System.arraycopy(tmp, 0, buf, offset, blockSize);
+ } else {
+ mac.doFinal(buf, offset);
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (this) {
+ if (s == null) {
+ s = getClass().getSimpleName() + "[" + getAlgorithm() + "] - "
+ + " block=" + getBlockSize() + "/" + getDefaultBlockSize() + " bytes";
+ }
+ }
+
+ return s;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java b/sshd-common/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
new file mode 100644
index 0000000..5a4528d
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.mac;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.config.NamedFactoriesListParseResult;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * Provides easy access to the currently implemented macs
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public enum BuiltinMacs implements MacFactory {
+ hmacmd5(Constants.HMAC_MD5, "HmacMD5", 16, 16),
+ hmacmd596(Constants.HMAC_MD5_96, "HmacMD5", 12, 16),
+ hmacsha1(Constants.HMAC_SHA1, "HmacSHA1", 20, 20),
+ hmacsha196(Constants.HMAC_SHA1_96, "HmacSHA1", 12, 20),
+ /** See <A HREF="https://tools.ietf.org/html/rfc6668">RFC 6668</A> */
+ hmacsha256(Constants.HMAC_SHA2_256, "HmacSHA256", 32, 32),
+ /** See <A HREF="https://tools.ietf.org/html/rfc6668">RFC 6668</A> */
+ hmacsha512(Constants.HMAC_SHA2_512, "HmacSHA512", 64, 64);
+
+ public static final Set<BuiltinMacs> VALUES =
+ Collections.unmodifiableSet(EnumSet.allOf(BuiltinMacs.class));
+
+ private static final Map<String, MacFactory> EXTENSIONS =
+ new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+ private final String factoryName;
+ private final String algorithm;
+ private final int defbsize;
+ private final int bsize;
+
+ BuiltinMacs(String factoryName, String algorithm, int bsize, int defbsize) {
+ this.factoryName = factoryName;
+ this.algorithm = algorithm;
+ this.bsize = bsize;
+ this.defbsize = defbsize;
+ }
+
+ @Override
+ public Mac create() {
+ return new BaseMac(getAlgorithm(), getBlockSize(), getDefaultBlockSize());
+ }
+
+ @Override
+ public final String getName() {
+ return factoryName;
+ }
+
+ @Override
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public final int getBlockSize() {
+ return bsize;
+ }
+
+ @Override
+ public final int getDefaultBlockSize() {
+ return defbsize;
+ }
+
+ @Override
+ public final boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public final String toString() {
+ return getName();
+ }
+
+ /**
+ * Registered a {@link NamedFactory} to be available besides the built-in
+ * ones when parsing configuration
+ *
+ * @param extension The factory to register
+ * @throws IllegalArgumentException if factory instance is {@code null},
+ * or overrides a built-in one or overrides another registered factory
+ * with the same name (case <U>insensitive</U>).
+ */
+ public static void registerExtension(MacFactory extension) {
+ String name = Objects.requireNonNull(extension, "No extension provided").getName();
+ ValidateUtils.checkTrue(fromFactoryName(name) == null, "Extension overrides built-in: %s", name);
+
+ synchronized (EXTENSIONS) {
+ ValidateUtils.checkTrue(!EXTENSIONS.containsKey(name), "Extension overrides existing: %s", name);
+ EXTENSIONS.put(name, extension);
+ }
+ }
+
+ /**
+ * @return A {@link NavigableSet} of the currently registered extensions, sorted
+ * according to the factory name (case <U>insensitive</U>)
+ */
+ public static NavigableSet<MacFactory> getRegisteredExtensions() {
+ synchronized (EXTENSIONS) {
+ return GenericUtils.asSortedSet(NamedResource.BY_NAME_COMPARATOR, EXTENSIONS.values());
+ }
+ }
+
+ /**
+ * Unregisters specified extension
+ *
+ * @param name The factory name - ignored if {@code null}/empty
+ * @return The registered extension - {@code null} if not found
+ */
+ public static MacFactory unregisterExtension(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ synchronized (EXTENSIONS) {
+ return EXTENSIONS.remove(name);
+ }
+ }
+
+ /**
+ * @param s The {@link Enum}'s name - ignored if {@code null}/empty
+ * @return The matching {@link org.apache.sshd.common.mac.BuiltinMacs} whose {@link Enum#name()} matches
+ * (case <U>insensitive</U>) the provided argument - {@code null} if no match
+ */
+ public static BuiltinMacs fromString(String s) {
+ if (GenericUtils.isEmpty(s)) {
+ return null;
+ }
+
+ for (BuiltinMacs c : VALUES) {
+ if (s.equalsIgnoreCase(c.name())) {
+ return c;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param factory The {@link org.apache.sshd.common.NamedFactory} for the MAC - ignored if {@code null}
+ * @return The matching {@link org.apache.sshd.common.mac.BuiltinMacs} whose factory name matches
+ * (case <U>insensitive</U>) the digest factory name
+ * @see #fromFactoryName(String)
+ */
+ public static BuiltinMacs fromFactory(NamedFactory<Mac> factory) {
+ if (factory == null) {
+ return null;
+ } else {
+ return fromFactoryName(factory.getName());
+ }
+ }
+
+ /**
+ * @param name The factory name - ignored if {@code null}/empty
+ * @return The matching {@link BuiltinMacs} whose factory name matches
+ * (case <U>insensitive</U>) the provided name - {@code null} if no match
+ */
+ public static BuiltinMacs fromFactoryName(String name) {
+ return NamedResource.findByName(name, String.CASE_INSENSITIVE_ORDER, VALUES);
+ }
+
+ /**
+ * @param macs A comma-separated list of MACs' names - ignored
+ * if {@code null}/empty
+ * @return A {@link ParseResult} containing the successfully parsed
+ * factories and the unknown ones. <B>Note:</B> it is up to caller to
+ * ensure that the lists do not contain duplicates
+ */
+ public static ParseResult parseMacsList(String macs) {
+ return parseMacsList(GenericUtils.split(macs, ','));
+ }
+
+ public static ParseResult parseMacsList(String... macs) {
+ return parseMacsList(GenericUtils.isEmpty((Object[]) macs) ? Collections.emptyList() : Arrays.asList(macs));
+ }
+
+ public static ParseResult parseMacsList(Collection<String> macs) {
+ if (GenericUtils.isEmpty(macs)) {
+ return ParseResult.EMPTY;
+ }
+
+ List<MacFactory> factories = new ArrayList<>(macs.size());
+ List<String> unknown = Collections.emptyList();
+ for (String name : macs) {
+ MacFactory m = resolveFactory(name);
+ if (m != null) {
+ factories.add(m);
+ } else {
+ // replace the (unmodifiable) empty list with a real one
+ if (unknown.isEmpty()) {
+ unknown = new ArrayList<>();
+ }
+ unknown.add(name);
+ }
+ }
+
+ return new ParseResult(factories, unknown);
+ }
+
+ /**
+ * @param name The factory name
+ * @return The factory or {@code null} if it is neither a built-in one
+ * or a registered extension
+ */
+ public static MacFactory resolveFactory(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ MacFactory m = fromFactoryName(name);
+ if (m != null) {
+ return m;
+ }
+
+ synchronized (EXTENSIONS) {
+ return EXTENSIONS.get(name);
+ }
+ }
+
+ public static final class ParseResult extends NamedFactoriesListParseResult<Mac, MacFactory> {
+ public static final ParseResult EMPTY = new ParseResult(Collections.emptyList(), Collections.emptyList());
+
+ public ParseResult(List<MacFactory> parsed, List<String> unsupported) {
+ super(parsed, unsupported);
+ }
+ }
+
+ public static final class Constants {
+ public static final String HMAC_MD5 = "hmac-md5";
+ public static final String HMAC_MD5_96 = "hmac-md5-96";
+ public static final String HMAC_SHA1 = "hmac-sha1";
+ public static final String HMAC_SHA1_96 = "hmac-sha1-96";
+ public static final String HMAC_SHA2_256 = "hmac-sha2-256";
+ public static final String HMAC_SHA2_512 = "hmac-sha2-512";
+
+ private Constants() {
+ throw new UnsupportedOperationException("No instance allowed");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/mac/Mac.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/mac/Mac.java b/sshd-common/src/main/java/org/apache/sshd/common/mac/Mac.java
new file mode 100644
index 0000000..4b80447
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/mac/Mac.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.mac;
+
+import org.apache.sshd.common.util.NumberUtils;
+
+/**
+ * Message Authentication Code for use in SSH.
+ * It usually wraps a javax.crypto.Mac class.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Mac extends MacInformation {
+ void init(byte[] key) throws Exception;
+
+ default void update(byte[] buf) {
+ update(buf, 0, NumberUtils.length(buf));
+ }
+
+ void update(byte[] buf, int start, int len);
+
+ void updateUInt(long foo);
+
+ default byte[] doFinal() throws Exception {
+ int blockSize = getBlockSize();
+ byte[] buf = new byte[blockSize];
+ doFinal(buf);
+ return buf;
+ }
+
+ default void doFinal(byte[] buf) throws Exception {
+ doFinal(buf, 0);
+ }
+
+ void doFinal(byte[] buf, int offset) throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/mac/MacFactory.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/mac/MacFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/mac/MacFactory.java
new file mode 100644
index 0000000..4463600
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/mac/MacFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.mac;
+
+import org.apache.sshd.common.BuiltinFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+// CHECKSTYLE:OFF
+public interface MacFactory extends MacInformation, BuiltinFactory<Mac> {
+ // nothing extra
+}
+//CHECKSTYLE:ON
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/mac/MacInformation.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/mac/MacInformation.java b/sshd-common/src/main/java/org/apache/sshd/common/mac/MacInformation.java
new file mode 100644
index 0000000..583165f
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/mac/MacInformation.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.mac;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface MacInformation {
+ /**
+ * @return MAC algorithm name
+ */
+ String getAlgorithm();
+
+ /**
+ * @return MAC output block size in bytes - may be less than the default
+ * - e.g., MD5-96
+ */
+ int getBlockSize();
+
+ /**
+ * @return The "natural" MAC block size in bytes
+ */
+ int getDefaultBlockSize();
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/mac/package.html
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/mac/package.html b/sshd-common/src/main/java/org/apache/sshd/common/mac/package.html
new file mode 100644
index 0000000..52a90ca
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/mac/package.html
@@ -0,0 +1,25 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<html>
+<head>
+</head>
+<body>
+
+<a href="{@docRoot}/org/apache/sshd/common/mac/Mac.html"><code>Mac</code></a> implementations.
+
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandom.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandom.java b/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandom.java
new file mode 100644
index 0000000..2a1f825
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandom.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractRandom implements Random {
+ protected AbstractRandom() {
+ super();
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandomFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandomFactory.java
new file mode 100644
index 0000000..c1d7893
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/AbstractRandomFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractRandomFactory implements RandomFactory {
+ private final String name;
+
+ protected AbstractRandomFactory(String name) {
+ this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No name");
+ }
+
+ @Override
+ public final String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandom.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandom.java b/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandom.java
new file mode 100644
index 0000000..ba050e6
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandom.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+import java.security.SecureRandom;
+
+/**
+ * A <code>Random</code> implementation using the built-in {@link SecureRandom} PRNG.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class JceRandom extends AbstractRandom {
+ public static final String NAME = "JCE";
+
+ private byte[] tmp = new byte[16];
+ private final SecureRandom random = new SecureRandom();
+
+ public JceRandom() {
+ super();
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public synchronized void fill(byte[] foo, int start, int len) {
+ if ((start == 0) && (len == foo.length)) {
+ random.nextBytes(foo);
+ } else {
+ if (len > tmp.length) {
+ tmp = new byte[len];
+ }
+ random.nextBytes(tmp);
+ System.arraycopy(tmp, 0, foo, start, len);
+ }
+ }
+
+ @Override
+ public synchronized int random(int n) {
+ return random.nextInt(n);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java
new file mode 100644
index 0000000..450a85e
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/JceRandomFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+/**
+ * Named factory for the JCE <code>Random</code>
+ */
+public class JceRandomFactory extends AbstractRandomFactory {
+ public static final String NAME = "default";
+ public static final JceRandomFactory INSTANCE = new JceRandomFactory();
+
+ public JceRandomFactory() {
+ super(NAME);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public Random create() {
+ return new JceRandom();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/Random.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/Random.java b/sshd-common/src/main/java/org/apache/sshd/common/random/Random.java
new file mode 100644
index 0000000..6e597ef
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/Random.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+import org.apache.sshd.common.NamedResource;
+
+/**
+ * A pseudo random number generator.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Random extends NamedResource {
+ /**
+ * Fill the buffer with random values
+ *
+ * @param bytes The bytes to fill
+ * @see #fill(byte[], int, int)
+ */
+ default void fill(byte[] bytes) {
+ fill(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Fill part of bytes with random values.
+ *
+ * @param bytes byte array to be filled.
+ * @param start index to start filling at.
+ * @param len length of segment to fill.
+ */
+ void fill(byte[] bytes, int start, int len);
+
+ /**
+ * Returns a pseudo-random uniformly distributed {@code int}
+ * in the half-open range [0, n).
+ *
+ * @param n The range upper limit
+ * @return The randomly selected value in the range
+ */
+ int random(int n);
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/RandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/RandomFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/random/RandomFactory.java
new file mode 100644
index 0000000..dded06f
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/RandomFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+import org.apache.sshd.common.BuiltinFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+// CHECKSTYLE:OFF
+public interface RandomFactory extends BuiltinFactory<Random> {
+ // nothing extra
+}
+//CHECKSTYLE:ON
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
new file mode 100644
index 0000000..ce24112
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/SingletonRandomFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.random;
+
+import java.util.Objects;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.OptionalFeature;
+
+/**
+ * A random factory wrapper that uses a single random instance.
+ * The underlying random instance has to be thread safe.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SingletonRandomFactory extends AbstractRandom implements RandomFactory {
+
+ private final NamedFactory<Random> factory;
+ private final Random random;
+
+ public SingletonRandomFactory(NamedFactory<Random> factory) {
+ this.factory = Objects.requireNonNull(factory, "No factory");
+ this.random = Objects.requireNonNull(factory.create(), "No random instance created");
+ }
+
+ @Override
+ public boolean isSupported() {
+ if (factory instanceof OptionalFeature) {
+ return ((OptionalFeature) factory).isSupported();
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public void fill(byte[] bytes, int start, int len) {
+ random.fill(bytes, start, len);
+ }
+
+ @Override
+ public int random(int max) {
+ return random.random(max);
+ }
+
+ @Override
+ public String getName() {
+ return factory.getName();
+ }
+
+ @Override
+ public Random create() {
+ return this;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/random/package.html
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/random/package.html b/sshd-common/src/main/java/org/apache/sshd/common/random/package.html
new file mode 100644
index 0000000..0e94d7f
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/random/package.html
@@ -0,0 +1,25 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<html>
+<head>
+</head>
+<body>
+
+<a href="{@docRoot}/org/apache/sshd/common/random/Random.html"><code>Random</code></a> implementations.
+
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java
new file mode 100644
index 0000000..ef06d15
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Objects;
+
+import org.apache.sshd.common.util.NumberUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.security.SecurityUtils;
+
+/**
+ * Useful base class for {@link Signature} implementation
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSignature implements Signature {
+ private java.security.Signature signatureInstance;
+ private final String algorithm;
+
+ protected AbstractSignature(String algorithm) {
+ this.algorithm = ValidateUtils.checkNotNullAndNotEmpty(algorithm, "No signature algorithm specified");
+ }
+
+ @Override
+ public final String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Initializes the internal signature instance
+ *
+ * @param algo The signature's algorithm
+ * @param forSigning If {@code true} then it is being initialized for signing,
+ * otherwise for verifying a signature
+ * @return The {@link java.security.Signature} instance
+ * @throws GeneralSecurityException if failed to initialize
+ */
+ protected java.security.Signature doInitSignature(String algo, boolean forSigning) throws GeneralSecurityException {
+ return SecurityUtils.getSignature(algo);
+ }
+
+ /**
+ * @return The current {@link java.security.Signature} instance
+ * - {@code null} if not initialized
+ * @see #doInitSignature(String, boolean)
+ */
+ protected java.security.Signature getSignature() {
+ return signatureInstance;
+ }
+
+ @Override
+ public byte[] sign() throws Exception {
+ java.security.Signature signature = Objects.requireNonNull(getSignature(), "Signature not initialized");
+ return signature.sign();
+ }
+
+ @Override
+ public void initVerifier(PublicKey key) throws Exception {
+ String algo = getAlgorithm();
+ signatureInstance = Objects.requireNonNull(doInitSignature(algo, false), "No signature instance create");
+ signatureInstance.initVerify(Objects.requireNonNull(key, "No public key provided"));
+ }
+
+ @Override
+ public void initSigner(PrivateKey key) throws Exception {
+ String algo = getAlgorithm();
+ signatureInstance = Objects.requireNonNull(doInitSignature(algo, true), "No signature instance create");
+ signatureInstance.initSign(Objects.requireNonNull(key, "No private key provided"));
+ }
+
+ @Override
+ public void update(byte[] hash, int off, int len) throws Exception {
+ java.security.Signature signature = Objects.requireNonNull(getSignature(), "Signature not initialized");
+ signature.update(hash, off, len);
+ }
+
+ /**
+ * Makes an attempt to detect if the signature is encoded or pure data
+ *
+ * @param sig The original signature
+ * @return A {@link SimpleImmutableEntry} where first value is the key type and second
+ * value is the data - {@code null} if not encoded
+ */
+ protected SimpleImmutableEntry<String, byte[]> extractEncodedSignature(byte[] sig) {
+ final int dataLen = NumberUtils.length(sig);
+ // if it is encoded then we must have at least 2 UINT32 values
+ if (dataLen < (2 * Integer.BYTES)) {
+ return null;
+ }
+
+ long keyTypeLen = BufferUtils.getUInt(sig, 0, dataLen);
+ // after the key type we MUST have data bytes
+ if (keyTypeLen >= (dataLen - Integer.BYTES)) {
+ return null;
+ }
+
+ int keyTypeStartPos = Integer.BYTES;
+ int keyTypeEndPos = keyTypeStartPos + (int) keyTypeLen;
+ int remainLen = dataLen - keyTypeEndPos;
+ // must have UINT32 with the data bytes length
+ if (remainLen < Integer.BYTES) {
+ return null;
+ }
+
+ long dataBytesLen = BufferUtils.getUInt(sig, keyTypeEndPos, remainLen);
+ // make sure reported number of bytes does not exceed available
+ if (dataBytesLen > (remainLen - Integer.BYTES)) {
+ return null;
+ }
+
+ String keyType = new String(sig, keyTypeStartPos, (int) keyTypeLen, StandardCharsets.UTF_8);
+ byte[] data = new byte[(int) dataBytesLen];
+ System.arraycopy(sig, keyTypeEndPos + Integer.BYTES, data, 0, (int) dataBytesLen);
+ return new SimpleImmutableEntry<>(keyType, data);
+ }
+
+ protected boolean doVerify(byte[] data) throws SignatureException {
+ java.security.Signature signature = Objects.requireNonNull(getSignature(), "Signature not initialized");
+ return signature.verify(data);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + getAlgorithm() + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
new file mode 100644
index 0000000..7d4e1e2
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.security.spec.ECParameterSpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.NamedFactoriesListParseResult;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.security.SecurityUtils;
+
+/**
+ * Provides easy access to the currently implemented signatures
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public enum BuiltinSignatures implements SignatureFactory {
+ dsa(KeyPairProvider.SSH_DSS) {
+ @Override
+ public Signature create() {
+ return new SignatureDSA();
+ }
+ },
+ rsa(KeyPairProvider.SSH_RSA) {
+ @Override
+ public Signature create() {
+ return new SignatureRSA();
+ }
+ },
+ nistp256(KeyPairProvider.ECDSA_SHA2_NISTP256) {
+ @Override
+ public Signature create() {
+ return new SignatureECDSA.SignatureECDSA256();
+ }
+
+ @Override
+ public boolean isSupported() {
+ return SecurityUtils.isECCSupported();
+ }
+ },
+ nistp384(KeyPairProvider.ECDSA_SHA2_NISTP384) {
+ @Override
+ public Signature create() {
+ return new SignatureECDSA.SignatureECDSA384();
+ }
+
+ @Override
+ public boolean isSupported() {
+ return SecurityUtils.isECCSupported();
+ }
+ },
+ nistp521(KeyPairProvider.ECDSA_SHA2_NISTP521) {
+ @Override
+ public Signature create() {
+ return new SignatureECDSA.SignatureECDSA521();
+ }
+
+ @Override
+ public boolean isSupported() {
+ return SecurityUtils.isECCSupported();
+ }
+ },
+ ed25519(KeyPairProvider.SSH_ED25519) {
+ @Override
+ public Signature create() {
+ return SecurityUtils.getEDDSASigner();
+ }
+
+ @Override
+ public boolean isSupported() {
+ return SecurityUtils.isEDDSACurveSupported();
+ }
+ };
+
+ public static final Set<BuiltinSignatures> VALUES =
+ Collections.unmodifiableSet(EnumSet.allOf(BuiltinSignatures.class));
+
+ private static final Map<String, SignatureFactory> EXTENSIONS =
+ new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+ private final String factoryName;
+
+ BuiltinSignatures(String facName) {
+ factoryName = facName;
+ }
+
+ public static Signature getByCurveSize(ECParameterSpec params) {
+ int curveSize = ECCurves.getCurveSize(params);
+ if (curveSize <= 256) {
+ return nistp256.create();
+ } else if (curveSize <= 384) {
+ return nistp384.create();
+ } else {
+ return nistp521.create();
+ }
+ }
+
+ @Override
+ public final String getName() {
+ return factoryName;
+ }
+
+ @Override
+ public final String toString() {
+ return getName();
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ /**
+ * Registered a {@link NamedFactory} to be available besides the built-in
+ * ones when parsing configuration
+ *
+ * @param extension The factory to register
+ * @throws IllegalArgumentException if factory instance is {@code null},
+ * or overrides a built-in one or overrides another registered factory
+ * with the same name (case <U>insensitive</U>).
+ */
+ public static void registerExtension(SignatureFactory extension) {
+ String name = Objects.requireNonNull(extension, "No extension provided").getName();
+ ValidateUtils.checkTrue(fromFactoryName(name) == null, "Extension overrides built-in: %s", name);
+
+ synchronized (EXTENSIONS) {
+ ValidateUtils.checkTrue(!EXTENSIONS.containsKey(name), "Extension overrides existing: %s", name);
+ EXTENSIONS.put(name, extension);
+ }
+ }
+
+ /**
+ * @return A {@link NavigableSet} of the currently registered extensions, sorted
+ * according to the factory name (case <U>insensitive</U>)
+ */
+ public static NavigableSet<SignatureFactory> getRegisteredExtensions() {
+ synchronized (EXTENSIONS) {
+ return GenericUtils.asSortedSet(NamedResource.BY_NAME_COMPARATOR, EXTENSIONS.values());
+ }
+ }
+
+ /**
+ * Unregisters specified extension
+ *
+ * @param name The factory name - ignored if {@code null}/empty
+ * @return The registered extension - {@code null} if not found
+ */
+ public static SignatureFactory unregisterExtension(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ synchronized (EXTENSIONS) {
+ return EXTENSIONS.remove(name);
+ }
+ }
+
+ /**
+ * @param s The {@link Enum}'s name - ignored if {@code null}/empty
+ * @return The matching {@link org.apache.sshd.common.signature.BuiltinSignatures} whose {@link Enum#name()} matches
+ * (case <U>insensitive</U>) the provided argument - {@code null} if no match
+ */
+ public static BuiltinSignatures fromString(String s) {
+ if (GenericUtils.isEmpty(s)) {
+ return null;
+ }
+
+ for (BuiltinSignatures c : VALUES) {
+ if (s.equalsIgnoreCase(c.name())) {
+ return c;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param factory The {@link org.apache.sshd.common.NamedFactory} for the signature - ignored if {@code null}
+ * @return The matching {@link org.apache.sshd.common.signature.BuiltinSignatures} whose factory name matches
+ * (case <U>insensitive</U>) the digest factory name
+ * @see #fromFactoryName(String)
+ */
+ public static BuiltinSignatures fromFactory(NamedFactory<Signature> factory) {
+ if (factory == null) {
+ return null;
+ } else {
+ return fromFactoryName(factory.getName());
+ }
+ }
+
+ /**
+ * @param name The factory name - ignored if {@code null}/empty
+ * @return The matching {@link BuiltinSignatures} whose factory name matches
+ * (case <U>insensitive</U>) the provided name - {@code null} if no match
+ */
+ public static BuiltinSignatures fromFactoryName(String name) {
+ return NamedResource.findByName(name, String.CASE_INSENSITIVE_ORDER, VALUES);
+ }
+
+ /**
+ * @param sigs A comma-separated list of signatures' names - ignored
+ * if {@code null}/empty
+ * @return A {@link ParseResult} of all the {@link NamedFactory} whose
+ * name appears in the string and represent a built-in signature. Any
+ * unknown name is <U>ignored</U>. The order of the returned result
+ * is the same as the original order - bar the unknown signatures.
+ * <B>Note:</B> it is up to caller to ensure that the list does not
+ * contain duplicates
+ */
+ public static ParseResult parseSignatureList(String sigs) {
+ return parseSignatureList(GenericUtils.split(sigs, ','));
+ }
+
+ public static ParseResult parseSignatureList(String... sigs) {
+ return parseSignatureList(GenericUtils.isEmpty((Object[]) sigs) ? Collections.emptyList() : Arrays.asList(sigs));
+ }
+
+ public static ParseResult parseSignatureList(Collection<String> sigs) {
+ if (GenericUtils.isEmpty(sigs)) {
+ return ParseResult.EMPTY;
+ }
+
+ List<SignatureFactory> factories = new ArrayList<>(sigs.size());
+ List<String> unknown = Collections.emptyList();
+ for (String name : sigs) {
+ SignatureFactory s = resolveFactory(name);
+ if (s != null) {
+ factories.add(s);
+ } else {
+ // replace the (unmodifiable) empty list with a real one
+ if (unknown.isEmpty()) {
+ unknown = new ArrayList<>();
+ }
+ unknown.add(name);
+ }
+ }
+
+ return new ParseResult(factories, unknown);
+ }
+
+ /**
+ * @param name The factory name
+ * @return The factory or {@code null} if it is neither a built-in one
+ * or a registered extension
+ */
+ public static SignatureFactory resolveFactory(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ SignatureFactory s = fromFactoryName(name);
+ if (s != null) {
+ return s;
+ }
+
+ synchronized (EXTENSIONS) {
+ return EXTENSIONS.get(name);
+ }
+ }
+
+ /**
+ * Holds the result of the {@link BuiltinSignatures#parseSignatureList(String)}
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ public static final class ParseResult extends NamedFactoriesListParseResult<Signature, SignatureFactory> {
+ public static final ParseResult EMPTY = new ParseResult(Collections.emptyList(), Collections.emptyList());
+
+ public ParseResult(List<SignatureFactory> parsed, List<String> unsupported) {
+ super(parsed, unsupported);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/Signature.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/Signature.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/Signature.java
new file mode 100644
index 0000000..fd88a1d
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/Signature.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.apache.sshd.common.util.NumberUtils;
+
+/**
+ * Signature interface for SSH used to sign or verify packets
+ * Usually wraps a javax.crypto.Signature object
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Signature {
+ /**
+ * @return The signature algorithm name
+ */
+ String getAlgorithm();
+
+ /**
+ * @param key The {@link PublicKey} to be used for verifying signatures
+ * @throws Exception If failed to initialize
+ */
+ void initVerifier(PublicKey key) throws Exception;
+
+ /**
+ * @param key The {@link PrivateKey} to be used for signing
+ * @throws Exception If failed to initialize
+ */
+ void initSigner(PrivateKey key) throws Exception;
+
+ /**
+ * Update the computed signature with the given data
+ *
+ * @param hash The hash data buffer
+ * @throws Exception If failed to update
+ * @see #update(byte[], int, int)
+ */
+ default void update(byte[] hash) throws Exception {
+ update(hash, 0, NumberUtils.length(hash));
+ }
+
+ /**
+ * Update the computed signature with the given data
+ *
+ * @param hash The hash data buffer
+ * @param off Offset of hash data in buffer
+ * @param len Length of hash data
+ * @throws Exception If failed to update
+ */
+ void update(byte[] hash, int off, int len) throws Exception;
+
+ /**
+ * Verify against the given signature
+ *
+ * @param sig The signed data
+ * @return {@code true} if signature is valid
+ * @throws Exception If failed to extract signed data for validation
+ */
+ boolean verify(byte[] sig) throws Exception;
+
+ /**
+ * Compute the signature
+ *
+ * @return The signature value
+ * @throws Exception If failed to calculate the signature
+ */
+ byte[] sign() throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
new file mode 100644
index 0000000..1f552bd
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureDSA.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.io.StreamCorruptedException;
+import java.math.BigInteger;
+import java.security.SignatureException;
+import java.util.Map;
+
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.NumberUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.io.der.DERParser;
+import org.apache.sshd.common.util.io.der.DERWriter;
+
+
+/**
+ * DSA <code>Signature</code>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://tools.ietf.org/html/rfc4253#section-6.6">RFC4253 section 6.6</A>
+ */
+public class SignatureDSA extends AbstractSignature {
+ public static final String DEFAULT_ALGORITHM = "SHA1withDSA";
+
+ public static final int DSA_SIGNATURE_LENGTH = 40;
+ // result must be 40 bytes, but length of r and s may not exceed 20 bytes
+ public static final int MAX_SIGNATURE_VALUE_LENGTH = DSA_SIGNATURE_LENGTH / 2;
+
+ public SignatureDSA() {
+ this(DEFAULT_ALGORITHM);
+ }
+
+ protected SignatureDSA(String algorithm) {
+ super(algorithm);
+ }
+
+ @Override
+ public byte[] sign() throws Exception {
+ byte[] sig = super.sign();
+
+ try (DERParser parser = new DERParser(sig)) {
+ int type = parser.read();
+ if (type != 0x30) {
+ throw new StreamCorruptedException("Invalid signature format - not a DER SEQUENCE: 0x" + Integer.toHexString(type));
+ }
+
+ // length of remaining encoding of the 2 integers
+ int remainLen = parser.readLength();
+ /*
+ * There are supposed to be 2 INTEGERs, each encoded with:
+ *
+ * - one byte representing the fact that it is an INTEGER
+ * - one byte of the integer encoding length
+ * - at least one byte of integer data (zero length is not an option)
+ */
+ if (remainLen < (2 * 3)) {
+ throw new StreamCorruptedException("Invalid signature format - not enough encoded data length: " + remainLen);
+ }
+
+ BigInteger r = parser.readBigInteger();
+ BigInteger s = parser.readBigInteger();
+
+ byte[] result = new byte[DSA_SIGNATURE_LENGTH];
+ putBigInteger(r, result, 0);
+ putBigInteger(s, result, MAX_SIGNATURE_VALUE_LENGTH);
+ return result;
+ }
+ }
+
+ public static void putBigInteger(BigInteger value, byte[] result, int offset) {
+ byte[] data = value.toByteArray();
+ boolean maxExceeded = data.length > MAX_SIGNATURE_VALUE_LENGTH;
+ int dstOffset = maxExceeded ? 0 : (MAX_SIGNATURE_VALUE_LENGTH - data.length);
+ System.arraycopy(data, maxExceeded ? 1 : 0,
+ result, offset + dstOffset,
+ Math.min(MAX_SIGNATURE_VALUE_LENGTH, data.length));
+ }
+
+ @Override
+ public boolean verify(byte[] sig) throws Exception {
+ int sigLen = NumberUtils.length(sig);
+ byte[] data = sig;
+
+ if (sigLen != DSA_SIGNATURE_LENGTH) {
+ // probably some encoded data
+ Map.Entry<String, byte[]> encoding = extractEncodedSignature(sig);
+ if (encoding != null) {
+ String keyType = encoding.getKey();
+ ValidateUtils.checkTrue(KeyPairProvider.SSH_DSS.equals(keyType), "Mismatched key type: %s", keyType);
+ data = encoding.getValue();
+ sigLen = NumberUtils.length(data);
+ }
+ }
+
+ if (sigLen != DSA_SIGNATURE_LENGTH) {
+ throw new SignatureException("Bad signature length (" + sigLen + " instead of " + DSA_SIGNATURE_LENGTH + ")"
+ + " for " + BufferUtils.toHex(':', data));
+ }
+
+ byte[] rEncoding;
+ try (DERWriter w = new DERWriter(MAX_SIGNATURE_VALUE_LENGTH + 4)) { // in case length > 0x7F
+ w.writeBigInteger(data, 0, MAX_SIGNATURE_VALUE_LENGTH);
+ rEncoding = w.toByteArray();
+ }
+
+ byte[] sEncoding;
+ try (DERWriter w = new DERWriter(MAX_SIGNATURE_VALUE_LENGTH + 4)) { // in case length > 0x7F
+ w.writeBigInteger(data, MAX_SIGNATURE_VALUE_LENGTH, MAX_SIGNATURE_VALUE_LENGTH);
+ sEncoding = w.toByteArray();
+ }
+
+ int length = rEncoding.length + sEncoding.length;
+ byte[] encoded;
+ try (DERWriter w = new DERWriter(1 + length + 4)) { // in case length > 0x7F
+ w.write(0x30); // SEQUENCE
+ w.writeLength(length);
+ w.write(rEncoding);
+ w.write(sEncoding);
+ encoded = w.toByteArray();
+ }
+
+ return doVerify(encoded);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java
new file mode 100644
index 0000000..56964d3
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureECDSA.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.io.StreamCorruptedException;
+import java.math.BigInteger;
+import java.util.Map;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.der.DERParser;
+import org.apache.sshd.common.util.io.der.DERWriter;
+
+/**
+ * Signature algorithm for EC keys using ECDSA.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://tools.ietf.org/html/rfc3278#section-8.2">RFC3278 section 8.2</A>
+ */
+public class SignatureECDSA extends AbstractSignature {
+ public static class SignatureECDSA256 extends SignatureECDSA {
+ public static final String DEFAULT_ALGORITHM = "SHA256withECDSA";
+
+ public SignatureECDSA256() {
+ super(DEFAULT_ALGORITHM);
+ }
+ }
+
+ public static class SignatureECDSA384 extends SignatureECDSA {
+ public static final String DEFAULT_ALGORITHM = "SHA384withECDSA";
+
+ public SignatureECDSA384() {
+ super(DEFAULT_ALGORITHM);
+ }
+ }
+
+ public static class SignatureECDSA521 extends SignatureECDSA {
+ public static final String DEFAULT_ALGORITHM = "SHA512withECDSA";
+
+ public SignatureECDSA521() {
+ super(DEFAULT_ALGORITHM);
+ }
+ }
+
+ protected SignatureECDSA(String algo) {
+ super(algo);
+ }
+
+ @Override
+ public byte[] sign() throws Exception {
+ byte[] sig = super.sign();
+
+ try (DERParser parser = new DERParser(sig)) {
+ int type = parser.read();
+ if (type != 0x30) {
+ throw new StreamCorruptedException("Invalid signature format - not a DER SEQUENCE: 0x" + Integer.toHexString(type));
+ }
+
+ // length of remaining encoding of the 2 integers
+ int remainLen = parser.readLength();
+ /*
+ * There are supposed to be 2 INTEGERs, each encoded with:
+ *
+ * - one byte representing the fact that it is an INTEGER
+ * - one byte of the integer encoding length
+ * - at least one byte of integer data (zero length is not an option)
+ */
+ if (remainLen < (2 * 3)) {
+ throw new StreamCorruptedException("Invalid signature format - not enough encoded data length: " + remainLen);
+ }
+
+ BigInteger r = parser.readBigInteger();
+ BigInteger s = parser.readBigInteger();
+ // Write the <r,s> to its own types writer.
+ Buffer rsBuf = new ByteArrayBuffer();
+ rsBuf.putMPInt(r);
+ rsBuf.putMPInt(s);
+
+ return rsBuf.getCompactData();
+ }
+ }
+
+ @Override
+ public boolean verify(byte[] sig) throws Exception {
+ byte[] data = sig;
+ Map.Entry<String, byte[]> encoding = extractEncodedSignature(data);
+ if (encoding != null) {
+ String keyType = encoding.getKey();
+ ECCurves curve = ECCurves.fromKeyType(keyType);
+ ValidateUtils.checkNotNull(curve, "Unknown curve type: %s", keyType);
+ data = encoding.getValue();
+ }
+
+ Buffer rsBuf = new ByteArrayBuffer(data);
+ byte[] rArray = rsBuf.getMPIntAsBytes();
+ byte[] rEncoding;
+ try (DERWriter w = new DERWriter(rArray.length + 4)) { // in case length > 0x7F
+ w.writeBigInteger(rArray);
+ rEncoding = w.toByteArray();
+ }
+
+ byte[] sArray = rsBuf.getMPIntAsBytes();
+ byte[] sEncoding;
+ try (DERWriter w = new DERWriter(sArray.length + 4)) { // in case length > 0x7F
+ w.writeBigInteger(sArray);
+ sEncoding = w.toByteArray();
+ }
+
+ int remaining = rsBuf.available();
+ if (remaining != 0) {
+ throw new StreamCorruptedException("Signature had padding - remaining=" + remaining);
+ }
+
+ int length = rEncoding.length + sEncoding.length;
+ byte[] encoded;
+ try (DERWriter w = new DERWriter(1 + length + 4)) { // in case length > 0x7F
+ w.write(0x30); // SEQUENCE
+ w.writeLength(length);
+ w.write(rEncoding);
+ w.write(sEncoding);
+ encoded = w.toByteArray();
+ }
+
+ return doVerify(encoded);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactoriesManager.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactoriesManager.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactoriesManager.java
new file mode 100644
index 0000000..c9d876a
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactoriesManager.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * Manage the list of named factories for <code>Signature</code>.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface SignatureFactoriesManager {
+ /**
+ * @return The list of named <code>Signature</code> factories
+ */
+ List<NamedFactory<Signature>> getSignatureFactories();
+
+ default String getSignatureFactoriesNameList() {
+ return NamedResource.getNames(getSignatureFactories());
+ }
+
+ default List<String> getSignatureFactoriesNames() {
+ return NamedResource.getNameList(getSignatureFactories());
+ }
+
+ void setSignatureFactories(List<NamedFactory<Signature>> factories);
+
+ default void setSignatureFactoriesNameList(String names) {
+ setSignatureFactoriesNames(GenericUtils.split(names, ','));
+ }
+
+ default void setSignatureFactoriesNames(String... names) {
+ setSignatureFactoriesNames(GenericUtils.isEmpty((Object[]) names) ? Collections.emptyList() : Arrays.asList(names));
+ }
+
+ default void setSignatureFactoriesNames(Collection<String> names) {
+ BuiltinSignatures.ParseResult result = BuiltinSignatures.parseSignatureList(names);
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ List<NamedFactory<Signature>> factories =
+ (List) ValidateUtils.checkNotNullAndNotEmpty(result.getParsedFactories(), "No supported signature factories: %s", names);
+ Collection<String> unsupported = result.getUnsupportedFactories();
+ ValidateUtils.checkTrue(GenericUtils.isEmpty(unsupported), "Unsupported signature factories found: %s", unsupported);
+ setSignatureFactories(factories);
+ }
+
+ /**
+ * Attempts to use the primary manager's signature factories if not {@code null}/empty,
+ * otherwise uses the secondary ones (regardless of whether there are any...)
+ *
+ * @param primary The primary {@link SignatureFactoriesManager}
+ * @param secondary The secondary {@link SignatureFactoriesManager}
+ * @return The resolved signature factories - may be {@code null}/empty
+ * @see #getSignatureFactories(SignatureFactoriesManager)
+ */
+ static List<NamedFactory<Signature>> resolveSignatureFactories(
+ SignatureFactoriesManager primary, SignatureFactoriesManager secondary) {
+ List<NamedFactory<Signature>> factories = getSignatureFactories(primary);
+ return GenericUtils.isEmpty(factories) ? getSignatureFactories(secondary) : factories;
+ }
+
+ /**
+ * @param manager The {@link SignatureFactoriesManager} instance - ignored if {@code null}
+ * @return The associated list of named <code>Signature</code> factories or {@code null} if
+ * no manager instance
+ */
+ static List<NamedFactory<Signature>> getSignatureFactories(SignatureFactoriesManager manager) {
+ return (manager == null) ? null : manager.getSignatureFactories();
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
new file mode 100644
index 0000000..0881714
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import org.apache.sshd.common.BuiltinFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+// CHECKSTYLE:OFF
+public interface SignatureFactory extends BuiltinFactory<Signature> {
+ // nothing extra
+}
+//CHECKSTYLE:ON
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
new file mode 100644
index 0000000..ad1d37e
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.sshd.common.signature;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.interfaces.RSAKey;
+import java.util.Map;
+
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * RSA <code>Signature</code>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://tools.ietf.org/html/rfc4253#section-6.6">RFC4253 section 6.6</A>
+ */
+public class SignatureRSA extends AbstractSignature {
+ public static final String DEFAULT_ALGORITHM = "SHA1withRSA";
+
+ private int verifierSignatureSize = -1;
+
+ public SignatureRSA() {
+ super(DEFAULT_ALGORITHM);
+ }
+
+ protected SignatureRSA(String algorithm) {
+ super(algorithm);
+ }
+
+ /**
+ * @return The expected number of bytes in the signature - non-positive
+ * if not initialized or not intended to be used for verification
+ */
+ protected int getVerifierSignatureSize() {
+ return verifierSignatureSize;
+ }
+
+ @Override
+ public void initVerifier(PublicKey key) throws Exception {
+ super.initVerifier(key);
+ RSAKey rsaKey = ValidateUtils.checkInstanceOf(key, RSAKey.class, "Not an RSA key");
+ verifierSignatureSize = getVerifierSignatureSize(rsaKey);
+ }
+
+ public static int getVerifierSignatureSize(RSAKey key) {
+ BigInteger modulus = key.getModulus();
+ return (modulus.bitLength() + Byte.SIZE - 1) / Byte.SIZE;
+ }
+
+ @Override
+ public boolean verify(byte[] sig) throws Exception {
+ byte[] data = sig;
+ Map.Entry<String, byte[]> encoding = extractEncodedSignature(data);
+ if (encoding != null) {
+ String keyType = encoding.getKey();
+ ValidateUtils.checkTrue(KeyPairProvider.SSH_RSA.equals(keyType), "Mismatched key type: %s", keyType);
+ data = encoding.getValue();
+ }
+
+ int expectedSize = getVerifierSignatureSize();
+ ValidateUtils.checkTrue(expectedSize > 0, "Signature verification size has not been initialized");
+ // Pad with zero if value is trimmed
+ if (data.length < expectedSize) {
+ byte[] pad = new byte[expectedSize];
+ System.arraycopy(data, 0, pad, pad.length - data.length, data.length);
+ data = pad;
+ }
+
+ return doVerify(data);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/main/java/org/apache/sshd/common/signature/package.html
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/signature/package.html b/sshd-common/src/main/java/org/apache/sshd/common/signature/package.html
new file mode 100644
index 0000000..d1b16e4
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/signature/package.html
@@ -0,0 +1,25 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<html>
+<head>
+</head>
+<body>
+
+<a href="{@docRoot}/org/apache/sshd/common/signature/Signature.html"><code>Signature</code></a> implementations.
+
+</body>
+</html>