/*
    Python Samba Password Hash Generating module
    
    Copyright (C) 2002 Barry Pederson <bp@barryp.org>

    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.

    -----------------

    2002-10-27  Initial version

*/

 
#include "Python.h" 
#include <memory.h>
#include <ctype.h>

#define LMPASSWDLEN 14

/* from md4.c and smbdes.c */
void mdfour(unsigned char *out, unsigned char *in, int n);
void E_P16(unsigned char *p14,unsigned char *p16);


static char module_doc [] =
"This module generates SMB lanman and nt password\n\
hashes suitable for use with Samba.\n\
\n\
Functions:\n\
\n\
  lmhash(passwd) -- return a string containing the lanman\n\
                    hash of the password\n\
  nthash(passwd) -- return a string containing the nt hash\n\
                    of the password\n\
  hash(passwd)   -- return a tuple containing the both the\n\
                    lanman hash and the nt hash strings\n\
";


/*
  convert 16-byte binary buffer to 32 hex-char Python string
*/
static char HEXCHARS[] = "0123456789ABCDEF";

static PyObject *
hash_to_string(char *tmp) 
    {
    int i;
    unsigned char c;
    char outbuffer[32];

    /* build string from binary hash */
    for(i = 0; i < 16; i++) 
        {
        c=tmp[i];
        outbuffer[ i*2   ] = HEXCHARS[(c>>4) & 0x0f];
        outbuffer[(i*2)+1] = HEXCHARS[   c   & 0x0f];
        }
        
    return PyString_FromStringAndSize(outbuffer, 32);
    }


static PyObject * 
lmhash(PyObject *self, PyObject *args)
    {
    char *pwd;
    int pwd_len;
    unsigned char lmpwd[LMPASSWDLEN+1];
    char hashout[17];
    int i;

    /* Unicode passwords are SOL I guess, python
       will convert to 8-bit chars here */
    if (!(PyArg_ParseTuple(args, "s#", &pwd, &pwd_len)))
        return NULL;

    /* make a copy that's truncated to 14 chars and uppercased */ 
    if (pwd_len > LMPASSWDLEN)       
        pwd_len = LMPASSWDLEN;
    memset(lmpwd, '\0', sizeof(lmpwd));
    for (i = 0; i < pwd_len; i++)
        lmpwd[i]=toupper(pwd[i]);        

    /* Generate the hash */
    memset(hashout,'\0',sizeof(hashout));
    E_P16(lmpwd, hashout);                
    
    /* clean things up  - don't know how much good it does since 
       Python presumably has other copies of the password floating 
       around, but what the hell - I'll do my part since I know it's
       safe.
    */
    memset(lmpwd, '\0', sizeof(lmpwd));
        
    return hash_to_string(hashout);
    }


static PyObject * 
nthash(PyObject *self, PyObject *args)
    {
    char *pwd;
    int pwd_len;
    char hashout[17];
         
    pwd = NULL;         
    if (!(PyArg_ParseTuple(args, "es#", "utf-16le", &pwd, &pwd_len)))
        return NULL;

    memset(hashout,'\0',sizeof(hashout));
    mdfour(hashout, pwd, pwd_len);        
    
    /* clean things up  - don't know how much good it does since 
       Python presumably has other copies of the password floating 
       around, but what the hell - I'll do my part since I'm pretty
       sure it's safe, from my understanding of PyArg_ParseTuple and "es#"
    */
    memset(pwd, '\0', pwd_len);
    PyMem_Free(pwd);
    
    return hash_to_string(hashout);
    }


static PyObject * 
hash(PyObject *self, PyObject *args)
    {
    PyObject *result;
    
    result = PyTuple_New(2);
    PyTuple_SetItem(result, 0, lmhash(self, args));
    PyTuple_SetItem(result, 1, nthash(self, args));
    
    return result;        
    }


/* List of functions exported by this module */
static PyMethodDef smbpasswd_functions[] = 
    {
    {"lmhash",  lmhash, METH_VARARGS},
    {"nthash",  nthash, METH_VARARGS},
    {"hash",    hash,   METH_VARARGS},
    {NULL,      NULL}   /* Sentinel */
    };


/* Initialize this module. */
void 
initsmbpasswd(void)
    {
    Py_InitModule3("smbpasswd", smbpasswd_functions, module_doc);
    }

/****** EOF *********/


syntax highlighted by Code2HTML, v. 0.9.1