File: winrand.c

package info (click to toggle)
codeville 0.8.0-2.1
  • links: PTS
  • area: main
  • in suites: buster, sid, stretch
  • size: 1,140 kB
  • sloc: python: 10,335; ansic: 89; sh: 62; makefile: 25
file content (121 lines) | stat: -rw-r--r-- 3,496 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* -*- C -*- */
/*
 * Uses Windows CryptoAPI CryptGenRandom to get random bytes
 *
 * Distribute and use freely; there are no restrictions on further 
 * dissemination and usage except those imposed by the laws of your 
 * country of residence.  This software is provided "as is" without
 * warranty of fitness for use or suitability for any purpose, express
 * or implied. Use at your own risk or not at all. 
 *
 */

/* Author: Mark Moraes */

#include "Python.h"

#ifdef MS_WIN32

#define _WIN32_WINNT 0x400
#define WINSOCK

#include <windows.h>
#include <wincrypt.h>

LPVOID PrintWindowsError(char* msg, DWORD error) 
{
  LPVOID lpMsgBuf;
  if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		     FORMAT_MESSAGE_FROM_SYSTEM | 
		     FORMAT_MESSAGE_IGNORE_INSERTS,
		     NULL, error,
		     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		     (LPTSTR) &lpMsgBuf,
		     0,
		     NULL )) {
    fprintf(stderr, "FormatMessage had an error when processing this error (%d) and this message (%s)!", error, msg);
  }
  fprintf(stderr, "%s: %s\n", msg, lpMsgBuf); 
  LocalFree(lpMsgBuf);
}


static char winrandom__doc__[] =
"winrandom(nbytes): Returns nbytes of random data from Windows CryptGenRandom,"
"a cryptographically strong pseudo-random generator using system entropy";

static PyObject *
winrandom(PyObject *self, PyObject *args)
{
  HCRYPTPROV hcp = 0;
  int n, nbytes;
  PyObject *res;
  char *buf;

  if (!PyArg_ParseTuple(args, "i", &n)) {
    return NULL;
  }
  /* Just in case char != BYTE */
  nbytes = (n * sizeof(char)) / sizeof(BYTE);
  if (nbytes <= 0) {
    PyErr_SetString(PyExc_ValueError, "nbytes must be positive number");
    return NULL;
  }
  if ((buf = (char *) PyMem_Malloc(nbytes)) == NULL)
    return PyErr_NoMemory();

  if (! CryptAcquireContext(&hcp, NULL, NULL, PROV_RSA_FULL, 0)) {
    // If the last error was a bad keyset, then it might be
    // because we need to generate a keyset, so we call
    // CryptAcquireContext again in order to try to create
    // a key set this time.
    DWORD lastError = GetLastError();
    if (lastError == NTE_BAD_KEYSET) {
      if (!CryptAcquireContext(&hcp, NULL, NULL, PROV_RSA_FULL,
                               CRYPT_NEWKEYSET)) {
        lastError = GetLastError();
      } else {
        lastError = 0;
      }
    }
    if (lastError != 0) {
      PyErr_Format(PyExc_SystemError,
                   "CryptAcquireContext failed, error %i",
                   lastError);
      PrintWindowsError("CryptAcquireContext failed", lastError);
      PyMem_Free(buf);
      return NULL;
    }
  } 
  if (! CryptGenRandom(hcp, (DWORD) nbytes, (BYTE *) buf)) {
    PyErr_Format(PyExc_SystemError,
                 "CryptGenRandom failed, error %i",
                 GetLastError());
    PyMem_Free(buf);
    (void) CryptReleaseContext(hcp, 0);
    return NULL;
  }
  if (! CryptReleaseContext(hcp, 0)) {
    PyErr_Format(PyExc_SystemError,
                 "CryptReleaseContext failed, error %i",
                 GetLastError());
    return NULL;
  }
  res = PyString_FromStringAndSize(buf, n);
  PyMem_Free(buf);
  return res;
}

static PyMethodDef WRMethods[] = {
  {"winrandom", (PyCFunction) winrandom, METH_VARARGS, winrandom__doc__},
  {NULL,	    NULL}	 /* Sentinel */
};


void
initwinrandom()
{
  (void) Py_InitModule("winrandom", WRMethods);
}

#endif /* MS_WIN32 */