/* * Copyright (C) 1998,1999,2000,2001,2002,2003 Nikos Mavroyanopoulos * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * 2004-12-01 Mario Juric * * Modified for use in libencio * */ /* Some functions that didn't fit elsewhere */ /* $Id: extra.c,v 1.25 2003/02/21 17:57:14 nmav Exp $ */ #include "seekcrypt_internal.h" #include #include #include #include void mcrypt_tolow(char *str, int size) { int i; for (i = 0; i < size; i++) { str[i] = tolower(str[i]); } } int identify_algorithm ( char* keymode) { if (strcasecmp(keymode, "asis")==0) return 0; if (strcasecmp(keymode, "scrypt")==0) return 0; if (strcasecmp(keymode, "hex")==0) return 0; if (strcasecmp(keymode, "pkdes")==0) return 0; if (strcasecmp(keymode, "mcrypt-sha1")==0) return 0; if (strcasecmp(keymode, "mcrypt-md5")==0) return 0; if (strcasecmp(keymode, "s2k-simple-md5")==0) return 0; if (strcasecmp(keymode, "s2k-simple-ripemd")==0) return 0; if (strcasecmp(keymode, "s2k-simple-sha1")==0) return 0; if (strcasecmp(keymode, "s2k-salted-md5")==0) return 0; if (strcasecmp(keymode, "s2k-salted-sha1")==0) return 0; if (strcasecmp(keymode, "s2k-salted-ripemd")==0) return 0; if (strcasecmp(keymode, "s2k-isalted-md5")==0) return 0; if (strcasecmp(keymode, "s2k-isalted-sha1")==0) return 0; if (strcasecmp(keymode, "s2k-isalted-ripemd")==0) return 0; return -1; } /* read from file until we reach \0 character, or read 100 bytes */ void read_until_null(char *pointer, FILE * fstream) { int i; for (i = 0; i < 100; i++) { fread(&pointer[i], 1, 1, fstream); if (pointer[i] == 0) { break; } } } /* Convert passphrase to key, given a salt and a hashing algorithm Called by fixkey() keymode == which hashing algorithm to use keyword == encryption key salt == salt password == input passphrase which will be hashed */ int generate_key( char* keymode, void* keyword, int keysize, void* salt, int saltsize, byte* password, int plen) { KEYGEN data; keygenid id=0; hashid algo=0; int icrypt=0; if (strcasecmp(keymode, "scrypt")==0) icrypt = 1; if (strcasecmp(keymode, "asis")==0) id = KEYGEN_ASIS; if (strcasecmp(keymode, "hex")==0) id = KEYGEN_HEX; if (strcasecmp(keymode, "pkdes")==0) id = KEYGEN_PKDES; if (strcasecmp(keymode, "mcrypt-sha1")==0) { id = KEYGEN_MCRYPT; algo = MHASH_SHA1; } if (strcasecmp(keymode, "mcrypt-md5")==0) { id = KEYGEN_ASIS; algo = MHASH_MD5; } /* _mcrypt_pgp_conv_keymode( keymode, &id, &algo); */ if (icrypt == 0) { data.hash_algorithm[0] = algo; data.count = 0; data.salt = salt; data.salt_size = saltsize; return mhash_keygen_ext(id, data, keyword, keysize, password, plen); } else { return gen_crypt( keyword, keysize, password, plen); } } void Bzero(void *s, size_t n) { #ifdef HAVE_MEMSET memset((void *) s, '\0', (size_t) n); #else #ifdef HAVE_BZERO bzero((void *) s, (size_t) n); #else char *stmp = s; int i; for (i = 0; i < n; i++) stmp[i] = '\0'; #endif #endif } /* fixkey takes the input key (or NULL if it wasn't given) and converts it */ #define MAX_KEY_LEN 513 /* convert a passphrase to key, using hashing algorithm */ void * passphrase_to_key( const char *passphrase, unsigned int *len, /* passphrase, passphrase length (on output, generated key length) */ char* keymode, /* hashing method */ int keysize, /* key length to be generated */ void *salt, int salt_size) { int i; char *tmp; char *keyword; char *tmpkey; tmpkey = calloc(1, MAX_KEY_LEN); keyword = calloc(1, keysize); if (*len > MAX_KEY_LEN) { *len = MAX_KEY_LEN; } memcpy(tmpkey, passphrase, *len); /* Generate key by hashing the passphrase */ if (salt_size == 0) { salt = NULL; } i = generate_key(keymode, keyword, keysize, salt, salt_size, (void *) tmpkey, *len); /* unexpected error in libmhash */ if (i < 0) { set_error("Key transformation failed.\n"); } *len = keysize; /* lame attempt at not leaving the passphrase dangling in memory after it's freed */ memset(tmpkey, 0, MAX_KEY_LEN); free(tmpkey); return keyword; } /* Convert hashing algorithm name to MHASH algorithm id. Go through all possible hashing algorithms supported by MHASH, and see if any one corresponds to */ int hash_algo_name_to_id(char *chain) { int i; char *y; char tmp[255]; for (i = 0; i < 255; i++) { y = mhash_get_hash_name(i); if (y != NULL) { strcpy(tmp, y); free(y); mcrypt_tolow(tmp, strlen(tmp)); if (strcmp(tmp, chain) == 0) { return i; } } } return -1; } unsigned int m_setbit(unsigned int which, unsigned int fullnum, unsigned int what) { if (what == 1) { return i_setbit(which, fullnum); } else { return i_unsetbit(which, fullnum); } } /* load MCRYPT file header */ int read_header( FILE * fstream, /* [in] input stream */ char *cipher, /* [out] encryption cipher */ char *mode, /* [out] encryption mode (cfb, ccb, ...) */ char *keymode, int *keysize, /* [out] key hash algorithm, key size */ void *salt, int *salt_size, /* [out] salt, salt size */ int *noiv, /* [out] is IV present in the file */ int *hash_algorithm /* [out] checksum hash algorithm */ ) { char buf[3]; char tmp_buf[101]; short int keylen; int i; unsigned char flags; unsigned char sflag; /* file magic */ fread(buf, 1, 3, fstream); fread(&flags, 1, 1, fstream); char magic3[] = "\0m\3"; if (memcmp(buf, magic3, 3) != 0) { return 1; } /* if headers are ok */ for(i = 0; i != 6; i++) { if (m_getbit(i, flags) != 0) { set_error(("Unsupported version of encrypted file\n")); return -1; } } if (m_getbit(7, flags) != 0) { *noiv = TRUE; } /* No iv is being used */ /* cipher */ read_until_null(tmp_buf, fstream); strcpy(cipher, tmp_buf); /* key length */ fread(&keylen, sizeof(short int), 1, fstream); #ifdef WORDS_BIGENDIAN *keysize = byteswap16(keylen); #else *keysize = keylen; #endif /* encryption mode */ read_until_null(tmp_buf, fstream); strcpy(mode, tmp_buf); /* passphrase->key hash algorithm */ read_until_null(tmp_buf, fstream); strcpy(keymode, tmp_buf); /* "salt flag" */ fread(&sflag, 1, 1, fstream); if (m_getbit(6, flags) == 1) /* if the salt bit is set */ { if (m_getbit(0, sflag) != 0) /* if the first bit is set */ { *salt_size = m_setbit(0, sflag, 0); if (*salt_size > 0) { fread(tmp_buf, 1, *salt_size, fstream); memcpy(salt, tmp_buf, *salt_size); } } } /* checksum hash algorithm */ read_until_null(tmp_buf, fstream); *hash_algorithm = hash_algo_name_to_id(tmp_buf); return 0; } /* load initialization vector from */ void *read_iv(FILE * fstream, int ivsize) { char *IV; IV = malloc(ivsize); fread(IV, 1, ivsize, fstream); return IV; } /* Write MCRYPT-compatible file header */ int write_header( FILE * filedes, char *cipher, char *mode, char *keymode, int *keysize, void *salt, int salt_size) { char buf[4]; short int keylen = *keysize; unsigned char null = 0; unsigned char sflag = 0; char tmp[255]; /* we don't support/encourage IV-less files */ int noiv = FALSE; buf[0] = '\0'; buf[1] = 'm'; buf[2] = '\3'; buf[3] = '\0'; /* flags */ /* set flags */ if (salt != NULL) buf[3] = m_setbit(6, buf[3], 1); if (noiv == TRUE) buf[3] = m_setbit(7, buf[3], 1); if (fwrite(buf, 1, 4, filedes) != 4) { return 1; } /* cipher, mode, keyhash, ... */ if (fwrite(cipher, 1, strlen(cipher)+1, filedes) != strlen(cipher)+1) { return 1; } #ifdef WORDS_BIGENDIAN keylen = byteswap16(keylen); #endif if (fwrite(&keylen, 1, sizeof(short int), filedes) != sizeof(short int)) { return 1; } if (fwrite(mode, 1, strlen(mode) + 1, filedes) != strlen(mode) + 1) { return 1; } if (fwrite(keymode, 1, strlen(keymode) + 1, filedes) != strlen(keymode) + 1) { return 1; } if (salt != NULL) { sflag = salt_size; sflag = m_setbit(0, sflag, 1); fwrite(&sflag, 1, 1, filedes); if (fwrite(salt, 1, salt_size, filedes) != salt_size) { return 1; } } /* checksum algorithm name */ char *checksumalgo = mhash_get_hash_name(enc_checksum_algo); if (buf == NULL) { return 1; } strcpy(tmp, checksumalgo); free(checksumalgo); mcrypt_tolow(tmp, strlen(tmp)); if (fwrite(tmp, 1, strlen(tmp) + 1, filedes) != strlen(tmp) + 1) { return 1; } return 0; } /* write the intialization vector (IV) */ int write_iv(FILE * filedes, void *IV, int ivsize) { unsigned char *buf = NULL; if (ivsize <= 0) { return 0; } buf = malloc(ivsize); if (IV != NULL) { memcpy(buf, IV, ivsize); } else { memset(buf, 0, ivsize); } if (fwrite(buf, 1, ivsize, filedes) != ivsize) { return 1; } free(buf); return 0; } /************* utility functions ********************/ /* dump given memory address/length as hex code */ void hexdump(char *text, void *data, int len) { int i; fprintf(stderr, "%s: ", text); for (i = 0; i < len; i++) { fprintf(stderr, "%.2x.", ((unsigned char *) data)[i]); } fprintf(stderr, " [%d]\n", len); } /* same as strdup(), with length given explicitly */ void *memdup(void *src, int length) { void *ptr = malloc(length); memcpy(ptr, src, length); return ptr; } /* * Error handling functions */ char errortext[1000]; void set_error(const char *errtext, ...) { va_list ap; va_start(ap, errtext); vfprintf(stderr, "Error: %s", ap); fprintf(stderr, "\n"); strncpy(errortext, errtext, sizeof(errortext)); errortext[sizeof(errortext)-1] = 0; }