/* * Copyright (C) 1998 Nikos Mavroyanopoulos * Copyright (C) 1999,2000 Sascha Schumman, Nikos Mavroyanopoulos * Copyright (C) 2002 Nikos Mavroyanopoulos * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "mhash.h" #include "libdefs.h" #include "keygen.h" #define MAX_DIGEST_SIZE 40 /* Key generation using OpenPGP Simple S2K algorithm */ mutils_error _mhash_gen_key_s2k_simple(hashid algorithm, void *keyword, mutils_word32 key_size, mutils_word8 *password, mutils_word32 plen) { mutils_word8* key; mutils_word8 digest[MAX_DIGEST_SIZE]; char null = '\0'; mutils_word32 i,j, times, total; MHASH td; mutils_word32 block_size = mhash_get_block_size(algorithm); /* This should never happen, so naturally it is bound to. */ if (block_size == 0) { errno = EINVAL; return(-MUTILS_INVALID_SIZE); } times = key_size / block_size; if (key_size % block_size != 0) { times++; } total = times * block_size; key = mutils_malloc(total); if (key == NULL) { return(-MUTILS_SYSTEM_RESOURCE_ERROR); /* or what? */ } mutils_bzero(key, total); for (i = 0; i < times; i++) { td = mhash_init(algorithm); if (td == MHASH_FAILED) { mutils_free(key); return(-MUTILS_INVALID_FUNCTION); } for (j = 0; j < i; j++) { mhash(td, &null, 1); } mhash(td, password, plen); mhash_deinit(td, digest); mutils_memcpy(&key[i * block_size], digest, block_size); } mutils_memcpy(keyword, key, key_size); mutils_bzero(key, key_size); mutils_free(key); return(MUTILS_OK); } /* Key generation using OpenPGP Salted S2K algorithm */ mutils_error _mhash_gen_key_s2k_salted(hashid algorithm, void *keyword, mutils_word32 key_size, mutils_word8 *salt, mutils_word32 salt_size, mutils_word8 *password, mutils_word32 plen) { mutils_word8 *key; mutils_word8 digest[MAX_DIGEST_SIZE]; char null='\0'; mutils_word32 i; mutils_word32 j; mutils_word32 times; MHASH td; mutils_word32 block_size = mhash_get_block_size(algorithm); mutils_word32 total; if (salt == NULL) { return(-MUTILS_INVALID_INPUT_BUFFER); } if (salt_size < 8) { return(-MUTILS_INVALID_SIZE); /* This algorithm will use EXACTLY * 8 bytes salt. */ } times = key_size / block_size; if (key_size % block_size != 0) times++; total = times * block_size; key = mutils_malloc(total); #if defined(MHASH_ROBUST) if (key == NULL) return(-MUTILS_SYSTEM_RESOURCE_ERROR); /* or what? */ #endif for (i = 0; i < times; i++) { td = mhash_init(algorithm); if (td == MHASH_FAILED) { mutils_free(key); return(-MUTILS_INVALID_FUNCTION); } for (j = 0; j < i; j++) mhash(td, &null, 1); mhash(td, salt, 8); mhash(td, password, plen); mhash_deinit(td, digest); mutils_memcpy( &key[i*block_size], digest, block_size); } mutils_memcpy(keyword, key, key_size); mutils_bzero(key, key_size); mutils_free(key); return(MUTILS_OK); } #define EXPBIAS 6 /* Key generation using OpenPGP Iterated and Salted S2K algorithm */ mutils_error _mhash_gen_key_s2k_isalted(hashid algorithm, mutils_word64 _count, void *keyword, mutils_word32 key_size, mutils_word8 *salt, mutils_word32 salt_size, mutils_word8 *password, mutils_word32 plen) { mutils_word8 *key; mutils_word8 digest[MAX_DIGEST_SIZE]; mutils_word8 null='\0'; mutils_word32 i; mutils_word32 j; mutils_word32 z; mutils_word32 times; MHASH td; mutils_word32 block_size = mhash_get_block_size(algorithm); mutils_word8 *saltpass; mutils_word32 saltpass_size; mutils_word32 bcount, rest; mutils_word32 count = _count; mutils_word32 total; if (salt == NULL) return(-MUTILS_INVALID_INPUT_BUFFER); if (salt_size < 8) return(-MUTILS_INVALID_SIZE); /* This algorithm will use EXACTLY * 8 bytes salt. */ if ((saltpass = mutils_malloc(8 + plen)) == NULL) return(-MUTILS_SYSTEM_RESOURCE_ERROR); /* hmm */ mutils_memcpy( saltpass, salt, 8); mutils_memcpy( &saltpass[8], password, plen); saltpass_size = plen+8; times = key_size/block_size; if (key_size % block_size != 0) times++; total = times * block_size; key = mutils_malloc(total); if (key == NULL) { mutils_bzero(saltpass, saltpass_size); mutils_free(saltpass); return(-MUTILS_SYSTEM_RESOURCE_ERROR); } mutils_bzero(key, total); /* Calculate the iterations */ bcount /*bytes */ = ((mutils_word32)16 + (count & 15)) << ((count >> 4) + EXPBIAS); count /* iterations */ = (bcount / saltpass_size); rest = bcount % saltpass_size; if (bcount < saltpass_size) { count++; rest = 0; } for (i = 0; i < times; i++) { td = mhash_init(algorithm); if (td == MHASH_FAILED) { mutils_bzero( key, key_size); mutils_bzero( saltpass, saltpass_size); mutils_free(key); mutils_free(saltpass); return(-MUTILS_INVALID_FUNCTION); } for (j = 0; j < i; j++) mhash(td, &null, 1); for (z = 0; z < count; z++) { mhash(td, saltpass, saltpass_size); } mhash(td, saltpass, rest); mhash_deinit(td, digest); mutils_memcpy( &key[i*block_size], digest, block_size); } mutils_memcpy(keyword, key, key_size); mutils_bzero(key, key_size); mutils_bzero(saltpass, saltpass_size); mutils_free(key); mutils_free(saltpass); return(MUTILS_OK); }