mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 23:30:55 +03:00
Merge branch 'master' of https://github.com/xardazz/sshj
This commit is contained in:
@@ -39,6 +39,7 @@ package net.schmizz.sshj;
|
|||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
import net.schmizz.sshj.common.SecurityUtils;
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
import net.schmizz.sshj.signature.SignatureDSA;
|
import net.schmizz.sshj.signature.SignatureDSA;
|
||||||
|
import net.schmizz.sshj.signature.SignatureECDSA;
|
||||||
import net.schmizz.sshj.signature.SignatureRSA;
|
import net.schmizz.sshj.signature.SignatureRSA;
|
||||||
import net.schmizz.sshj.transport.cipher.AES128CBC;
|
import net.schmizz.sshj.transport.cipher.AES128CBC;
|
||||||
import net.schmizz.sshj.transport.cipher.AES128CTR;
|
import net.schmizz.sshj.transport.cipher.AES128CTR;
|
||||||
@@ -74,22 +75,22 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
* A {@link net.schmizz.sshj.Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
||||||
* BouncyCastle is in the classpath.
|
* BouncyCastle is in the classpath.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link ConfigImpl#setKeyExchangeFactories Key exchange}: {@link DHG14}*, {@link DHG1}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyExchangeFactories Key exchange}: {@link net.schmizz.sshj.transport.kex.DHG14}*, {@link net.schmizz.sshj.transport.kex.DHG1}</li>
|
||||||
* <li>{@link ConfigImpl#setCipherFactories Ciphers} [1]: {@link AES128CTR}, {@link AES192CTR}, {@link AES256CTR},
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setCipherFactories Ciphers} [1]: {@link net.schmizz.sshj.transport.cipher.AES128CTR}, {@link net.schmizz.sshj.transport.cipher.AES192CTR}, {@link net.schmizz.sshj.transport.cipher.AES256CTR},
|
||||||
* {@link
|
* {@link
|
||||||
* AES128CBC}, {@link AES192CBC}, {@link AES256CBC}, {@link AES192CBC}, {@link TripleDESCBC}, {@link BlowfishCBC}</li>
|
* net.schmizz.sshj.transport.cipher.AES128CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.AES256CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.TripleDESCBC}, {@link net.schmizz.sshj.transport.cipher.BlowfishCBC}</li>
|
||||||
* <li>{@link ConfigImpl#setMACFactories MAC}: {@link HMACSHA1}, {@link HMACSHA196}, {@link HMACMD5}, {@link
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setMACFactories MAC}: {@link net.schmizz.sshj.transport.mac.HMACSHA1}, {@link net.schmizz.sshj.transport.mac.HMACSHA196}, {@link net.schmizz.sshj.transport.mac.HMACMD5}, {@link
|
||||||
* HMACMD596}</li>
|
* net.schmizz.sshj.transport.mac.HMACMD596}</li>
|
||||||
* <li>{@link ConfigImpl#setCompressionFactories Compression}: {@link NoneCompression}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li>
|
||||||
* <li>{@link ConfigImpl#setSignatureFactories Signature}: {@link SignatureRSA}, {@link SignatureDSA}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setSignatureFactories Signature}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li>
|
||||||
* <li>{@link ConfigImpl#setRandomFactory PRNG}: {@link BouncyCastleRandom}* or {@link JCERandom}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory PRNG}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li>
|
||||||
* <li>{@link ConfigImpl#setFileKeyProviderFactories Key file support}: {@link PKCS8KeyFile}*, {@link
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link
|
||||||
* OpenSSHKeyFile}*</li>
|
* net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*</li>
|
||||||
* <li>{@link ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
|
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
|
||||||
@@ -100,7 +101,7 @@ public class DefaultConfig
|
|||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private static final String VERSION = "SSHJ_0_9_1";
|
private static final String VERSION = "SSHJ_0_9_2";
|
||||||
|
|
||||||
public DefaultConfig() {
|
public DefaultConfig() {
|
||||||
setVersion(VERSION);
|
setVersion(VERSION);
|
||||||
@@ -166,7 +167,7 @@ public class DefaultConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void initSignatureFactories() {
|
protected void initSignatureFactories() {
|
||||||
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory());
|
setSignatureFactories(new SignatureECDSA.Factory(), new SignatureRSA.Factory(), new SignatureDSA.Factory());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initMACFactories() {
|
protected void initMACFactories() {
|
||||||
|
|||||||
@@ -15,21 +15,24 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||||
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.*;
|
||||||
import java.security.Key;
|
import java.security.interfaces.*;
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.interfaces.DSAPrivateKey;
|
|
||||||
import java.security.interfaces.DSAPublicKey;
|
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.security.spec.DSAPublicKeySpec;
|
import java.security.spec.DSAPublicKeySpec;
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
|
||||||
/** Type of key e.g. rsa, dsa */
|
/** Type of key e.g. rsa, dsa */
|
||||||
public enum KeyType {
|
public enum KeyType {
|
||||||
|
|
||||||
|
|
||||||
/** SSH identifier for RSA keys */
|
/** SSH identifier for RSA keys */
|
||||||
RSA("ssh-rsa") {
|
RSA("ssh-rsa") {
|
||||||
@Override
|
@Override
|
||||||
@@ -96,6 +99,90 @@ public enum KeyType {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** SSH identifier for ECDSA keys */
|
||||||
|
ECDSA("ecdsa-sha2-nistp256") {
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(getClass());
|
||||||
|
@Override
|
||||||
|
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
try {
|
||||||
|
// final String algo = buf.readString(); it has been already read
|
||||||
|
final String curveName = buf.readString();
|
||||||
|
final int keyLen = buf.readUInt32AsInt();
|
||||||
|
final byte x04 = buf.readByte(); // it must be 0x04, but don't think we need that check
|
||||||
|
final byte[] x = new byte[(keyLen - 1) / 2];
|
||||||
|
final byte[] y = new byte[(keyLen - 1) / 2];
|
||||||
|
buf.readRawBytes(x);
|
||||||
|
buf.readRawBytes(y);
|
||||||
|
LOG.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s",
|
||||||
|
type,
|
||||||
|
curveName,
|
||||||
|
keyLen,
|
||||||
|
x04,
|
||||||
|
x,
|
||||||
|
y)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!NISTP_CURVE.equals(curveName)) {
|
||||||
|
throw new GeneralSecurityException("Unknown curve name");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger bigX = new BigInteger(1, x);
|
||||||
|
BigInteger bigY = new BigInteger(1, y);
|
||||||
|
|
||||||
|
X9ECParameters ecParams = NISTNamedCurves.getByName("p-256");
|
||||||
|
ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY, false);
|
||||||
|
ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(),
|
||||||
|
ecParams.getG(), ecParams.getN());
|
||||||
|
ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec);
|
||||||
|
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
|
||||||
|
|
||||||
|
PublicKey pubKey = keyFactory.generatePublic(publicSpec);
|
||||||
|
return pubKey;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new GeneralSecurityException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
|
||||||
|
final ECPublicKey ecdsa = (ECPublicKey) pk;
|
||||||
|
final java.security.spec.ECPoint point = ecdsa.getW();
|
||||||
|
final byte[] x = trimStartingZeros(point.getAffineX().toByteArray());
|
||||||
|
final byte[] y = trimStartingZeros(point.getAffineY().toByteArray());
|
||||||
|
|
||||||
|
buf.putString(sType)
|
||||||
|
.putString(NISTP_CURVE)
|
||||||
|
.putUInt32(1 + x.length + y.length)
|
||||||
|
.putRawBytes(new byte[] { (byte) 0x04 })
|
||||||
|
.putRawBytes(x)
|
||||||
|
.putRawBytes(y)
|
||||||
|
.compact()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isMyType(Key key) {
|
||||||
|
return ("ECDSA".equals(key.getAlgorithm()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] trimStartingZeros(byte[] in) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < in.length; i++) {
|
||||||
|
if (in[i] != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final byte[] out = new byte[in.length - i];
|
||||||
|
System.arraycopy(in, i, out, 0, out.length);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
/** Unrecognized */
|
/** Unrecognized */
|
||||||
UNKNOWN("unknown") {
|
UNKNOWN("unknown") {
|
||||||
@Override
|
@Override
|
||||||
@@ -117,6 +204,8 @@ public enum KeyType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static final String NISTP_CURVE = "nistp256";
|
||||||
|
|
||||||
protected final String sType;
|
protected final String sType;
|
||||||
|
|
||||||
private KeyType(String type) {
|
private KeyType(String type) {
|
||||||
|
|||||||
143
src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java
Normal file
143
src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2012 sshj contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* This file may incorporate work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* 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 net.schmizz.sshj.signature;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.Buffer;
|
||||||
|
import net.schmizz.sshj.common.KeyType;
|
||||||
|
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||||
|
|
||||||
|
import java.security.SignatureException;
|
||||||
|
|
||||||
|
/** ECDSA {@link Signature} */
|
||||||
|
public class SignatureECDSA
|
||||||
|
extends AbstractSignature {
|
||||||
|
|
||||||
|
/** A named factory for ECDSA signature */
|
||||||
|
public static class Factory
|
||||||
|
implements net.schmizz.sshj.common.Factory.Named<Signature> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Signature create() {
|
||||||
|
return new SignatureECDSA();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return KeyType.ECDSA.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignatureECDSA() {
|
||||||
|
super("SHA256withECDSA");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] sign() {
|
||||||
|
throw new UnsupportedOperationException("No implementation for sign!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(byte[] sig) {
|
||||||
|
|
||||||
|
byte[] r = null;
|
||||||
|
byte[] s = null;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
Buffer sigbuf = new Buffer.PlainBuffer(sig);
|
||||||
|
final String algo = new String(sigbuf.readBytes());
|
||||||
|
if (!"ecdsa-sha2-nistp256".equals(algo)) {
|
||||||
|
throw new SSHRuntimeException(String.format("Signature :: ecdsa-sha2-nistp256 expected, got %s", algo));
|
||||||
|
}
|
||||||
|
final int rsLen = sigbuf.readUInt32AsInt();
|
||||||
|
if (!(sigbuf.available() == rsLen)) {
|
||||||
|
throw new SSHRuntimeException("Invalid key length");
|
||||||
|
}
|
||||||
|
r = sigbuf.readBytes();
|
||||||
|
s = sigbuf.readBytes();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rLen = r.length;
|
||||||
|
int sLen = s.length;
|
||||||
|
|
||||||
|
/* We can't have the high bit set, so add an extra zero at the beginning if so. */
|
||||||
|
if ((r[0] & 0x80) != 0) {
|
||||||
|
rLen++;
|
||||||
|
}
|
||||||
|
if ((s[0] & 0x80) != 0) {
|
||||||
|
sLen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate total output length */
|
||||||
|
int length = 6 + rLen + sLen;
|
||||||
|
byte[] asn1 = new byte[length];
|
||||||
|
|
||||||
|
/* ASN.1 SEQUENCE tag */
|
||||||
|
asn1[0] = (byte) 0x30;
|
||||||
|
|
||||||
|
/* Size of SEQUENCE */
|
||||||
|
asn1[1] = (byte) (4 + rLen + sLen);
|
||||||
|
|
||||||
|
/* ASN.1 INTEGER tag */
|
||||||
|
asn1[2] = (byte) 0x02;
|
||||||
|
|
||||||
|
/* "r" INTEGER length */
|
||||||
|
asn1[3] = (byte) rLen;
|
||||||
|
|
||||||
|
/* Copy in the "r" INTEGER */
|
||||||
|
System.arraycopy(r, 0, asn1, 4, rLen);
|
||||||
|
|
||||||
|
/* ASN.1 INTEGER tag */
|
||||||
|
asn1[rLen + 4] = (byte) 0x02;
|
||||||
|
|
||||||
|
/* "s" INTEGER length */
|
||||||
|
asn1[rLen + 5] = (byte) sLen;
|
||||||
|
|
||||||
|
/* Copy in the "s" INTEGER */
|
||||||
|
System.arraycopy(s, 0, asn1, (6 + rLen), sLen);
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
return signature.verify(asn1);
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user