-#!/usr/bin/perl -w -T
+#!/usr/bin/perl -T
+
+# keytrans: this is an RSA key translation utility; it is capable of
+# transforming RSA keys (both public keys and secret keys) between
+# several popular representations, including OpenPGP, PEM-encoded
+# PKCS#1 DER, and OpenSSH-style public key lines.
+
+# How it behaves depends on the name under which it is invoked. The
+# two implementations currently are: pem2openpgp and openpgp2ssh.
+
+
# pem2openpgp: take a PEM-encoded RSA private-key on standard input, a
# User ID as the first argument, and generate an OpenPGP secret key
# pem2openpgp 'ssh://'$(hostname -f) < /etc/ssh/ssh_host_rsa_key | gpg --import
+
+
+
+# openpgp2ssh: take a stream of OpenPGP packets containing public or
+# secret key material on standard input, and a Key ID (or fingerprint)
+# as the first argument. Find the matching key in the input stream,
+# and emit it on stdout in an OpenSSH-compatible format. If the input
+# key is an OpenPGP public key (either primary or subkey), the output
+# will be an OpenSSH single-line public key. If the input key is an
+# OpenPGP secret key, the output will be a PEM-encoded RSA key.
+
+# Example usage:
+
+# gpg --export-secret-subkeys --export-options export-reset-subkey-passwd $KEYID | \
+# openpgp2ssh $KEYID | ssh-add /dev/stdin
+
+
# Authors:
# Jameson Rollins <jrollins@finestructure.net>
# Daniel Kahn Gillmor <dkg@fifthhorseman.net>
########### Math/Utility Functions ##############
-# see the bottom of page 43 of RFC 4880
+# see the bottom of page 44 of RFC 4880 (http://tools.ietf.org/html/rfc4880#page-44)
sub simple_checksum {
my $bytes = shift;
- return unpack("%32W*",$bytes) % 65536;
+ return unpack("%16C*",$bytes);
}
# calculate the multiplicative inverse of a mod b this is euclid's
my $uid = shift;
my $args = shift;
- $rsa->use_sha1_hash();
+ $rsa->use_sha256_hash();
# see page 22 of RFC 4880 for why i think this is the right padding
# choice to use:
# RSA
my $pubkey_algo = pack('C', $asym_algos->{rsa});
# SHA1
- my $hash_algo = pack('C', $digests->{sha1});
+ my $hash_algo = pack('C', $digests->{sha256});
# FIXME: i'm worried about generating a bazillion new OpenPGP
# certificates from the same key, which could easily happen if you run
$ciphers->{tripledes}
);
- # prefer SHA-1, SHA-256, RIPE-MD/160
- my $pref_hash_algos = pack('CCCCC', 4, $subpacket_types->{preferred_digest},
- $digests->{sha1},
+ # prefer SHA-512, SHA-384, SHA-256, SHA-224, RIPE-MD/160, SHA-1
+ my $pref_hash_algos = pack('CCCCCCCC', 7, $subpacket_types->{preferred_digest},
+ $digests->{sha512},
+ $digests->{sha384},
$digests->{sha256},
- $digests->{ripemd160}
+ $digests->{sha224},
+ $digests->{ripemd160},
+ $digests->{sha1}
);
# prefer ZLIB, BZip2, ZIP
my $foundfpr = fingerprint($pubkey, $timestamp);
my $foundfprstr = Crypt::OpenSSL::Bignum->new_from_bin($foundfpr)->to_hex();
+ # left-pad with 0's to bring up to full 40-char (160-bit) fingerprint:
+ $foundfprstr = sprintf("%040s", $foundfprstr);
# is this a match?
if ((!defined($fpr)) ||