Module Name:    src
Committed By:   agc
Date:           Sun Nov  7 02:29:28 UTC 2010

Modified Files:
        src/crypto/external/bsd/netpgp/dist/src/lib: config.h.in create.c
            crypto.c crypto.h openssl_crypto.c

Log Message:
Add the ability to perform Elgamal encryption to netpgp.  Some of this
code is inspired by the (BSD-licensed) Elgamal crypto code in
Postgresql by Marko Kreen, but netpgp uses BIGNUM numbers instead of
MPIs, and its keys have a completely different structure, so much has
changed.

% cp config.h f
% netpgp -e f
netpgp: default key set to "d4a643c5"
% gpg -d f.gpg > f2

You need a passphrase to unlock the secret key for
user: "Alistair Crooks (DSA TEST KEY - DO NOT USE) <a...@netbsd.org>"
2048-bit ELG-E key, ID D727BC1E, created 2010-05-19 (main key ID D4A643C5)

gpg: encrypted with 2048-bit ELG-E key, ID D727BC1E, created 2010-05-19
      "Alistair Crooks (DSA TEST KEY - DO NOT USE) <a...@netbsd.org>"
% diff f f2
% ls -al f*
-rw-r--r--  1 agc  agc  5730 Nov  6 05:40 f
-rw-------  1 agc  agc  1727 Nov  6 05:40 f.gpg
-rw-r--r--  1 agc  agc  5730 Nov  6 05:41 f2
%


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 \
    src/crypto/external/bsd/netpgp/dist/src/lib/config.h.in
cvs rdiff -u -r1.35 -r1.36 \
    src/crypto/external/bsd/netpgp/dist/src/lib/create.c
cvs rdiff -u -r1.29 -r1.30 \
    src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c
cvs rdiff -u -r1.24 -r1.25 \
    src/crypto/external/bsd/netpgp/dist/src/lib/crypto.h
cvs rdiff -u -r1.30 -r1.31 \
    src/crypto/external/bsd/netpgp/dist/src/lib/openssl_crypto.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/crypto/external/bsd/netpgp/dist/src/lib/config.h.in
diff -u src/crypto/external/bsd/netpgp/dist/src/lib/config.h.in:1.14 src/crypto/external/bsd/netpgp/dist/src/lib/config.h.in:1.15
--- src/crypto/external/bsd/netpgp/dist/src/lib/config.h.in:1.14	Fri Nov  5 03:37:18 2010
+++ src/crypto/external/bsd/netpgp/dist/src/lib/config.h.in	Sun Nov  7 02:29:28 2010
@@ -12,9 +12,6 @@
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
-/* Define to 1 if you have the <dmalloc.h> header file. */
-#undef HAVE_DMALLOC_H
-
 /* Define to 1 if you have the <errno.h> header file. */
 #undef HAVE_ERRNO_H
 

Index: src/crypto/external/bsd/netpgp/dist/src/lib/create.c
diff -u src/crypto/external/bsd/netpgp/dist/src/lib/create.c:1.35 src/crypto/external/bsd/netpgp/dist/src/lib/create.c:1.36
--- src/crypto/external/bsd/netpgp/dist/src/lib/create.c:1.35	Thu Nov  4 15:38:45 2010
+++ src/crypto/external/bsd/netpgp/dist/src/lib/create.c	Sun Nov  7 02:29:28 2010
@@ -57,7 +57,7 @@
 
 #if defined(__NetBSD__)
 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
-__RCSID("$NetBSD: create.c,v 1.35 2010/11/04 15:38:45 agc Exp $");
+__RCSID("$NetBSD: create.c,v 1.36 2010/11/07 02:29:28 agc Exp $");
 #endif
 
 #include <sys/types.h>
@@ -881,41 +881,39 @@
 	/* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
 	switch (pubkey->alg) {
 	case OPS_PKA_RSA:
+		k = (unsigned)BN_num_bytes(pubkey->key.rsa.n);
+		if (mLen > k - 11) {
+			(void) fprintf(stderr, "encode_m_buf: message too long\n");
+			return 0;
+		}
 		break;
 	case OPS_PKA_DSA:
 	case OPS_PKA_ELGAMAL:
-		(void) fprintf(stderr, "encode_m_buf: DSA/Elgamal encryption not implemented yet\n");
+		k = (unsigned)BN_num_bytes(pubkey->key.elgamal.p);
+		if (mLen > k - 11) {
+			(void) fprintf(stderr, "encode_m_buf: message too long\n");
+			return 0;
+		}
 		break;
 	default:
 		(void) fprintf(stderr, "encode_m_buf: pubkey algorithm\n");
 		return 0;
 	}
-
-	k = (unsigned)BN_num_bytes(pubkey->key.rsa.n);
-	if (mLen > k - 11) {
-		(void) fprintf(stderr, "encode_m_buf: message too long\n");
-		return 0;
-	}
 	/* these two bytes defined by RFC */
 	EM[0] = 0x00;
 	EM[1] = 0x02;
-
 	/* add non-zero random bytes of length k - mLen -3 */
 	for (i = 2; i < (k - mLen) - 1; ++i) {
 		do {
 			__ops_random(EM + i, 1);
 		} while (EM[i] == 0);
 	}
-
 	if (i < 8 + 2) {
 		(void) fprintf(stderr, "encode_m_buf: bad i len\n");
 		return 0;
 	}
-
 	EM[i++] = 0;
-
 	(void) memcpy(EM + i, M, mLen);
-
 	if (__ops_get_debug_level(__FILE__)) {
 		hexdump(stderr, "Encoded Message:", EM, mLen);
 	}
@@ -967,7 +965,18 @@
 			"__ops_create_pk_sesskey: can't allocate\n");
 		return NULL;
 	}
-	sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
+	switch(pubkey->alg) {
+	case OPS_PKA_RSA:
+		sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
+		break;
+	case OPS_PKA_DSA:
+	case OPS_PKA_ELGAMAL:
+		sz_encoded_m_buf = BN_num_bytes(pubkey->key.elgamal.p);
+		break;
+	default:
+		sz_encoded_m_buf = 0;
+		break;
+	}
 	if ((encoded_m_buf = calloc(1, sz_encoded_m_buf)) == NULL) {
 		(void) fprintf(stderr,
 			"__ops_create_pk_sesskey: can't allocate\n");
@@ -993,7 +1002,7 @@
 	(void) memcpy(sesskey->key_id, id, sizeof(sesskey->key_id));
 
 	if (__ops_get_debug_level(__FILE__)) {
-		hexdump(stderr, "Encrypting for RSA keyid", id, sizeof(sesskey->key_id));
+		hexdump(stderr, "Encrypting for keyid", id, sizeof(sesskey->key_id));
 	}
 	switch (pubkey->alg) {
 	case OPS_PKA_RSA:
@@ -1041,11 +1050,14 @@
 		break;
 	case OPS_PKA_DSA:
 	case OPS_PKA_ELGAMAL:
-		(void) fprintf(stderr, "DSA/Elgamal encryption not supported yet\n");
-		free(unencoded_m_buf);
-		free(encoded_m_buf);
-		free(sesskey);
-		return NULL;
+		if (!__ops_elgamal_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
+				&sesskey->params)) {
+			free(unencoded_m_buf);
+			free(encoded_m_buf);
+			free(sesskey);
+			return NULL;
+		}
+		break;
 	default:
 		/* will not get here - for lint only */
 		break;
@@ -1084,8 +1096,17 @@
 			;
 	case OPS_PKA_DSA:
 	case OPS_PKA_ELGAMAL:
-		(void) fprintf(stderr, "__ops_write_pk_sesskey: DSA/Elgamal encryption not implemented yet\n");
-		return 0;
+		return __ops_write_ptag(output, OPS_PTAG_CT_PK_SESSION_KEY) &&
+			__ops_write_length(output, (unsigned)(1 + 8 + 1 +
+				BN_num_bytes(pksk->params.elgamal.g_to_k) + 2 +
+				BN_num_bytes(pksk->params.elgamal.encrypted_m) + 2)) &&
+			__ops_write_scalar(output, (unsigned)pksk->version, 1) &&
+			__ops_write(output, pksk->key_id, 8) &&
+			__ops_write_scalar(output, (unsigned)pksk->alg, 1) &&
+			__ops_write_mpi(output, pksk->params.elgamal.g_to_k) &&
+			__ops_write_mpi(output, pksk->params.elgamal.encrypted_m)
+			/* ??	&& __ops_write_scalar(output, 0, 2); */
+			;
 	default:
 		(void) fprintf(stderr,
 			"__ops_write_pk_sesskey: bad algorithm\n");

Index: src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c
diff -u src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c:1.29 src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c:1.30
--- src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c:1.29	Thu Nov  4 15:38:45 2010
+++ src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c	Sun Nov  7 02:29:28 2010
@@ -54,7 +54,7 @@
 
 #if defined(__NetBSD__)
 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
-__RCSID("$NetBSD: crypto.c,v 1.29 2010/11/04 15:38:45 agc Exp $");
+__RCSID("$NetBSD: crypto.c,v 1.30 2010/11/07 02:29:28 agc Exp $");
 #endif
 
 #include <sys/types.h>
@@ -223,6 +223,45 @@
 	return 1;
 }
 
+/**
+\ingroup Core_MPI
+\brief Elgamal-encrypt an MPI
+*/
+unsigned 
+__ops_elgamal_encrypt_mpi(const uint8_t *encoded_m_buf,
+		    const size_t sz_encoded_m_buf,
+		    const __ops_pubkey_t * pubkey,
+		    __ops_pk_sesskey_params_t * skp)
+{
+
+	uint8_t   encmpibuf[NETPGP_BUFSIZ];
+	uint8_t   g_to_k[NETPGP_BUFSIZ];
+	int             n;
+
+	if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.elgamal.p)) {
+		(void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
+		return 0;
+	}
+
+	n = __ops_elgamal_public_encrypt(g_to_k, encmpibuf, encoded_m_buf,
+				sz_encoded_m_buf, &pubkey->key.elgamal);
+	if (n == -1) {
+		(void) fprintf(stderr, "__ops_elgamal_public_encrypt failure\n");
+		return 0;
+	}
+
+	if (n <= 0)
+		return 0;
+
+	skp->elgamal.g_to_k = BN_bin2bn(g_to_k, n / 2, NULL);
+	skp->elgamal.encrypted_m = BN_bin2bn(encmpibuf, n / 2, NULL);
+
+	if (__ops_get_debug_level(__FILE__)) {
+		hexdump(stderr, "encrypted mpi", encmpibuf, 16);
+	}
+	return 1;
+}
+
 static __ops_cb_ret_t
 write_parsed_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
 {

Index: src/crypto/external/bsd/netpgp/dist/src/lib/crypto.h
diff -u src/crypto/external/bsd/netpgp/dist/src/lib/crypto.h:1.24 src/crypto/external/bsd/netpgp/dist/src/lib/crypto.h:1.25
--- src/crypto/external/bsd/netpgp/dist/src/lib/crypto.h:1.24	Thu Nov  4 15:38:45 2010
+++ src/crypto/external/bsd/netpgp/dist/src/lib/crypto.h	Sun Nov  7 02:29:28 2010
@@ -129,6 +129,8 @@
 int __ops_rsa_private_decrypt(uint8_t *, const uint8_t *, size_t,
 			const __ops_rsa_seckey_t *, const __ops_rsa_pubkey_t *);
 
+int __ops_elgamal_public_encrypt(uint8_t *, uint8_t *, const uint8_t *, size_t,
+			const __ops_elgamal_pubkey_t *);
 int __ops_elgamal_private_decrypt(uint8_t *, const uint8_t *, size_t,
 			const __ops_elgamal_seckey_t *, const __ops_elgamal_pubkey_t *);
 
@@ -161,6 +163,9 @@
 unsigned __ops_rsa_encrypt_mpi(const uint8_t *, const size_t,
 			const __ops_pubkey_t *,
 			__ops_pk_sesskey_params_t *);
+unsigned __ops_elgamal_encrypt_mpi(const uint8_t *, const size_t,
+			const __ops_pubkey_t *,
+			__ops_pk_sesskey_params_t *);
 
 /* Encrypt everything that's written */
 struct __ops_key_data;

Index: src/crypto/external/bsd/netpgp/dist/src/lib/openssl_crypto.c
diff -u src/crypto/external/bsd/netpgp/dist/src/lib/openssl_crypto.c:1.30 src/crypto/external/bsd/netpgp/dist/src/lib/openssl_crypto.c:1.31
--- src/crypto/external/bsd/netpgp/dist/src/lib/openssl_crypto.c:1.30	Thu Nov  4 06:45:28 2010
+++ src/crypto/external/bsd/netpgp/dist/src/lib/openssl_crypto.c	Sun Nov  7 02:29:28 2010
@@ -57,7 +57,7 @@
 
 #if defined(__NetBSD__)
 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
-__RCSID("$NetBSD: openssl_crypto.c,v 1.30 2010/11/04 06:45:28 agc Exp $");
+__RCSID("$NetBSD: openssl_crypto.c,v 1.31 2010/11/07 02:29:28 agc Exp $");
 #endif
 
 #ifdef HAVE_OPENSSL_DSA_H
@@ -878,6 +878,103 @@
 	return ok;
 }
 
+/*
+ * Decide the number of bits in the random componont k
+ *
+ * It should be in the same range as p for signing (which
+ * is deprecated), but can be much smaller for encrypting.
+ *
+ * Until I research it further, I just mimic gpg behaviour.
+ * It has a special mapping table, for values <= 5120,
+ * above that it uses 'arbitrary high number'.	Following
+ * algorihm hovers 10-70 bits above gpg values.  And for
+ * larger p, it uses gpg's algorihm.
+ *
+ * The point is - if k gets large, encryption will be
+ * really slow.  It does not matter for decryption.
+ */
+static int
+decide_k_bits(int p_bits)
+{
+	return (p_bits <= 5120) ? p_bits / 10 + 160 : (p_bits / 8 + 200) * 3 / 2;
+}
+
+int
+__ops_elgamal_public_encrypt(uint8_t *g_to_k, uint8_t *encm,
+			const uint8_t *in,
+			size_t size,
+			const __ops_elgamal_pubkey_t *pubkey)
+{
+	int	ret = 0;
+	int	k_bits;
+	BIGNUM	   *m;
+	BIGNUM	   *p;
+	BIGNUM	   *g;
+	BIGNUM	   *y;
+	BIGNUM	   *k;
+	BIGNUM	   *yk;
+	BIGNUM	   *c1;
+	BIGNUM	   *c2;
+	BN_CTX	   *tmp;
+
+	m = BN_bin2bn(in, size, NULL);
+	p = pubkey->p;
+	g = pubkey->g;
+	y = pubkey->y;
+	k = BN_new();
+	yk = BN_new();
+	c1 = BN_new();
+	c2 = BN_new();
+	tmp = BN_CTX_new();
+	if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp) {
+		goto done;
+	}
+	/*
+	 * generate k
+	 */
+	k_bits = decide_k_bits(BN_num_bits(p));
+	if (!BN_rand(k, k_bits, 0, 0)) {
+		goto done;
+	}
+	/*
+	 * c1 = g^k c2 = m * y^k
+	 */
+	if (!BN_mod_exp(c1, g, k, p, tmp)) {
+		goto done;
+	}
+	if (!BN_mod_exp(yk, y, k, p, tmp)) {
+		goto done;
+	}
+	if (!BN_mod_mul(c2, m, yk, p, tmp)) {
+		goto done;
+	}
+	/* result */
+	BN_bn2bin(c1, g_to_k);
+	ret = BN_num_bytes(c1);	/* c1 = g^k */
+	BN_bn2bin(c2, encm);
+	ret += BN_num_bytes(c2); /* c2 = m * y^k */
+done:
+	if (tmp) {
+		BN_CTX_free(tmp);
+	}
+	if (c2) {
+		BN_clear_free(c2);
+	}
+	if (c1) {
+		BN_clear_free(c1);
+	}
+	if (yk) {
+		BN_clear_free(yk);
+	}
+	if (k) {
+		BN_clear_free(k);
+	}
+	if (g) {
+		BN_clear_free(g);
+	}
+	return ret;
+}
+
 int
 __ops_elgamal_private_decrypt(uint8_t *out,
 				const uint8_t *in,

Reply via email to