Back to index

python-bcrypt  0.2
Functions | Variables
bcrypt_python.c File Reference
#include "Python.h"

Go to the source code of this file.

Functions

char * pybc_bcrypt (const char *, const char *)
void encode_salt (char *, u_int8_t *, u_int16_t, u_int8_t)
 PyDoc_STRVAR (bcrypt_encode_salt_doc,"encode_salt(csalt, log_rounds) -> encoded_salt\n\ Encode a raw binary salt and the specified log2(rounds) as a\n\ standard bcrypt text salt. Used internally by bcrypt.gensalt()\n")
static PyObject * bcrypt_encode_salt (PyObject *self, PyObject *args, PyObject *kw_args)
 PyDoc_STRVAR (bcrypt_hashpw_doc,"hashpw(password, salt) -> hashed_password\n\ Hash the specified password and the salt using the OpenBSD\n\ Blowfish password hashing algorithm. Returns the hashed password.\n")
static PyObject * bcrypt_hashpw (PyObject *self, PyObject *args, PyObject *kw_args)
 PyDoc_STRVAR (module_doc,"Internal module used by bcrypt.\n")
PyMODINIT_FUNC init_bcrypt (void)

Variables

static PyMethodDef bcrypt_methods []

Function Documentation

static PyObject* bcrypt_encode_salt ( PyObject *  self,
PyObject *  args,
PyObject *  kw_args 
) [static]

Definition at line 37 of file bcrypt_python.c.

{
       static char *keywords[] = { "csalt", "log_rounds", NULL };
       char *csalt = NULL;
       int csaltlen = -1;
       long log_rounds = -1;
       char ret[64];

       if (!PyArg_ParseTupleAndKeywords(args, kw_args, "s#l:encode_salt",
           keywords, &csalt, &csaltlen, &log_rounds))
                return NULL;
       if (csaltlen != 16) {
              PyErr_SetString(PyExc_ValueError, "Invalid salt length");
              return NULL;
       }
       if (log_rounds < 4 || log_rounds > 31) {
              PyErr_SetString(PyExc_ValueError, "Invalid number of rounds");
              return NULL;
       }
       encode_salt(ret, csalt, csaltlen, log_rounds);
       return PyString_FromString(ret);
}

Here is the call graph for this function:

static PyObject* bcrypt_hashpw ( PyObject *  self,
PyObject *  args,
PyObject *  kw_args 
) [static]

Definition at line 66 of file bcrypt_python.c.

{
       static char *keywords[] = { "password", "salt", NULL };
       char *password = NULL, *salt = NULL;
       char *ret;

       if (!PyArg_ParseTupleAndKeywords(args, kw_args, "ss:hashpw", keywords,
           &password, &salt))
                return NULL;

       char *password_copy = strdup(password);
       char *salt_copy = strdup(salt);

       Py_BEGIN_ALLOW_THREADS;
       ret = pybc_bcrypt(password_copy, salt_copy);
       Py_END_ALLOW_THREADS;

       free(password_copy);
       free(salt_copy);
       if ((ret == NULL) ||
           strcmp(ret, ":") == 0) {
              PyErr_SetString(PyExc_ValueError, "Invalid salt");
              return NULL;
       }

       return PyString_FromString(ret);
}

Here is the call graph for this function:

void encode_salt ( char *  ,
u_int8_t *  ,
u_int16_t  ,
u_int8_t   
)

Definition at line 134 of file bcrypt.c.

{
       salt[0] = '$';
       salt[1] = BCRYPT_VERSION;
       salt[2] = 'a';
       salt[3] = '$';

       snprintf(salt + 4, 4, "%2.2u$", logr);

       encode_base64((u_int8_t *) salt + 7, csalt, clen);
}

Here is the call graph for this function:

Here is the caller graph for this function:

PyMODINIT_FUNC init_bcrypt ( void  )

Definition at line 105 of file bcrypt_python.c.

{
       PyObject *m;

       m = Py_InitModule3("bcrypt._bcrypt", bcrypt_methods, module_doc);
       PyModule_AddStringConstant(m, "__version__", "0.1");
}
char* pybc_bcrypt ( const char *  ,
const char *   
)

Definition at line 150 of file bcrypt.c.

{
       pybc_blf_ctx state;
       u_int32_t rounds, i, k;
       u_int16_t j;
       u_int8_t key_len, salt_len, logr, minor;
       u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
       u_int8_t csalt[BCRYPT_MAXSALT];
       u_int32_t cdata[BCRYPT_BLOCKS];
       int n;

       /* Discard "$" identifier */
       salt++;

       if (*salt > BCRYPT_VERSION) {
              /* How do I handle errors ? Return ':' */
              return error;
       }

       /* Check for minor versions */
       if (salt[1] != '$') {
               switch (salt[1]) {
               case 'a':
                      /* 'ab' should not yield the same as 'abab' */
                      minor = salt[1];
                      salt++;
                      break;
               default:
                      return error;
               }
       } else
               minor = 0;

       /* Discard version + "$" identifier */
       salt += 2;

       if (salt[2] != '$')
              /* Out of sync with passwd entry */
              return error;

       /* Computer power doesn't increase linear, 2^x should be fine */
       n = atoi(salt);
       if (n > 31 || n < 0)
              return error;
       logr = (u_int8_t)n;
       if ((rounds = (u_int32_t) 1 << logr) < BCRYPT_MINROUNDS)
              return error;

       /* Discard num rounds + "$" identifier */
       salt += 3;

       if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
              return error;

       /* We dont want the base64 salt but the raw data */
       decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt);
       salt_len = BCRYPT_MAXSALT;
       key_len = strlen(key) + (minor >= 'a' ? 1 : 0);

       /* Setting up S-Boxes and Subkeys */
       pybc_Blowfish_initstate(&state);
       pybc_Blowfish_expandstate(&state, csalt, salt_len,
           (u_int8_t *) key, key_len);
       for (k = 0; k < rounds; k++) {
              pybc_Blowfish_expand0state(&state, (u_int8_t *) key, key_len);
              pybc_Blowfish_expand0state(&state, csalt, salt_len);
       }

       /* This can be precomputed later */
       j = 0;
       for (i = 0; i < BCRYPT_BLOCKS; i++) {
              cdata[i] = pybc_Blowfish_stream2word(ciphertext,
                  4 * BCRYPT_BLOCKS, &j);
       }

       /* Now do the encryption */
       for (k = 0; k < 64; k++)
              pybc_blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);

       for (i = 0; i < BCRYPT_BLOCKS; i++) {
              ciphertext[4 * i + 3] = cdata[i] & 0xff;
              cdata[i] = cdata[i] >> 8;
              ciphertext[4 * i + 2] = cdata[i] & 0xff;
              cdata[i] = cdata[i] >> 8;
              ciphertext[4 * i + 1] = cdata[i] & 0xff;
              cdata[i] = cdata[i] >> 8;
              ciphertext[4 * i + 0] = cdata[i] & 0xff;
       }


       i = 0;
       encrypted[i++] = '$';
       encrypted[i++] = BCRYPT_VERSION;
       if (minor)
              encrypted[i++] = minor;
       encrypted[i++] = '$';

       snprintf(encrypted + i, 4, "%2.2u$", logr);

       encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
       encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
           4 * BCRYPT_BLOCKS - 1);
       return encrypted;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PyDoc_STRVAR ( bcrypt_encode_salt_doc  ,
"encode_salt(csalt, log_rounds) -> encoded_salt\n\ Encode a raw binary salt and the specified log2(rounds) as a\n\ standard bcrypt text salt. Used internally by bcrypt.gensalt()\n"   
)
PyDoc_STRVAR ( bcrypt_hashpw_doc  ,
"hashpw(password, salt) -> hashed_password\n\ Hash the specified password and the salt using the OpenBSD\n\ Blowfish password hashing algorithm. Returns the hashed password.\n"   
)
PyDoc_STRVAR ( module_doc  ,
"Internal module used by bcrypt.\n"   
)

Variable Documentation

PyMethodDef bcrypt_methods[] [static]
Initial value:
 {
       {      "hashpw",     (PyCFunction)bcrypt_hashpw,
              METH_VARARGS|METH_KEYWORDS, bcrypt_hashpw_doc    },
       {      "encode_salt",       (PyCFunction)bcrypt_encode_salt,
              METH_VARARGS|METH_KEYWORDS, bcrypt_encode_salt_doc      },
       {NULL,        NULL}         
}

Definition at line 94 of file bcrypt_python.c.