#!/usr/bin/perl -w
my
%opts
;
Getopt::Long::Configure(
'no_ignore_case'
);
GetOptions(\
%opts
,
"b=i"
,
"f=s"
,
"l"
,
"B"
,
"p"
,
"c"
,
"q"
,
"t=s"
,
"C=s"
,
"N=s"
,
"P=s"
,
"x"
,
"X"
,
"y"
);
use
vars
qw( $VERBOSE $SSH_DIR )
;
$VERBOSE
= !
$opts
{
q};
$SSH_DIR = "$ENV{HOME}
/.ssh";
my
%types
= (
dsa
=> {
name
=>
'DSA'
,
keyfile
=>
'id_dsa'
,
},
rsa
=> {
name
=>
'RSA'
,
keyfile
=>
'id_rsa'
,
},
rsa1
=> {
name
=>
'RSA1'
,
keyfile
=>
'identity'
,
},
ecdsa521
=> {
name
=>
'ECDSA521'
,
keyfile
=>
'id_ecdsa'
,
},
ecdsa384
=> {
name
=>
'ECDSA384'
,
keyfile
=>
'id_ecdsa'
,
},
ecdsa256
=> {
name
=>
'ECDSA256'
,
keyfile
=>
'id_ecdsa'
,
},
ed25519
=> {
name
=>
'Ed25519'
,
keyfile
=>
'id_ed25519'
,
},
);
my
$type
=
$opts
{t} ||
'rsa'
;
$opts
{b} ||= 2048
if
$type
eq
'rsa'
;
$opts
{b} ||= 521
if
$type
eq
'ecdsa'
;
$type
=
$type
.
$opts
{b}
if
$type
eq
'ecdsa'
;
delete
$opts
{b}
unless
$type
=~ /^rsa/;
my
$key_type
=
$types
{
$type
}{name};
my
$def_keyfile
=
"$SSH_DIR/$types{$type}{keyfile}"
;
if
(
$opts
{p} ||
$opts
{x} ||
$opts
{y} ||
$opts
{c} ||
$opts
{l} ||
$opts
{B}) {
my
$keyfile
;
unless
(
$keyfile
=
$opts
{f}) {
$keyfile
= prompt(
"Enter file in which the key is:"
,
$def_keyfile
);
}
my
(
$pass
);
my
(
$key
,
$comment
) = Net::SSH::Perl::Key->read_private(
$key_type
,
$keyfile
,
$opts
{P});
unless
(
$key
) {
$pass
= _read_passphrase(
"Enter old passphrase: "
);
(
$key
,
$comment
) = Net::SSH::Perl::Key->read_private(
$key_type
,
$keyfile
,
$pass
);
}
die
"Bad passphrase.\n"
unless
$key
;
if
(
$opts
{p}) {
my
$new
=
$opts
{N};
unless
(
$new
) {
$new
= _read_passphrase(
"Enter new passphrase (empty for no passphrase): "
);
my
$again
= _read_passphrase(
"Enter same passphrase again: "
);
die
"Pass phrases do not match. Try again.\n"
unless
$new
eq
$again
;
}
$key
->write_private(
$keyfile
,
$new
);
}
elsif
(
$opts
{c}) {
die
"Comments are only supported for RSA1 keys.\n"
unless
$type
eq
'rsa1'
;
print
"Key now has comment '$comment'\n"
;
my
$new
=
$opts
{C};
unless
(
$new
) {
$new
= prompt(
"Enter new comment:"
);
}
$key
->write_private(
$keyfile
,
$pass
,
$new
);
write_public(
$keyfile
,
$key
,
$new
);
print
"The comment in your key file has been changed.\n"
;
}
elsif
(
$opts
{l}) {
print
$key
->size,
" "
,
$key
->fingerprint,
"\n"
;
}
elsif
(
$opts
{B}) {
print
$key
->size,
" "
,
$key
->fingerprint(
'bubblebabble'
),
"\n"
;
}
elsif
(
$opts
{y}) {
print
$key
->dump_public,
"\n"
;
}
elsif
(
$opts
{x}) {
my
$comment
=
$key
->size .
"-bit $key_type, converted from Net::SSH::Perl"
;
(
my
$pub
= encode_base64(
$key
->as_blob,
''
)) =~ s!(.{1,70})!$1\n!g;
print
qq(---- BEGIN SSH2 PUBLIC KEY ----\n)
,
qq(Comment: "$comment"\n)
,
$pub
,
qq(---- END SSH2 PUBLIC KEY ----\n)
;
}
}
elsif
(
$opts
{X}) {
my
$keyfile
;
unless
(
$keyfile
=
$opts
{f}) {
$keyfile
= prompt(
"Enter file in which the key is:"
,
$def_keyfile
);
}
my
$key
= Net::SSH::Perl::Key->new(
'DSA'
);
$key
->{dsa} = Crypt::DSA::Key->new(
Filename
=>
$keyfile
,
Type
=>
'SSH2'
);
die
"Loading key failed"
unless
$key
->{dsa};
print
$key
->write_private;
}
else
{
debug(
"Generating public/private $type key pair."
);
my
$key
= Net::SSH::Perl::Key->keygen(
$key_type
,
$opts
{b});
my
$keyfile
;
unless
(
$keyfile
=
$opts
{f}) {
$keyfile
= prompt(
"Enter file in which to save the key:"
,
$def_keyfile
);
}
my
$pass
=
$opts
{N};
unless
(
$pass
) {
$pass
= _read_passphrase(
"Enter new passphrase (empty for no passphrase): "
);
my
$again
= _read_passphrase(
"Enter same passphrase again: "
);
die
"Pass phrases do not match. Try again.\n"
unless
$pass
eq
$again
;
}
my
$comment
=
getpwuid
($<) .
'@'
. hostname;
$key
->write_private(
$keyfile
,
$pass
);
chmod
0600,
$keyfile
or
die
"Can't chmod $keyfile to 0600: $!"
;
debug(
"Your identification has been saved in $keyfile."
);
my
$pub
= write_public(
$keyfile
,
$key
,
$comment
);
debug(
"Your public key has been saved in $pub."
);
debug(
"The key fingerprint is:"
);
debug(
$key
->fingerprint);
}
sub
write_public {
my
(
$priv_keyfile
,
$key
,
$comment
) =
@_
;
$comment
||=
''
;
my
$pub
=
"$priv_keyfile.pub"
;
local
*FH
;
open
FH,
">$pub"
or
die
"Can't open public keyfile $pub: $!"
;
print
FH
$key
->dump_public;
print
FH
" "
,
$comment
,
"\n"
;
close
FH or
warn
"Can't close public keyfile $pub: $!"
;
$pub
;
}
sub
debug {
print
STDERR
"@_\n"
if
$VERBOSE
;
}
sub
prompt {
my
(
$msg
,
$def
) =
@_
;
print
"$msg "
. (
$def
?
"[$def] "
:
""
);
chomp
(
my
$ans
= <STDIN>);
$ans
?
$ans
:
$def
;
}