问题
public class FTP {
public static void main(String args[]){
JSch jsch = new JSch();
jsch.setKnownHosts("./known_hosts");
Path privateKeyPath = Paths.get("./id_dsa");
byte[] privateKey = Files.readAllBytes(privateKeyPath);
Path publicKeyPath = Paths.get("./id_dsa.pub");
byte[] publicKey = Files.readAllBytes(publicKeyPath);
// Either of the lines below work... Why?
// jsch.addIdentity("", privateKey, publicKey, null);
// or
jsch.addIdentity("", privateKey, null, null);
Session session = jsch.getSession("USER", "myHost.com", 22);
session.connect();
}
}
Setting publicKey
to null
, doesn't make a difference, I can connect either way. Why is that?
It looks like the publicKey
isn't being used, so why pass it to addIdentity
in the first place?
回答1:
It's an optimization for (some) encrypted private keys. You didn't notice any difference because you used unencrypted private keys.
If you give jsch an OpenSSL-format encrypted private key, and don't up-front provide the passphrase to decrypt it, but do provide the public key (which is never encrypted), and that keypair becomes the next choice for authentication, jsch probes the server using the publickey to determine if the server will possibly accept auth with this key. If so, jsch must prompt for the passphrase to decrypt the privatekey to actually perform authentication; if not, it skips the prompting and goes to the next possibility, if any. See the source for com.jcraft.jsch.UserAuthPublicKey.java
.
The OpenSSH client ssh
does almost the same thing. If you give it (as an option, in config or by default) an OpenSSL-format encrypted privatekey, and it finds a matching publickey, it probes first, and prompts for the passphrase to decrypt only if this key is usable. ssh
does not allow specifying the passphrase in advance like Jsch.addIdentity
, but it can use an ssh-agent
process (or substitute) that accomplishes the same thing.
OpenSSH since 6.5 also supports 'new format' key files created with ssh-keygen -o
which can have encrypted privatekey and unencrypted publickey in one file, avoiding handling publickey separately. Jsch does not (yet?) support this format, but it does support PuTTY's PPK format, which does the same thing, and thus for which you provide the single file as privatekey and no publickey.
回答2:
The private key contains the information needed to construct the public key. If jsch needs the public key, it can get it from the private key.
As an example, you can use ssh-keygen
to extract the public key from a private key file:
$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/Users/foo/.ssh/id_dsa): key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
...
$ ls -l
total 16
-rw------- 1 foo bar 668 Jan 12 16:28 key
-rw-r--r-- 1 foo bar 613 Jan 12 16:28 key.pub
$ cat key.pub
ssh-dss AAAAB3NzaC1kc3MAAACBANzp8qnI3e+iO/5KkK...
$ rm key.pub
$ ssh-keygen -y -f key
ssh-dss AAAAB3NzaC1kc3MAAACBANzp8qnI3e+iO/5KkK...
来源:https://stackoverflow.com/questions/41622662/jsch-addidentity-public-key-argument-doesnt-make-a-difference