- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试从 Java keystore 中提取私钥,然后将其提供给 Ganymed SSH 以建立与公钥身份验证的连接。但是它拒绝连接。
我可以通过 Cygwin (ssh -i
) 成功连接以下程序生成的文件,但程序本身无法在同一台机器上通过身份验证。我究竟做错了什么?
我没有得到异常,Connection.authenticateWithPublicKey(String, char[], String)只是返回 false,所以这不应该是格式问题。如果我不加密私钥也没关系,结果是一样的。此外,我还能够通过 putty-gen 和 ssh-keygen 生成的文件连接到与此类似的程序。
您将需要以下内容进行编译(bouncycaSTLe 和 ganymed):
生成 keystore :
keytool -genkeypair -keystore keystore.jks -alias myalias -storepass password -keypass password -keyalg RSA -dname CN=myalias,O=example.com -storetype JKS -validity 365 -v
代码(期望主机和端口作为参数以及工作目录中的上述 keystore ):
import ch.ethz.ssh2.Connection;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import javax.xml.bind.DatatypeConverter;
import org.bouncycastle.openssl.PEMEncryptor;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
public class KeystoreGanymedSSH {
public static void main(String[] args)
throws Exception {
String keystorePath = "keystore.jks";
char[] password = "password".toCharArray();
String alias = "myalias";
String host = args[0];
int port = Integer.parseInt(args[1]);
// keystore init
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream in;
try {
in = new FileInputStream(keystorePath);
} catch (FileNotFoundException ex) {
System.out.println("Generate keystore using this command:");
System.out.println("keytool -genkeypair -keystore keystore.jks"
+ " -alias myalias -storepass password -keypass password"
+ " -keyalg RSA -dname CN=myalias,O=example.com -storetype"
+ " JKS -validity 365 -v");
throw ex;
}
try {
keystore.load(in, password);
} finally {
in.close();
}
// get public key in OpenSSH format
String authorizedKeysEntry = genAuthorizedKeysEntry(keystore, alias);
if (authorizedKeysEntry == null) {
throw new Exception("could not generate authorized_keys entry");
}
System.out.println("Public key for pasting into OpenSSH authorized_keys file (always same):");
System.out.println(authorizedKeysEntry);
System.out.println();
Writer writer;
// write to file
writer = new OutputStreamWriter(
new FileOutputStream(new File("authorized_keys")), "UTF-8");
try {
writer.write(authorizedKeysEntry);
} finally {
writer.close();
}
// obtain PEM encrypted char[]
Key key = keystore.getKey(alias, password);
writer = new CharArrayWriter();
JcaPEMWriter pw = new JcaPEMWriter(writer);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
PEMEncryptor encryptor = new JcePEMEncryptorBuilder("DES-EDE3-CBC")
.setSecureRandom(random).build(password);
pw.writeObject(key, encryptor);
pw.flush();
char[] privateKey = ((CharArrayWriter)writer).toCharArray();
System.out.println("Encrypted private key (changes on each run):");
System.out.println(new String(privateKey));
String name = "RSA".equals(key.getAlgorithm()) ? "id_rsa" : "id_dsa";
writer = new OutputStreamWriter(
new FileOutputStream(new File(name)), "UTF-8");
try {
writer.write(privateKey);
} finally {
writer.close();
}
// attempt ganymed connection
Connection connection = null;
try {
System.out.println("Connecting to " + host + ":" + port);
connection = new Connection(host, port);
connection.connect(); // no known_hosts
if (!connection.isAuthMethodAvailable(alias, "publickey")) {
System.out.println("Public key auth is not available.");
return;
}
boolean result = connection.authenticateWithPublicKey(
alias, privateKey, new String(password));
System.out.println(result ? "Authentication success." : "Authentication failure.");
} finally {
if (connection != null) {
connection.close();
}
}
}
private static String genAuthorizedKeysEntry(
KeyStore keystore, String alias) throws GeneralSecurityException, IOException {
Certificate[] chain = keystore.getCertificateChain(alias);
if (chain == null || chain.length <= 0) {
return null;
}
PublicKey publicKey = chain[0].getPublicKey();
if ("RSA".equals(publicKey.getAlgorithm())) {
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
String type = "ssh-rsa";
dos.writeInt(type.getBytes("UTF-8").length);
dos.write(type.getBytes("UTF-8"));
byte[] exponent = rsaPublicKey.getPublicExponent().toByteArray();
dos.writeInt(exponent.length);
dos.write(exponent);
byte[] modulus = rsaPublicKey.getModulus().toByteArray();
dos.writeInt(modulus.length);
dos.write(modulus);
String encoded = DatatypeConverter.printBase64Binary(
baos.toByteArray());
return type + " " + encoded + " " + alias;
} else if ("DSA".equals(publicKey.getAlgorithm())) {
DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey;
DSAParams params = dsaPublicKey.getParams();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
String type = "ssh-dss";
dos.writeInt(type.getBytes("UTF-8").length);
dos.write(type.getBytes("UTF-8"));
byte[] p = params.getP().toByteArray();
dos.writeInt(p.length);
dos.write(p);
byte[] q = params.getQ().toByteArray();
dos.writeInt(q.length);
dos.write(q);
byte[] g = params.getG().toByteArray();
dos.writeInt(g.length);
dos.write(g);
byte[] y = dsaPublicKey.getY().toByteArray();
dos.writeInt(y.length);
dos.write(y);
String encoded = DatatypeConverter.printBase64Binary(
baos.toByteArray());
return type + " " + encoded + " " + alias;
} else {
return null;
}
}
}
示例输出:
Public key for pasting into OpenSSH authorized_keys file (always same):
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCJLXgRaVdbZNuCsTgUsw2UPGdEA4La8ggQZWkevgAEMrgF+YYT2uN6BYDgD7hzs3ZTLXz2KUQLkMe7xLvimAsg6YXUi46IGEkTSOBFR0yYj+12O2BNbAxOXLIDIMBK5bsDwnuOsFedbeILFU4DaV+igJKO1zHWNbmbmd4RlfrIgH7Blfce8zSVkEdLkqEmydbg4xmj6r+MlzA5HSNZJILivb1XYNnoLjRH1SwUC8Rj6bjgBdNEXLOH0FNpCatHk9R00GaSZjcDZRKNAKnBSEIpw01TKaJlyQUTGqYGjK7UIbbafwMuYKR1rIzkyh4Usxvd3FvMdmKQSUeCnZU296YF myalias
Encrypted private key (changes on each run):
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,86DF7B50D4E319F6
QGngqwq+NXQGee7pEVROnwvIX6cyzo9QjdKtlherLCIYQjD4zagCvCd4vOUmwe0S
g/KaPeq8tanU0KB6m/WfAsgfOAkR+ujIod0hkUoCZp/Jg9LO2Me7ZFDNW/cBqbW0
CifaqDmOVgJ+HnZHJouMZyPf+To8SDdMSJZQ/3Wc2ZQn6BIhEjLzdz0hSVXGz2Gs
wmVYy4oedjB2f+dQliEnwFXBOusRMfqgiPqkdQj38voipqYBmPHUYSity0HGsRlo
KgovSeQhEDPT8GyYVJcKZLV3BUipvNvKJBP613wBZsuCtvhUNNNOfVFeTkD8+7PG
q2YzF3nasOM471EHyj18zPZ+DdPQMDPHtpVFQXJCFlf7xlGVAesPPUFJICXFE5OZ
JRAJC8+7WuT8O974uT9zDLeV5XLJRJK6o8dYXtZBK0YMpZy91b9axYDeVQh+Sfd+
V/T5RQ2osXg72lDBtz6vzeyMGj+Y9PQwZb97tdRW1X/ON4Eiiz/+1SVeDbWilo29
gMSPl4wb379Dvi7Z+b5OTGoF+F1p7Cp48sUEgIP8vPXinoOhBLdy1zq8oNVbo7PS
M5+41PKL4ao8pL9BCOALZpzP2R9LxoHjjL1auaWMzKLECtiEDvgu4GJeTVXvg7sO
yptecswVCF8fY+pV8dTtYU3vUs4UsdC9PG9IhqeRbML9dX7htsgkBmHdYAq5WOS/
RREuU+jyrCnc6kpOhIK/1wMOoIMOBnJ8EJXpMJaZtNwOQr05bOfFvozOEe35JwnP
NElP7CYBIvQrTyfrRxtJE+ntQO+uJbIvxFDY0EoQJX6YPFr0V7rnWy4W1yH0Yv6E
pmwERGYr1lbBIpxjTzTwZ3r845EUEwiwEt3+xfepBh3HUXg/mZYUw4cEz3HbzZDT
tWRPFpsBaicfatzbqvL7Teq1V8baUj1CW0wrANZbHc0FvSzuHMygub2ARgM3QAMj
L5yaITjH8/Tnbew7jPi5kSTXdNUnAJf3M/m6DC7svJtx+1Xwd0tfzp3GHYLaT+Mm
vOu8R5g/JJvBVMTzP8gyI32jDViRuHHwyFOlyJ35IrRCkW8i+aBmG1iT2WANWRai
2ujX4Gc+M2VncUdFR9MoCxUOy/7qKDcGNMpk8sgIi6Pc8SLiodueiWP3W6AXJKvs
u5akyk7jj8zq9+fe85T/cZ8lYe81hd3oA/9b/9cs8sdlhTmYjfUr1FgFHNyFPwdV
QnyayxeAy3xvoYXBBr7JrmWXLDTHghhMBHGHW7imoLNN8QZtTF+pGWzsxNcAVbEz
kmLll9ki0CUIbfufszp/b05OBC2M0EHn9uW61bwbiZfWxhfTlC2zHNHpig6zQhHu
q8n//KgHB5LDctGHoeqlUwoLbt78wd0bAD23GeZ2q1CdB6FYxoMYL8FuVOnxoUh3
fquXzH0wjv3Qm4Rwit+8zSdbD/+QbtJ2c/ZguUy4T3phI5BGzhLh2IDO8T9B6y5B
MmTyFjfZjVj+zU4F0BAIzzLlYTl332ecMj87StoNazqIF5Dj2ZqjUtF46MDeMZjO
tRvpIi8bWBm78rFNC51TZSBcfw714yOxHsPU0PqUMQMCgXawcDkTt2645/+ZZQtk
-----END RSA PRIVATE KEY-----
Connecting to 10.0.3.138:22
Authentication failure.
Edit01
我已经用 jsch 试过了和 sshj并且所有这些都无法连接。上面提取私钥的代码一定有问题。令我困惑的是我可以使用 ssh -i
进行连接。此外,如果我将上述私钥加载到 putty-gen 中,我将获得与程序输出中相同的 authorized_keys 字符串(已存在于远程计算机的 .ssh/authorized_keys
中)。但是,如果我将它保存为一个 ppk 文件,然后尝试与它建立一个 putty session ,它也不会通过(服务器拒绝了我们的 key )。
最佳答案
我发布的代码没有任何错误。这只是我的一个巨大失败。
我使用 keystore 别名作为用户名,在远程 linux 机器上作为用户帐户不存在。创建帐户后,一切正常。我正在编辑错误的 authorized_keys
文件(在其他帐户上)并期望它能够通过一些只有妖精、 unicorn 和显然是我的大脑才知道的晦涩黑魔法起作用。
至于为什么它在我执行 ssh -i
时有效... 默认值。愚蠢的默认值。我根本没有指定用户名,所以它默认为 Cygwin 当前正在使用的用户名,而且碰巧它与我正在编辑 authorized_keys
文件的远程帐户具有相同的名称。
太棒了。惊人的。刚刚好。我需要去找一座桥,让自己从现在开始跳下去。
我在代码中所做的工作适用于 ganymed、jsch 和 sshj(对其他两个 API 进行了一些小的修改)。
关于java - 使用 JKS keystore 通过 Ganymed SSH 进行公钥身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26211480/
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!