X-Git-Url: https://git.distorted.org.uk/~mdw/become/blobdiff_plain/fe59d3d70fc7337b7a50c4fcff72d20967672157..f60a34341fee6aafd5b878dce23b80af7c60064d:/src/crypt.c diff --git a/src/crypt.c b/src/crypt.c deleted file mode 100644 index 549e94b..0000000 --- a/src/crypt.c +++ /dev/null @@ -1,542 +0,0 @@ -/* -*-c-*- - * - * $Id: crypt.c,v 1.5 1998/06/18 15:08:49 mdw Exp $ - * - * Cryptographic transfer of `become' requests - * - * (c) 1998 EBI - */ - -/*----- Licensing notice --------------------------------------------------* - * - * This file is part of `become' - * - * `Become' is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * `Become' is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with `become'; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/*----- Revision history --------------------------------------------------* - * - * $Log: crypt.c,v $ - * Revision 1.5 1998/06/18 15:08:49 mdw - * Paranoia: set close-on-exec flag for seed file. - * - * Revision 1.4 1998/01/12 16:45:55 mdw - * Fix copyright date. - * - * Revision 1.3 1997/09/26 09:14:58 mdw - * Merged blowfish branch into trunk. - * - * Revision 1.2.2.1 1997/09/26 09:08:02 mdw - * Use the Blowfish encryption algorithm instead of IDEA. This is partly - * because I prefer Blowfish (without any particularly strong evidence) but - * mainly because IDEA is patented and Blowfish isn't. - * - * Revision 1.2 1997/08/04 10:24:21 mdw - * Sources placed under CVS control. - * - * Revision 1.1 1997/07/21 13:47:51 mdw - * Initial revision - * - */ - -/*----- Header files ------------------------------------------------------*/ - -/* --- ANSI headers --- */ - -#include -#include -#include -#include -#include -#include - -/* --- Unix headers --- */ - -#include -#include -#include -#include -#include - -/* --- Local headers --- */ - -#include "become.h" -#include "blowfish.h" -#include "config.h" -#include "crypt.h" -#include "icrypt.h" -#include "md5.h" -#include "noise.h" -#include "rand.h" -#include "tx.h" -#include "utils.h" - -/*----- Magic numbers -----------------------------------------------------*/ - -#define crypt__timeError 60 /* Seconds error to permit */ - -/*----- Main code ---------------------------------------------------------*/ - -/* --- @crypt__sessionKey@ --- * - * - * Arguments: @const char *seedfile@ = pointer to name of seed file - * @unsigned char *k@ = our secret key - * @unsigned *sk@ = where to store the session key - * @unsigned char *iv@ = where to store the IV - * - * Returns: --- - * - * Use: Decides on a random session key and initialisation vector. - */ - -static void crypt__sessionKey(const char *seedfile, unsigned char *k, - unsigned char *sk, unsigned char *iv) -{ - FILE *fp; /* File handle for reading */ - struct flock l; - int ok = 1; - - /* --- Open the random seed file --- * - * - * If I can't manage that, create a new one. - */ - - if ((fp = fopen(seedfile, "r+")) == 0) { - ok = 0; - if ((fp = fopen(seedfile, "w+")) == 0) - die("can't create random number file: %s", strerror(errno)); - rand_clear(); - } - if (fcntl(fileno(fp), F_SETFD, 1) < 0) { - die("can't set close-on-exec for random number file: %s", - strerror(errno)); - } - - /* --- Lock the seed file against concurrency problems --- */ - - l.l_type = F_WRLCK; - l.l_whence = SEEK_SET; - l.l_start = 0; - l.l_len = 0; - if (fcntl(fileno(fp), F_SETLKW, &l) < 0) - die("can't lock random number file: %s", strerror(errno)); - - /* --- Now read the file, and launder the seed --- */ - - if (ok) - rand_read(fp); - - /* --- Encrypt the pool using the secret key --- */ - - { - icrypt_job j; - icrypt_init(&j, k, BLOWFISH_KEYSIZE, 0); - rand_encrypt(&j); - burn(j); - } - - /* --- Generate the session key and IV --- */ - - noise_acquire(); - rand_extract(sk, BLOWFISH_KEYSIZE); - rand_extract(iv, BLOWFISH_BLKSIZE); - - IF_TRACING(TRACE_CRYPTO, - traceblk(TRACE_CRYPTO, "crypto: session key:", sk, BLOWFISH_KEYSIZE); - traceblk(TRACE_CRYPTO, "crypto: initialisation vector:", - iv, BLOWFISH_BLKSIZE); - ); - - /* --- Write the seed back --- */ - - rewind(fp); - rand_write(fp); - fclose(fp); - -} - -/* --- @crypt_packRequest@ --- * - * - * Arguments: @request *rq@ = pointer to request block - * @unsigned char *buff@ = pointer to a buffer - * @time_t t@ = the current time - * @pid_t pid@ = my process ID - * @unsigned char *k@ = pointer to 128-bit key - * @unsigned char *sk@ = where to put the session key - * - * Returns: --- - * - * Use: Packs a request block into a buffer. The buffer should have - * space for at least @crq_size@ bytes. The buffer comes back - * encrypted and ready to send. - */ - -void crypt_packRequest(request *rq, unsigned char *buff, - time_t t, pid_t pid, - unsigned char *k, unsigned char *sk) -{ - /* --- First, build the easy stuff in the block --- */ - - buff[crq_cryptType] = cryptType_blowfish; - store32(buff + crq_time, t); - store32(buff + crq_pid, pid); - store32(buff + crq_from, rq->from); - store32(buff + crq_to, rq->to); - - /* --- Now generate session keys and things --- */ - - crypt__sessionKey(file_RANDSEED, k, sk, buff + crq_iv); - memcpy(buff + crq_session, sk, BLOWFISH_KEYSIZE); - - /* --- The string causes a few problems --- * - * - * There's a good chance that the string will be a good deal shorter than - * the space allowed for it. This will probably mean lots of zeroes, and a - * very easy known-plaintext job for a potential attacker. (An early - * version of this code used @strncpy@ which is even worse!) - * - * I'll fill the block with random (from @rand@(3) -- nothing too - * elaborate) and then encrypt it using Blowfish in CFB mode, using the - * first few bytes as the key. This should provide a sufficiently - * unpredictable background for the block. - */ - - { - icrypt_job j; - unsigned char *p; - unsigned u; - md5 md; - unsigned char qk[BLOWFISH_KEYSIZE]; - - /* --- Initialise the buffer with junk --- */ - - srand((unsigned int)(t ^ pid)); /* Seed the (bad) RNG */ - for (p = buff + crq_cmd; p < buff + crq_cmd + CMDLEN_MAX; p++) { - u = rand(); *p = u ^ (u >> 8); - } - - /* --- Now make the junk a whole lot harder to predict --- */ - - p = buff + crq_cmd; - md5_init(&md); md5_buffer(&md, p, CMDLEN_MAX); md5_final(&md, qk); - icrypt_init(&j, qk, BLOWFISH_KEYSIZE, 0); - icrypt_encrypt(&j, p, p, CMDLEN_MAX); - burn(j); burn(qk); burn(md); - - /* --- Copy the string into here --- */ - - strcpy((char *)buff + crq_cmd, rq->cmd); - } - - /* --- Checksum the finished data --- */ - - { - md5 md; - unsigned char mdbuf[MD5_HASHSIZE]; - - md5_init(&md); - md5_buffer(&md, buff + crq_cipher, crq_check - crq_cipher); - md5_final(&md, mdbuf); - memcpy(buff + crq_check, mdbuf, 4); - burn(md); burn(mdbuf); - } - - /* --- Encrypt the block --- * - * - * First, encrypt the session key using the master key. Since the session - * key is effectively random, this makes cracking the master key much - * harder. The rest of the block is then encrypted with the session key, - * using the IV left over from encrypting the session key. - */ - - { - icrypt_job j; - - T( traceblk(TRACE_CRYPTO, "crypto: plaintext request:", - buff, crq_size); ) - - T( traceblk(TRACE_CRYPTO, "crypto: master key:", k, BLOWFISH_KEYSIZE); ) - T( traceblk(TRACE_CRYPTO, "crypto: initial iv:", - buff + crq_iv, BLOWFISH_BLKSIZE); ) - T( traceblk(TRACE_CRYPTO, "crypto: session key:", - sk, BLOWFISH_KEYSIZE); ) - - icrypt_init(&j, k, BLOWFISH_KEYSIZE, buff + crq_iv); - - icrypt_encrypt(&j, buff + crq_session, - buff + crq_session, BLOWFISH_KEYSIZE); - T( traceblk(TRACE_CRYPTO, "crypto: encrypted session key:", - buff + crq_session, BLOWFISH_KEYSIZE); ) - - icrypt_reset(&j, sk, BLOWFISH_KEYSIZE, 0); - - T( traceblk(TRACE_CRYPTO, "crypto: partial iv:", - j.iv, BLOWFISH_BLKSIZE); ) - - icrypt_encrypt(&j, buff + crq_cipher, - buff + crq_cipher, crq_size - crq_cipher); - burn(j); - - T( traceblk(TRACE_CRYPTO, "crypto: ciphertext request:", - buff, crq_size); ) - } -} - -/* --- @crypt_unpackRequest@ --- * - * - * Arguments: @reqest *rq@ = pointer to destination request block - * @unsigned char *buff@ = pointer to source buffer - * @unsigned char *k@ = pointer to encryption key - * @unsigned char *sk@ = pointer to where to store session key - * @unsigned char *rpl@ = where to start building reply - * - * Returns: Nonzero if it was decrypted OK - * - * Use: Decrypts and unpacks a request buffer. - */ - -int crypt_unpackRequest(request *rq, unsigned char *buff, - unsigned char *k, unsigned char *sk, - unsigned char *rpl) -{ - { - /* --- Check the encryption format --- */ - - if (buff[crq_cryptType] != cryptType_blowfish) - return (0); - } - - { - /* --- First things first: decrypt the block --- */ - - icrypt_job j; - - T( traceblk(TRACE_CRYPTO, "crypto: ciphertext request:", - buff, crq_size); ) - - T( traceblk(TRACE_CRYPTO, "crypto: master key:", k, BLOWFISH_KEYSIZE); ) - T( traceblk(TRACE_CRYPTO, "crypto: initial iv:", - buff + crq_iv, BLOWFISH_BLKSIZE); ) - - icrypt_init(&j, k, BLOWFISH_KEYSIZE, buff + crq_iv); - T( traceblk(TRACE_CRYPTO, "crypto: job block:", &j, sizeof(j)); ) - - T( traceblk(TRACE_CRYPTO, "crypto: encrypted session key:", - buff + crq_session, BLOWFISH_KEYSIZE); ) - icrypt_decrypt(&j, buff + crq_session, - buff + crq_session, BLOWFISH_KEYSIZE); - memcpy(sk, buff + crq_session, BLOWFISH_KEYSIZE); - T( traceblk(TRACE_CRYPTO, "crypto: session key:", - sk, BLOWFISH_KEYSIZE); ) - - icrypt_reset(&j, sk, BLOWFISH_KEYSIZE, 0); - - T( traceblk(TRACE_CRYPTO, "crypto: partial iv:", - j.iv, BLOWFISH_BLKSIZE); ) - - icrypt_decrypt(&j, buff + crq_cipher, - buff + crq_cipher, crq_size - crq_cipher); - icrypt_saveIV(&j, rpl + crp_iv); - - T( traceblk(TRACE_CRYPTO, "crypto: plaintext request:", - buff, crq_size); ) - - memset(buff + crq_session, 0, BLOWFISH_KEYSIZE); /* Burn, baby, burn */ - burn(j); - } - - { - /* --- Check the validity of the data therein --- */ - - md5 md; - unsigned char mdbuf[MD5_HASHSIZE]; - - md5_init(&md); - md5_buffer(&md, buff + crq_cipher, crq_check - crq_cipher); - md5_final(&md, mdbuf); - if (memcmp(mdbuf, buff + crq_check, 4) != 0) { - syslog(LOG_INFO, "packet rejected: bad checksum"); - T( trace(TRACE_CRYPTO, "crypto: bad checksum on incoming request"); ) - return (0); - } - burn(md); burn(mdbuf); - } - - { - /* --- Extract fields from the block --- */ - - rq->from = load32(buff + crq_from); - rq->to = load32(buff + crq_to); - memcpy(rq->cmd, buff + crq_cmd, CMDLEN_MAX); - } - - { - /* --- Fill in bits of the reply block --- */ - - long t = (long)time(0); - long u = (long)load32(buff + crq_time); - - if (t - u > crypt__timeError || u - t > crypt__timeError) { - syslog(LOG_INFO, "packet rejected: bad time"); - T( trace(TRACE_CRYPTO, "crypto: bad time on incoming request"); ) - return (0); - } - memcpy(rpl + crp_time, buff + crq_time, 8); - } - - /* --- Done --- */ - - T( trace(TRACE_CRYPTO, "crypto: valid request received"); ) - return (1); -} - -/* --- @crypt_packReply@ --- * - * - * Arguments: @char *buff@ = pointer to reply block - * @unsigned char *sk@ = pointer to session key - * @int answer@ = yes or no - * - * Returns: --- - * - * Use: Packs and encrypts a reply block. - */ - -void crypt_packReply(unsigned char *buff, unsigned char *sk, int answer) -{ - { - /* --- Store the answer --- */ - - buff[crp_answer] = (answer != 0); - } - - { - /* --- Build the checksum --- */ - - md5 md; - unsigned char mdbuf[MD5_HASHSIZE]; - - md5_init(&md); - md5_buffer(&md, buff + crp_cipher, crp_check - crp_cipher); - md5_final(&md, mdbuf); - memcpy(buff + crp_check, mdbuf, 4); - burn(md); burn(mdbuf); - } - - { - /* --- Encrypt the buffer --- */ - - icrypt_job j; - - T( traceblk(TRACE_CRYPTO, "crypto: plaintext reply:", buff, crp_size); ) - - icrypt_init(&j, sk, BLOWFISH_KEYSIZE, buff + crp_iv); - icrypt_encrypt(&j, buff + crp_cipher, - buff + crp_cipher, crp_size - crp_cipher); - burn(j); - - T( traceblk(TRACE_CRYPTO, "crypto: ciphertext reply:", buff, crp_size); ) - } -} - -/* --- @crypt_unpackReply@ --- * - * - * Arguments: @unsigned char *buff@ = pointer to reply buffer - * @unsigned char *sk@ = pointer to session key - * @time_t t@ = time at which request was sent - * @pid_t pid@ = my process ID - * - * Returns: >0 if request granted, zero if denied, <0 if reply rejected - * - * Use: Unpacks a reply block, and informs the caller of the outcome. - */ - -int crypt_unpackReply(unsigned char *buff, unsigned char *sk, - time_t t, pid_t pid) -{ - { - /* --- Decrypt my reply block --- */ - - icrypt_job j; - - T( traceblk(TRACE_CRYPTO, "crypto: ciphertext reply:", buff, crp_size); ) - - icrypt_init(&j, sk, BLOWFISH_KEYSIZE, buff + crp_iv); - icrypt_decrypt(&j, buff + crp_cipher, - buff + crp_cipher, crp_size - crp_cipher); - burn(j); - - T( traceblk(TRACE_CRYPTO, "crypto: plaintext reply:", buff, crp_size); ) - } - - { - /* --- Check validity --- */ - - md5 md; - unsigned char mdbuf[MD5_HASHSIZE]; - char b[8]; - - /* --- Check the checksum --- */ - - md5_init(&md); - md5_buffer(&md, buff + crp_cipher, crp_check - crp_cipher); - md5_final(&md, mdbuf); - if (memcmp(buff + crp_check, mdbuf, 4) != 0) { - syslog(LOG_INFO, "reply rejected: bad checksum"); - T( trace(TRACE_CRYPTO, "crypto: bad checksum on reply"); ) - return (-1); - } - - /* --- Check the identifier --- */ - - store32(b + 0, t); store32(b + 4, pid); - if (memcmp(b, buff + crp_time, sizeof(b)) != 0) { - syslog(LOG_INFO, "reply rejected: bad identification marker"); - T( trace(TRACE_CRYPTO, "crypto: bad id on reply"); ) - return (-1); - } - } - - /* --- Return the value --- */ - - T( trace(TRACE_CRYPTO, "crypto: valid reply received"); ) - return (buff[crp_answer]); -} - -/*----- Test rig ----------------------------------------------------------*/ - -#ifdef TEST_RIG - -int main(int argc, char *argv[]) -{ - unsigned char buff[8]; - unsigned char sk[BLOWFISH_KEYSIZE], k[BLOWFISH_KEYSIZE]; - FILE *fp; - - ego(argv[0]); - traceon(stdout, TRACE_CRYPTO); - if (argc < 3) - die("bad args"); - fp = fopen(argv[1], "r"); - if (!fp) - die("fopen: %s", strerror(errno)); - tx_getBits(k, 128, fp); - fclose(fp); - crypt__sessionKey(argv[2], k, sk, buff); - return (0); -} - -#endif - -/*----- That's all, folks -------------------------------------------------*/