properly match fingerprints with leading 0 bytes (https://labs.riseup.net/code/issues...
[monkeysphere.git] / src / share / keytrans
index 8bf17fb2df6b2a2a212b1af218eac6eaad8d70d8..c47ccdc792d6cdfd98cf6fdb591ee9dae13e3969 100755 (executable)
@@ -1,4 +1,14 @@
-#!/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>
@@ -168,11 +195,11 @@ my $keyserver_prefs = { nomodify => 0x80
 ########### 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
@@ -399,7 +426,7 @@ sub pem2openpgp {
   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:
@@ -415,7 +442,7 @@ sub pem2openpgp {
   # 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
@@ -470,11 +497,14 @@ sub pem2openpgp {
                            $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
@@ -660,6 +690,8 @@ sub openpgp2ssh {
          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)) ||