/* Mixmaster version 2.9 -- (C) 1999 - 2003 Anonymizer Inc. and others.
Mixmaster may be redistributed and modified under certain conditions.
This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
ANY KIND, either express or implied. See the file COPYRIGHT for
details.
OpenPGP messages
$Id: pgp.c 665 2003-11-09 01:47:32Z rabbi $ */
#include "mix.h"
#include "mix3.h"
#ifdef USE_PGP
#include "pgp.h"
#include <ctype.h>
#include <string.h>
int pgp_decrypt(BUFFER *in, BUFFER *pass, BUFFER *sig, char *pubring,
char *secring)
{
BUFFER *key;
int err;
key = buf_new();
if (pass)
buf_set(key, pass);
if (!pgp_ispacket(in))
pgp_dearmor(in, in);
err = pgp_getmsg(in, key, sig, pubring, secring);
buf_free(key);
return (err);
}
static void appendaddr(BUFFER *to, BUFFER *addr)
{
if (bufifind(addr, "<")) {
for (addr->ptr = 0; addr->ptr < addr->length; addr->ptr++)
if (addr->data[addr->ptr] == '<') {
buf_rest(to, addr);
break;
}
} else {
buf_appendc(to, '<');
buf_cat(to, addr);
buf_appendc(to, '>');
}
buf_nl(to);
buf_clear(addr);
}
int pgp_mailenc(int mode, BUFFER *msg, char *sigid,
BUFFER *pass, char *pubring, char *secring)
{
BUFFER *hdr, *body, *line, *uid, *field, *content;
int err = -1;
hdr = buf_new();
body = buf_new();
line = buf_new();
uid = buf_new();
field = buf_new();
content = buf_new();
buf_appendc(uid, '<');
buf_appends(uid, sigid);
if (sigid[strlen(sigid) - 1] != '@')
buf_appendc(uid, '>');
while (buf_getline(msg, line) == 0)
buf_cat(hdr, line), buf_nl(hdr);
if ((mode & PGP_SIGN) && !(mode & PGP_ENCRYPT))
while (buf_getheader(hdr, field, content) == 0)
if (bufileft(field, "content-") || bufieq(field, "mime-version")) {
/* Is MIME message */
err = pgpmime_sign(msg, uid, pass, secring);
goto end;
}
buf_rest(body, msg);
if ((mode & PGP_SIGN) && !(mode & PGP_ENCRYPT)) {
err = pgp_signtxt(body, uid, pass, secring, mode & PGP_REMAIL);
}
if (mode & PGP_ENCRYPT) {
BUFFER *plainhdr, *encrhdr, *to, *addr;
int encapsulate = 0;
plainhdr = buf_new();
encrhdr = buf_new();
to = buf_new();
addr = buf_new();
while (buf_getheader(hdr, field, content) == 0) {
if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
buf_appendheader(plainhdr, field, content);
rfc822_addr(content, addr);
while (buf_getline(addr, content) != -1)
appendaddr(to, content);
} else
buf_appendheader(encrhdr, field, content);
}
#if 1
/* encrypt the headers */
buf_appends(plainhdr, "Subject: PGP encrypted message\n");
if (encrhdr->length) {
buf_nl(encrhdr);
buf_cat(encrhdr, body);
buf_move(body, encrhdr);
encapsulate = 1;
}
#else /* end of 1 */
/* send headers as plain text */
buf_cat(plainhdr, encrhdr);
#endif /* not 1 */
buf_move(hdr, plainhdr);
buf_clear(line);
if (encapsulate)
buf_sets(line, "Content-Type: message/rfc822\n");
else if (strlen(DEFLTENTITY))
buf_setf(line, "Content-Type: %s\n", DEFLTENTITY);
buf_nl(line);
buf_cat(line, body);
buf_move(body, line);
/* Use the user keyring if pubring == NULL */
err = pgp_encrypt(mode, body, to, uid, pass,
pubring ? pubring : PGPPUBRING, secring);
buf_free(plainhdr);
buf_free(encrhdr);
buf_free(to);
buf_free(addr);
}
if (err == 0) {
if (mode & PGP_ENCRYPT) {
#if 1
buf_sets(field, "+--");
#else /* end of 1 */
buf_setrnd(mboundary, 18);
encode(mboundary, 0);
#endif /* else if not 1 */
buf_appendf(hdr,
"Content-Type: multipart/encrypted; boundary=\"%b\"; "
"protocol=\"application/pgp-encrypted\"\n\n"
"--%b\n"
"Content-Type: application/pgp-encrypted\n\n"
"Version: 1\n\n"
"--%b\n"
"Content-Type: application/octet-stream\n",
field, field, field);
buf_appendf(body, "\n--%b--\n", field);
}
buf_move(msg, hdr);
buf_nl(msg);
buf_cat(msg, body);
}
end:
buf_free(hdr);
buf_free(body);
buf_free(line);
buf_free(uid);
buf_free(field);
buf_free(content);
return (err);
}
static void pgp_setkey(BUFFER *key, int algo)
{
buf_setc(key, algo);
buf_appendrnd(key, pgp_keylen(algo));
}
int pgp_encrypt(int mode, BUFFER *in, BUFFER *to, BUFFER *sigid,
BUFFER *pass, char *pubring, char *secring)
{
BUFFER *dek, *out, *sig, *dest, *tmp;
int err = 0, sym = 0, mdc = 0;
int text;
out = buf_new();
tmp = buf_new();
dek = buf_new();
sig = buf_new();
dest = buf_new();
text = mode & PGP_TEXT ? 1 : 0;
if (mode & (PGP_CONV3DES | PGP_CONVCAST))
mode |= PGP_NCONVENTIONAL;
if (mode & PGP_SIGN) {
err = pgp_sign(in, NULL, sig, sigid, pass, text, 0, 0,
mode & PGP_REMAIL ? 1 : 0, NULL, secring);
if (err < 0)
goto end;
if (mode & PGP_DETACHEDSIG) {
buf_move(in, sig);
if (!(mode & PGP_NOARMOR))
pgp_armor(in, PGP_ARMOR_NYMSIG);
goto end;
}
}
if (mode & PGP_ENCRYPT) {
err = buf_getline(to, dest);
if (err == -1)
goto end;
if (to->ptr == to->length) {
if ((err = pgpdb_getkey(PK_ENCRYPT, PGP_ANY, &sym, &mdc, NULL, dest, NULL,
NULL, pubring, NULL)) < 0)
goto end;
pgp_setkey(dek, sym);
err = pgp_sessionkey(out, dest, NULL, dek, pubring);
#ifdef USE_IDEA
if (err < 0 && dek->data[0] == PGP_K_IDEA) {
pgp_setkey(dek, PGP_K_3DES);
err = pgp_sessionkey(out, dest, NULL, dek, pubring);
}
#endif /* USE_IDEA */
} else {
/* multiple recipients */
pgp_setkey(dek, PGP_K_3DES);
buf_rewind(to);
while (buf_getline(to, dest) != -1)
if (dest->length) {
err = pgp_sessionkey(tmp, dest, NULL, dek, pubring);
#ifdef USE_IDEA
if (err < 0 && dek->data[0] != PGP_K_IDEA) {
buf_rewind(to);
buf_clear(out);
pgp_setkey(dek, PGP_K_IDEA);
continue;
}
#endif /* USE_IDEA */
if (err < 0)
goto end;
buf_cat(out, tmp);
}
}
} else if (mode & PGP_NCONVENTIONAL) {
/* genereate DEK in pgp_symsessionkey */
buf_setc(dek, mode & PGP_CONVCAST ? PGP_K_CAST5 : PGP_K_3DES);
pgp_marker(out);
err = pgp_symsessionkey(tmp, dek, to);
buf_cat(out, tmp);
} else if (mode & PGP_CONVENTIONAL) {
digest_md5(to, tmp);
buf_setc(dek, PGP_K_IDEA);
buf_cat(dek, tmp);
}
pgp_literal(in, NULL, text);
if (sig->length) {
buf_cat(sig, in);
buf_move(in, sig);
}
pgp_compress(in);
if (mode & (PGP_ENCRYPT | PGP_CONVENTIONAL | PGP_NCONVENTIONAL))
pgp_symmetric(in, dek, mdc);
if (mode & (PGP_ENCRYPT | PGP_NCONVENTIONAL)) {
buf_cat(out, in);
buf_move(in, out);
}
if (!(mode & PGP_NOARMOR))
pgp_armor(in, (mode & PGP_REMAIL) ? PGP_ARMOR_REM : PGP_ARMOR_NORMAL);
end:
buf_free(out);
buf_free(tmp);
buf_free(dek);
buf_free(sig);
buf_free(dest);
return (err);
}
#define POLY 0X1864CFB
unsigned long crc24(BUFFER * in)
{
unsigned long crc = 0xB704CE;
long p;
int i;
#if 0
/* CRC algorithm from RFC 2440 */
for (p = 0; p < in->length; p++) {
crc ^= in->data[p] << 16;
for (i = 0; i < 8; i++) {
crc <<= 1;
if (crc & 0x1000000)
crc ^= POLY;
}
}
#else /* end of 0 */
/* pre-computed CRC table -- much faster */
unsigned long table[256];
unsigned long t;
int q = 0;
table[0] = 0;
for (i = 0; i < 128; i++) {
t = table[i] << 1;
if (t & 0x1000000) {
table[q++] = t ^ POLY;
table[q++] = t;
} else {
table[q++] = t;
table[q++] = t ^ POLY;
}
}
for (p = 0; p < in->length; p++)
crc = crc << 8 ^ table[(in->data[p] ^ crc >> 16) & 255];
#endif /* end of not 0 */
return crc & ((1<<24)-1);
}
/* ASCII armor */
int pgp_dearmor(BUFFER *in, BUFFER *out)
{
BUFFER *line, *temp;
int err = 0;
int tempbuf = 0;
unsigned long crc1, crc2;
line = buf_new();
temp = buf_new();
if (in == out) {
out = buf_new();
tempbuf = 1;
}
do
if (buf_getline(in, line) == -1) {
err = -1;
goto end;
}
while (!bufleft(line, begin_pgp)) ;
while (buf_getheader(in, temp, line) == 0) ; /* scan for empty line */
err = decode(in, out);
crc1 = crc24(out);
err = buf_getline(in, line);
if (line->length == 5 && line->data[0] == '=') { /* CRC */
line->ptr = 1;
err = decode(line, temp);
crc2 = (((unsigned long)temp->data[0])<<16) | (((unsigned long)temp->data[1])<<8) | temp->data[2];
if (crc1 == crc2)
err = buf_getline(in, line);
else {
errlog(NOTICE, "Message CRC does not match.\n");
err = -1;
}
} else
err = -1;
if (err == 0 && bufleft(line, end_pgp))
err = 0;
else
err = -1;
end:
buf_free(temp);
buf_free(line);
if (tempbuf) {
buf_move(in, out);
buf_free(out);
}
return (err);
}
int pgp_armor(BUFFER *in, int mode)
/* mode = 1: remailer message (PGP_ARMOR_REM)
* 0: normal message, (PGP_ARMOR_NORMAL)
* 2: key (PGP_ARMOR_KEY)
* 3: nym key (PGP_ARMOR_NYMKEY)
* 4: nym signature (PGP_ARMOR_NYMSIG)
* 5: secret key (PGP_ARMOR_SECKEY)
*/
{
BUFFER *out;
unsigned long crc;
crc = crc24(in);
encode(in, 64);
out = buf_new();
if (mode == PGP_ARMOR_KEY || mode == PGP_ARMOR_NYMKEY)
buf_sets(out, begin_pgpkey);
else if (mode == PGP_ARMOR_NYMSIG)
buf_sets(out, begin_pgpsig);
else if (mode == PGP_ARMOR_SECKEY)
buf_sets(out, begin_pgpseckey);
else
buf_sets(out, begin_pgpmsg);
buf_nl(out);
#ifdef CLOAK
if (mode == PGP_ARMOR_REM || mode == PGP_ARMOR_NYMKEY || mode == PGP_ARMOR_NYMSIG)
buf_appends(out, "Version: N/A\n");
else
#elif MIMIC /* end of CLOAK */
if (mode == PGP_ARMOR_REM || mode == PGP_ARMOR_NYMKEY || mode == PGP_ARMOR_NYMSIG)
buf_appends(out, "Version: 2.6.3i\n");
else
#endif /* MIMIC */
{
buf_appends(out, "Version: Mixmaster ");
buf_appends(out, VERSION);
buf_appends(out, " (OpenPGP module)\n");
}
buf_nl(out);
buf_cat(out, in);
buf_reset(in);
buf_appendc(in, (crc >> 16) & 255);
buf_appendc(in, (crc >> 8) & 255);
buf_appendc(in, crc & 255);
encode(in, 0);
buf_appendc(out, '=');
buf_cat(out, in);
buf_nl(out);
if (mode == PGP_ARMOR_KEY || mode == PGP_ARMOR_NYMKEY)
buf_appends(out, end_pgpkey);
else if (mode == PGP_ARMOR_NYMSIG)
buf_appends(out, end_pgpsig);
else if (mode == PGP_ARMOR_SECKEY)
buf_appends(out, end_pgpseckey);
else
buf_appends(out, end_pgpmsg);
buf_nl(out);
buf_move(in, out);
buf_free(out);
return (0);
}
int pgp_keygen(int algo, int bits, BUFFER *userid, BUFFER *pass, char *pubring,
char *secring, int remail)
{
switch (algo) {
#ifdef USE_RSA
case PGP_ES_RSA:
#ifndef USE_IDEA
errlog(WARNING, "IDEA disabled: OpenPGP RSA key cannot be used for decryption!\n");
#endif
return (pgp_rsakeygen(bits, userid, pass, pubring, secring, remail));
#endif /* USE_RSA */
case PGP_E_ELG:
return (pgp_dhkeygen(bits, userid, pass, pubring, secring, remail));
default:
return -1;
}
}
int pgp_signtxt(BUFFER *msg, BUFFER *uid, BUFFER *pass,
char *secring, int remail)
{
int err;
BUFFER *line, *sig, *out;
sig = buf_new();
out = buf_new();
line = buf_new();
buf_appends(out, begin_pgpsigned);
buf_nl(out);
if (pgpdb_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, uid, NULL, NULL, secring, pass) == PGP_S_DSA)
buf_appends(out, "Hash: SHA1\n");
buf_nl(out);
while (buf_getline(msg, line) != -1) {
if (line->data[0] == '-')
buf_appends(out, "- ");
buf_cat(out, line);
buf_nl(out);
}
buf_nl(out);
buf_rewind(msg);
err = pgp_encrypt(PGP_SIGN | PGP_DETACHEDSIG | PGP_TEXT |
(remail ? PGP_REMAIL : 0),
msg, NULL, uid, pass, NULL, secring);
if (err == -1)
goto end;
buf_cat(out, msg);
buf_move(msg, out);
end:
buf_free(line);
buf_free(sig);
buf_free(out);
return (err);
}
#endif /* USE_PGP */
syntax highlighted by Code2HTML, v. 0.9.1