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,