blob: 058472cfd287401f3abfb5f105ddb3608a5d54ac [file] [log] [blame]
/*
* 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.util.security.eddsa;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Objects;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAKey;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.security.SecurityUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public final class EdDSASecurityProviderUtils {
// See EdDSANamedCurveTable
public static final String CURVE_ED25519_SHA512 = "Ed25519";
public static final int KEY_SIZE = 256;
private EdDSASecurityProviderUtils() {
throw new UnsupportedOperationException("No instance");
}
public static Class<? extends PublicKey> getEDDSAPublicKeyType() {
return EdDSAPublicKey.class;
}
public static Class<? extends PrivateKey> getEDDSAPrivateKeyType() {
return EdDSAPrivateKey.class;
}
public static boolean isEDDSAKey(Key key) {
return getEDDSAKeySize(key) == KEY_SIZE;
}
public static int getEDDSAKeySize(Key key) {
return (SecurityUtils.isEDDSACurveSupported() && (key instanceof EdDSAKey)) ? KEY_SIZE : -1;
}
public static boolean compareEDDSAPPublicKeys(PublicKey k1, PublicKey k2) {
if (!SecurityUtils.isEDDSACurveSupported()) {
return false;
}
if ((k1 instanceof EdDSAPublicKey) && (k2 instanceof EdDSAPublicKey)) {
if (k1.equals(k2)) {
return true;
}
EdDSAPublicKey ed1 = (EdDSAPublicKey) k1;
EdDSAPublicKey ed2 = (EdDSAPublicKey) k2;
return Arrays.equals(ed1.getAbyte(), ed2.getAbyte())
&& compareEDDSAKeyParams(ed1.getParams(), ed2.getParams());
}
return false;
}
public static boolean isEDDSASignatureAlgorithm(String algorithm) {
return EdDSAEngine.SIGNATURE_ALGORITHM.equalsIgnoreCase(algorithm);
}
public static EdDSAPublicKey recoverEDDSAPublicKey(PrivateKey key) throws GeneralSecurityException {
ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
if (!(key instanceof EdDSAPrivateKey)) {
throw new InvalidKeyException("Private key is not " + SecurityUtils.EDDSA);
}
EdDSAPrivateKey prvKey = (EdDSAPrivateKey) key;
EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getAbyte(), prvKey.getParams());
KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA);
return EdDSAPublicKey.class.cast(factory.generatePublic(keySpec));
}
public static org.apache.sshd.common.signature.Signature getEDDSASignature() {
ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
return new SignatureEd25519();
}
public static boolean isEDDSAKeyFactoryAlgorithm(String algorithm) {
return SecurityUtils.EDDSA.equalsIgnoreCase(algorithm);
}
public static boolean isEDDSAKeyPairGeneratorAlgorithm(String algorithm) {
return SecurityUtils.EDDSA.equalsIgnoreCase(algorithm);
}
public static PublicKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getEDDSAPublicKeyEntryDecoder() {
ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
return Ed25519PublicKeyDecoder.INSTANCE;
}
public static PrivateKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() {
ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
return OpenSSHEd25519PrivateKeyEntryDecoder.INSTANCE;
}
public static boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) {
if (!SecurityUtils.isEDDSACurveSupported()) {
return false;
}
if ((k1 instanceof EdDSAPrivateKey) && (k2 instanceof EdDSAPrivateKey)) {
if (k1.equals(k2)) {
return true;
}
EdDSAPrivateKey ed1 = (EdDSAPrivateKey) k1;
EdDSAPrivateKey ed2 = (EdDSAPrivateKey) k2;
return Arrays.equals(ed1.getSeed(), ed2.getSeed())
&& compareEDDSAKeyParams(ed1.getParams(), ed2.getParams());
}
return false;
}
public static boolean compareEDDSAKeyParams(EdDSAParameterSpec s1, EdDSAParameterSpec s2) {
if (Objects.equals(s1, s2)) {
return true;
} else if (s1 == null || s2 == null) {
return false; // both null is covered by Objects#equals
} else {
return Objects.equals(s1.getHashAlgorithm(), s2.getHashAlgorithm())
&& Objects.equals(s1.getCurve(), s2.getCurve())
&& Objects.equals(s1.getB(), s2.getB());
}
}
public static PublicKey generateEDDSAPublicKey(byte[] seed) throws GeneralSecurityException {
if (!SecurityUtils.isEDDSACurveSupported()) {
throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " not supported");
}
EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512);
EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(seed, params);
KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA);
return factory.generatePublic(keySpec);
}
public static PrivateKey generateEDDSAPrivateKey(byte[] seed) throws GeneralSecurityException {
if (!SecurityUtils.isEDDSACurveSupported()) {
throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " not supported");
}
EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512);
EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(seed, params);
KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA);
return factory.generatePrivate(keySpec);
}
public static <B extends Buffer> B putRawEDDSAPublicKey(B buffer, PublicKey key) {
ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
EdDSAPublicKey edKey = ValidateUtils.checkInstanceOf(key, EdDSAPublicKey.class, "Not an EDDSA public key: %s", key);
byte[] seed = Ed25519PublicKeyDecoder.getSeedValue(edKey);
ValidateUtils.checkNotNull(seed, "No seed extracted from key: %s", edKey.getA());
buffer.putBytes(seed);
return buffer;
}
public static <B extends Buffer> B putEDDSAKeyPair(B buffer, PublicKey pubKey, PrivateKey prvKey) {
ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported");
ValidateUtils.checkInstanceOf(pubKey, EdDSAPublicKey.class, "Not an EDDSA public key: %s", pubKey);
ValidateUtils.checkInstanceOf(prvKey, EdDSAPrivateKey.class, "Not an EDDSA private key: %s", prvKey);
throw new UnsupportedOperationException("Full SSHD-440 implementation N/A");
}
}