This may or may not be useful. We can embed the message after the
signature and reduce the number of files in half. It's not a lot of
code. (This is how the crypto_sign API originally worked, but we've
since added some metadata, so we still need to destruct and
reconstruct the crypto_sign inputs and outputs.)

The -e option is added. It works a lot like gzip/gunzip by default.
You sign a message, creating message.txt.sig:
        signify -e -S message.txt
You verify message.txt.sig, creating message.txt:
        signify -e -V message.txt
Note you always specify the message name. I've cleaned up the source a
bit to disambiguate between "input" and "message". And of course, -o
works as before.

The signature is prepended to the data (much easier to find than
appended). It can be stripped off manually by deleting the first two
lines. One other thing to note is that this now requires the base64
data to stay on one line, unless we go whole hog with fancy
        --- BEGIN HERE COMES THE DATA ---
        --- END THERE GOES THE DATA ---
lines. We keep accumulating features, so maybe we should.


Index: signify.1
===================================================================
RCS file: /cvs/src/usr.bin/signify/signify.1,v
retrieving revision 1.7
diff -u -p -r1.7 signify.1
--- signify.1   3 Jan 2014 17:10:27 -0000       1.7
+++ signify.1   8 Jan 2014 20:40:52 -0000
@@ -27,21 +27,23 @@
 .Fl s Ar seckey
 .Fl G
 .Nm signify
+.Op Fl e
 .Op Fl o Ar output
 .Fl s Ar seckey
 .Fl S
-.Ar input
+.Ar message
 .Nm signify
+.Op Fl e
 .Op Fl o Ar output
 .Fl p Ar pubkey
 .Fl V
-.Ar input
+.Ar message
 .Sh DESCRIPTION
 The
 .Nm
 utility creates and verifies cryptographic signatures for
 an input file
-.Ar input .
+.Ar message .
 The mode of operation is selected by the
 .Fl G ,
 .Fl S ,
@@ -51,6 +53,9 @@ options.
 .Pp
 The options are as follows:
 .Bl -tag -width Dssoutput
+.It Fl e
+Embed the message after the signature when signing.
+For verification, extract the message from the signature.
 .It Fl G
 Generate a new keypair.
 .It Fl n
@@ -58,7 +63,7 @@ Do not ask for a passphrase during key g
 Otherwise,
 .Nm
 will prompt the user for a passphrase on the terminal.
-.It Fl o Ar output
+.It Fl o Ar sigfile
 The signature file to create or verify.
 The default is
 .Ar input Ns .sig .
Index: signify.c
===================================================================
RCS file: /cvs/src/usr.bin/signify/signify.c,v
retrieving revision 1.15
diff -u -p -r1.15 signify.c
--- signify.c   8 Jan 2014 07:04:29 -0000       1.15
+++ signify.c   8 Jan 2014 20:33:06 -0000
@@ -64,6 +64,8 @@ struct sig {
        uint8_t sig[SIGBYTES];
 };
 
+static int embedded;
+
 extern char *__progname;
 
 static void
@@ -72,9 +74,9 @@ usage(void)
        fprintf(stderr, "usage:"
 #ifndef VERIFYONLY
            "\t%s [-n] -p pubkey -s seckey -G\n"
-           "\t%s [-o output] -s seckey -S input\n"
+           "\t%s [-e] [-o output] -s seckey -S input\n"
 #endif
-           "\t%s [-o output] -p pubkey -V input\n",
+           "\t%s [-e] [-o output] -p pubkey -V input\n",
 #ifndef VERIFYONLY
            __progname, __progname, 
 #endif
@@ -117,30 +119,43 @@ readall(int fd, void *buf, size_t len, c
        }
 }
 
+static size_t
+parseb64file(const char *filename, char *b64, void *buf, size_t len)
+{
+       int rv;
+       char *commentend, *b64end;
+
+       commentend = strchr(b64, '\n');
+       if (!commentend || commentend - b64 <= COMMENTHDRLEN ||
+           memcmp(b64, COMMENTHDR, COMMENTHDRLEN))
+               errx(1, "invalid comment in %s; must start with '%s'",
+                   filename, COMMENTHDR);
+       b64end = strchr(commentend + 1, '\n');
+       if (!b64end)
+               errx(1, "missing new line after b64 in %s", filename);
+       *b64end = 0;
+       rv = b64_pton(commentend + 1, buf, len);
+       if (rv != len)
+               errx(1, "invalid b64 encoding in %s", filename);
+       if (memcmp(buf, PKALG, 2))
+               errx(1, "unsupported file %s", filename);
+       return b64end - b64 + 1;
+}
+
 static void
 readb64file(const char *filename, void *buf, size_t len)
 {
        char b64[2048];
        int rv, fd;
-       char *commentend;
 
        fd = xopen(filename, O_RDONLY | O_NOFOLLOW, 0);
        memset(b64, 0, sizeof(b64));
        rv = read(fd, b64, sizeof(b64) - 1);
        if (rv == -1)
                err(1, "read from %s", filename);
-       commentend = strchr(b64, '\n');
-       if (!commentend || commentend - b64 <= COMMENTHDRLEN ||
-           memcmp(b64, COMMENTHDR, COMMENTHDRLEN))
-               errx(1, "invalid comment in %s; must start with '%s'",
-                   filename, COMMENTHDR);
-       rv = b64_pton(commentend + 1, buf, len);
-       if (rv != len)
-               errx(1, "invalid b64 encoding in %s", filename);
+       parseb64file(filename, b64, buf, len);
        memset(b64, 0, sizeof(b64));
        close(fd);
-       if (memcmp(buf, PKALG, 2))
-               errx(1, "unsupported file %s", filename);
 }
 
 uint8_t *
@@ -179,6 +194,16 @@ writeall(int fd, const void *buf, size_t
 }
 
 static void
+appendall(const char *filename, const void *buf, size_t len)
+{
+       int fd;
+
+       fd = xopen(filename, O_NOFOLLOW | O_RDWR | O_APPEND, 0);
+       writeall(fd, buf, len, filename);
+       close(fd);
+}
+
+static void
 writeb64file(const char *filename, const char *comment, const void *buf,
     size_t len, mode_t mode)
 {
@@ -270,7 +295,7 @@ generate(const char *pubkeyfile, const c
 }
 
 static void
-sign(const char *seckeyfile, const char *inputfile, const char *sigfile)
+sign(const char *seckeyfile, const char *msgfile, const char *sigfile)
 {
        struct sig sig;
        uint8_t digest[SHA512_DIGEST_LENGTH];
@@ -297,7 +322,7 @@ sign(const char *seckeyfile, const char 
            errx(1, "incorrect passphrase");
        memset(digest, 0, sizeof(digest));
 
-       msg = readmsg(inputfile, &msglen);
+       msg = readmsg(msgfile, &msglen);
 
        signmsg(enckey.seckey, msg, msglen, sig.sig);
        memcpy(sig.fingerprint, enckey.fingerprint, FPLEN);
@@ -305,6 +330,8 @@ sign(const char *seckeyfile, const char 
 
        memcpy(sig.pkalg, PKALG, 2);
        writeb64file(sigfile, "signature", &sig, sizeof(sig), 0666);
+       if (embedded)
+               appendall(sigfile, msg, msglen);
 
        free(msg);
 }
@@ -331,31 +358,44 @@ verifymsg(uint8_t *pubkey, uint8_t *msg,
 
 
 static void
-verify(const char *pubkeyfile, const char *inputfile, const char *sigfile)
+verify(const char *pubkeyfile, const char *msgfile, const char *sigfile)
 {
        struct sig sig;
        struct pubkey pubkey;
-       unsigned long long msglen;
+       unsigned long long msglen, siglen = 0;
        uint8_t *msg;
+       int fd;
+
+       msg = readmsg(embedded ? sigfile : msgfile, &msglen);
 
        readb64file(pubkeyfile, &pubkey, sizeof(pubkey));
-       readb64file(sigfile, &sig, sizeof(sig));
+       if (embedded) {
+               siglen = parseb64file(sigfile, msg, &sig, sizeof(sig));
+               msg += siglen;
+               msglen -= siglen;
+       } else {
+               readb64file(sigfile, &sig, sizeof(sig));
+       }
 
        if (memcmp(pubkey.fingerprint, sig.fingerprint, FPLEN))
                errx(1, "verification failed: checked against wrong key");
 
-       msg = readmsg(inputfile, &msglen);
-
        verifymsg(pubkey.pubkey, msg, msglen, sig.sig);
+       if (embedded) {
+               fd = xopen(msgfile, O_CREAT|O_EXCL|O_NOFOLLOW|O_RDWR, 0666);
+               writeall(fd, msg, msglen, msgfile);
+               close(fd);
+       }
+
        printf("verified\n");
 
-       free(msg);
+       free(msg - siglen);
 }
 
 int
 main(int argc, char **argv)
 {
-       const char *pubkeyfile = NULL, *seckeyfile = NULL, *inputfile = NULL,
+       const char *pubkeyfile = NULL, *seckeyfile = NULL, *msgfile = NULL,
            *sigfile = NULL;
        char sigfilebuf[1024];
        int ch, rounds;
@@ -369,7 +409,7 @@ main(int argc, char **argv)
 
        rounds = 42;
 
-       while ((ch = getopt(argc, argv, "GSVno:p:s:")) != -1) {
+       while ((ch = getopt(argc, argv, "GSVeno:p:s:")) != -1) {
                switch (ch) {
 #ifndef VERIFYONLY
                case 'G':
@@ -388,6 +428,9 @@ main(int argc, char **argv)
                                usage();
                        verb = VERIFY;
                        break;
+               case 'e':
+                       embedded = 1;
+                       break;
                case 'n':
                        rounds = 0;
                        break;
@@ -426,11 +469,11 @@ main(int argc, char **argv)
                if (argc != 1)
                        usage();
 
-               inputfile = argv[0];
+               msgfile = argv[0];
 
                if (!sigfile) {
                        if (snprintf(sigfilebuf, sizeof(sigfilebuf), "%s.sig",
-                           inputfile) >= sizeof(sigfilebuf))
+                           msgfile) >= sizeof(sigfilebuf))
                                errx(1, "path too long");
                        sigfile = sigfilebuf;
                }
@@ -438,13 +481,13 @@ main(int argc, char **argv)
                if (verb == SIGN) {
                        if (!seckeyfile)
                                usage();
-                       sign(seckeyfile, inputfile, sigfile);
+                       sign(seckeyfile, msgfile, sigfile);
                } else
 #endif
                if (verb == VERIFY) {
                        if (!pubkeyfile)
                                usage();
-                       verify(pubkeyfile, inputfile, sigfile);
+                       verify(pubkeyfile, msgfile, sigfile);
                }
        }
 


Reply via email to