Created
September 27, 2017 14:26
-
-
Save jpstotz/c336759aa4d67d9ab60d90a47e586e67 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.security.GeneralSecurityException; | |
import java.security.MessageDigest; | |
import java.security.PublicKey; | |
import java.util.Arrays; | |
import net.schmizz.sshj.common.Base64; | |
import net.schmizz.sshj.common.Buffer; | |
import net.schmizz.sshj.common.SSHRuntimeException; | |
import net.schmizz.sshj.common.SecurityUtils; | |
import net.schmizz.sshj.transport.verification.HostKeyVerifier; | |
public class SSHFingerprintVerifier implements HostKeyVerifier { | |
/** | |
* Valid examples: | |
* | |
* <ul> | |
* <li><code>4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21</code></li> | |
* <li><code>MD5:4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21</code></li> | |
* <li><code>SHA1:FghNYu1l/HyE/qWbdQ2mkxrd0rU</code></li> | |
* <li><code>SHA1:FghNYu1l/HyE/qWbdQ2mkxrd0rU=</code></li> | |
* <li><code>SHA256:l/SjyCoKP8jAx3d8k8MWH+UZG0gcuIR7TQRE/A3faQo</code></li> | |
* <li><code>SHA256:l/SjyCoKP8jAx3d8k8MWH+UZG0gcuIR7TQRE/A3faQo=</code></li> | |
* </ul> | |
* | |
* | |
* @param fingerprint of an SSH fingerprint in MD5 (hex), SHA-1 (base64) or SHA-256(base64) format | |
* | |
* @return | |
*/ | |
public static HostKeyVerifier getInstance(String fingerprint) { | |
try { | |
if (fingerprint.startsWith("SHA1:")) { | |
fingerprint = fingerprint.substring(5); | |
return new SSHFingerprintVerifier("SHA-1", fingerprint); | |
} | |
if (fingerprint.startsWith("SHA256:")) { | |
fingerprint = fingerprint.substring(7); | |
return new SSHFingerprintVerifier("SHA-256", fingerprint); | |
} | |
if (fingerprint.startsWith("MD5:")) { | |
fingerprint = fingerprint.substring(4); // remove the MD5: prefix | |
} | |
final String md5 = fingerprint; | |
String md5FingerprintRegex = "[0-9a-f]{2}+(:[0-9a-f]{2}+){15}+"; | |
if (!fingerprint.matches(md5FingerprintRegex)) { | |
throw new SSHRuntimeException("Invalid MD5 fingerprint: " + fingerprint); | |
} | |
// Use the old default fingerprint verifier for md5 fingerprints | |
return (new HostKeyVerifier() { | |
@Override | |
public boolean verify(String h, int p, PublicKey k) { | |
return SecurityUtils.getFingerprint(k).equals(md5); | |
} | |
}); | |
} catch (SSHRuntimeException e) { | |
throw e; | |
} catch (IOException e) { | |
throw new SSHRuntimeException(e); | |
} | |
} | |
private final String digestAlgorithm; | |
private final byte[] fingerprintData; | |
/** | |
* | |
* @param digestAlgorithm | |
* the used digest algorithm | |
* @param base64Fingerprint | |
* base64 encoded fingerprint data | |
* | |
* @throws IOException | |
*/ | |
public SSHFingerprintVerifier(String digestAlgorithm, String base64Fingerprint) throws IOException { | |
this.digestAlgorithm = digestAlgorithm; | |
// if the length is not padded with "=" chars at the end so that it is divisible by 4 the SSHJ Base64 implementation does not work correctly | |
while (base64Fingerprint.length() % 4 != 0) { | |
base64Fingerprint = base64Fingerprint + "="; | |
} | |
fingerprintData = Base64.decode(base64Fingerprint); | |
} | |
@Override | |
public boolean verify(String hostname, int port, PublicKey key) { | |
MessageDigest digest; | |
try { | |
digest = SecurityUtils.getMessageDigest(digestAlgorithm); | |
} catch (GeneralSecurityException e) { | |
throw new SSHRuntimeException(e); | |
} | |
digest.update(new Buffer.PlainBuffer().putPublicKey(key).getCompactData()); | |
byte[] digestData = digest.digest(); | |
return Arrays.equals(fingerprintData, digestData); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment