From a808b4245fa4b41e50a3a9d503c9eac1b909d31b Mon Sep 17 00:00:00 2001
From: mancha <mancha1 AT zoho DOT com>
Date: Thu, 8 May 2014
Subject: Allow adding, changing, and removing passphrases

 signify.1 |    6 +++++
 signify.c |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 2 deletions(-)

--- signify.c
+++ signify.c
@@ -79,6 +79,7 @@
 	    "\t%1$s -C [-q] -p pubkey -x sigfile [file ...]\n"
 	    "\t%1$s -G [-n] [-c comment] -p pubkey -s seckey\n"
 	    "\t%1$s -I [-p pubkey] [-s seckey] [-x sigfile]\n"
+	    "\t%1$s -P [-n] -s seckey\n"
 	    "\t%1$s -S [-e] [-x sigfile] -s seckey -m message\n"
 #endif
 	    "\t%1$s -V [-eq] [-x sigfile] -p pubkey -m message\n",
@@ -636,6 +637,50 @@
 }
 #endif
 
+static void
+passphrase(const char *seckeyfile, int nrounds)
+{
+	uint8_t digest[SHA512_DIGEST_LENGTH];
+	struct enckey enckey;
+	uint8_t xorkey[sizeof(enckey.seckey)];
+	char comment[COMMENTMAXLEN];
+	int i, rounds;
+	SHA2_CTX ctx;
+
+	readb64file(seckeyfile, &enckey, sizeof(enckey), comment);
+
+	if (memcmp(enckey.kdfalg, KDFALG, 2) != 0)
+		errx(1, "unsupported KDF");
+	rounds = ntohl(enckey.kdfrounds);
+	if (rounds != 0)
+		printf("Current passphrase\n");
+	kdf(enckey.salt, sizeof(enckey.salt), rounds, 1, 0,
+	    xorkey, sizeof(xorkey));
+	for (i = 0; i < sizeof(enckey.seckey); i++)
+		enckey.seckey[i] ^= xorkey[i];
+	explicit_bzero(xorkey, sizeof(xorkey));
+	SHA512Init(&ctx);
+	SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey));
+	SHA512Final(digest, &ctx);
+	if (memcmp(enckey.checksum, digest, sizeof(enckey.checksum)) != 0)
+		errx(1, "incorrect passphrase");
+	explicit_bzero(digest, sizeof(digest));
+
+	if (nrounds != 0) {
+		arc4random_buf(enckey.salt, sizeof(enckey.salt));	
+		printf("New passphrase\n");
+	}
+	enckey.kdfrounds = htonl(nrounds);
+	kdf(enckey.salt, sizeof(enckey.salt), nrounds, 1, 1,
+	    xorkey, sizeof(xorkey));
+	for (i = 0; i < sizeof(enckey.seckey); i++)
+		enckey.seckey[i] ^= xorkey[i];
+	explicit_bzero(xorkey, sizeof(xorkey));
+	writeb64file(seckeyfile, comment, &enckey,
+	    sizeof(enckey), NULL, 0, 0, 0600);
+	explicit_bzero(&enckey, sizeof(enckey));
+}
+
 int
 main(int argc, char **argv)
 {
@@ -652,13 +697,14 @@
 		GENERATE,
 		INSPECT,
 		SIGN,
-		VERIFY
+		VERIFY,
+		PASSPHRASE	
 	} verb = NONE;
 
 
 	rounds = 42;
 
-	while ((ch = getopt(argc, argv, "CGISVc:em:np:qs:x:")) != -1) {
+	while ((ch = getopt(argc, argv, "CGIPSVc:em:np:qs:x:")) != -1) {
 		switch (ch) {
 #ifndef VERIFYONLY
 		case 'C':
@@ -676,6 +722,11 @@
 				usage(NULL);
 			verb = INSPECT;
 			break;
+		case 'P':
+			if (verb)
+				usage(NULL);
+			verb = PASSPHRASE;
+			break;
 		case 'S':
 			if (verb)
 				usage(NULL);
@@ -755,6 +806,11 @@
 			usage("must specify message and seckey");
 		sign(seckeyfile, msgfile, sigfile, embedded);
 		break;
+	case PASSPHRASE:
+		if (!seckeyfile)
+			usage("must specify seckey");
+		passphrase(seckeyfile, rounds);
+		break;
 #endif
 	case VERIFY:
 		if (!msgfile)
--- signify.1
+++ signify.1
@@ -39,6 +39,10 @@
 .Op Fl s Ar seckey
 .Op Fl x Ar sigfile
 .Nm signify
+.Fl P 
+.Op Fl n
+.Fl s Ar seckey
+.Nm signify
 .Fl S
 .Op Fl e
 .Op Fl x Ar sigfile
@@ -69,6 +73,8 @@
 Generate a new key pair.
 .It Fl I
 Inspect the specified keys or signature and print their fingerprint.
+.It Fl P
+Add, change, or remove secret key passphrases.
 .It Fl S
 Sign the specified message file and create a signature.
 .It Fl V
