title: Using mouse movement and keystrokes to generate entropy for encryption (As seen on MEGA)
body: <p>I am interested in generating entropy from mouse movements and keystrokes in .NET (for the purposes of encryption this could be either in a Forms application where the mouse movement and keystroke data is received via events in the application itself or in a web application where the mouse movement and keystroke data is recorded using JavaScript and sent to the server via Ajax.</p>
  
  <p>This technique is being currently employed on the new MEGA site.</p>
  
  <p>I have done a little research myself and came across what looks like a good example in C++ however it is a little outside my C/C++ knowledge.</p>
  
  <p><a href="http://etutorials.org/Programming/secure+programming/Chapter+11.+Random+Numbers/11.21+Gathering+Entropy+from+Mouse+Events+on+Windows/" rel="nofollow">http://etutorials.org/Programming/secure+programming/Chapter+11.+Random+Numbers/11.21+Gathering+Entropy+from+Mouse+Events+on+Windows/</a></p>
  
  <pre><code>    #include &lt;windows.h&gt;
      #include &lt;wincrypt.h&gt;
      #include &lt;commctrl.h&gt;
  
      #define SPC_ENTROPY_PER_SAMPLE  0.5
      #define SPC_MOUSE_DLGID         102
      #define SPC_PROGRESS_BARID      1000
      #define SPC_MOUSE_COLLECTID     1003
      #define SPC_MOUSE_STATIC        1002
  
      typedef struct {
        double     dEntropy;
        DWORD      cbRequested;
        POINT      ptLastPos;
        DWORD      dwLastTime;
        HCRYPTHASH hHash;
      } SPC_DIALOGDATA;
  
      typedef struct {
        POINT ptMousePos;
        DWORD dwTickCount;
      } SPC_MOUSEPOS;
  
      static BOOL CALLBACK MouseEntropyProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
                                            LPARAM lParam) {
        SPC_MOUSEPOS    MousePos;
        SPC_DIALOGDATA  *pDlgData;
  
        switch (uMsg) {
          case WM_INITDIALOG:
            pDlgData = (SPC_DIALOGDATA *)lParam;
            SetWindowLong(hwndDlg, DWL_USER, lParam);
            SendDlgItemMessage(hwndDlg, SPC_PROGRESS_BARID, PBM_SETRANGE32, 0,
                               pDlgData-&gt;cbRequested);
            return TRUE;
  
          case WM_COMMAND:
            if (LOWORD(wParam) =  = IDOK &amp;&amp; HIWORD(wParam) =  = BN_CLICKED) {
              EndDialog(hwndDlg, TRUE);
              return TRUE;
            }
            break;
  
          case WM_MOUSEMOVE:
            pDlgData = (SPC_DIALOGDATA *)GetWindowLong(hwndDlg, DWL_USER);
            if (pDlgData-&gt;dEntropy &lt; pDlgData-&gt;cbRequested) {
              MousePos.ptMousePos.x = LOWORD(lParam);
              MousePos.ptMousePos.y = HIWORD(lParam);
              MousePos.dwTickCount  = GetTickCount(  );
              ClientToScreen(hwndDlg, &amp;(MousePos.ptMousePos));
              CryptHashData(pDlgData-&gt;hHash, (BYTE *)&amp;MousePos, sizeof(MousePos), 0);
              if ((MousePos.ptMousePos.x != pDlgData-&gt;ptLastPos.x ||
                   MousePos.ptMousePos.y != pDlgData-&gt;ptLastPos.y)  &amp;&amp; 
                  MousePos.dwTickCount - pDlgData-&gt;dwLastTime &gt; 100) {
                pDlgData-&gt;ptLastPos = MousePos.ptMousePos;
                pDlgData-&gt;dwLastTime = MousePos.dwTickCount;
                pDlgData-&gt;dEntropy += SPC_ENTROPY_PER_SAMPLE;
                SendDlgItemMessage(hwndDlg, SPC_PROGRESS_BARID, PBM_SETPOS,
                                   (WPARAM)pDlgData-&gt;dEntropy, 0);
                if (pDlgData-&gt;dEntropy &gt;= pDlgData-&gt;cbRequested) {
                  EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
                  SetFocus(GetDlgItem(hwndDlg, IDOK));
                  MessageBeep(0xFFFFFFFF);
                }
              }
            }
            return TRUE;
        }
  
        return FALSE;
      }
  
      BOOL SpcGatherMouseEntropy(HINSTANCE hInstance, HWND hWndParent, 
                                    BYTE *pbOutput, DWORD cbOutput) {
        BOOL           bResult = FALSE;
        BYTE           *pbHashData = 0;
        DWORD          cbHashData, dwByteCount = sizeof(DWORD);
        HCRYPTHASH     hHash = 0;
        HCRYPTPROV     hProvider = 0;
        SPC_DIALOGDATA DialogData;
  
        if (!CryptAcquireContext(&amp;hProvider, 0, MS_DEF_PROV, PROV_RSA_FULL,
                                CRYPT_VERIFYCONTEXT)) goto done;
        if (!CryptCreateHash(hProvider, CALG_SHA1, 0, 0, &amp;hHash)) goto done;
        if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&amp;cbHashData, &amp;dwByteCount,
                               0)) goto done;
        if (cbOutput &gt; cbHashData) goto done;
        if (!(pbHashData = (BYTE *)LocalAlloc(LMEM_FIXED, cbHashData))) goto done;
  
        DialogData.dEntropy     = 0.0;
        DialogData.cbRequested = cbOutput * 8;
        DialogData.hHash        = hHash;
        DialogData.dwLastTime   = 0;
        GetCursorPos(&amp;(DialogData.ptLastPos));
  
        bResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(SPC_MOUSE_DLGID),
                                 hWndParent, MouseEntropyProc, (LPARAM)&amp;DialogData);
  
        if (bResult) {
          if (!CryptGetHashParam(hHash, HP_HASHVAL, pbHashData, &amp;cbHashData, 0))
            bResult = FALSE;
          else
            CopyMemory(pbOutput, pbHashData, cbOutput);
        }
  
      done:
        if (pbHashData) LocalFree(pbHashData);
        if (hHash) CryptDestroyHash(hHash);
        if (hProvider) CryptReleaseContext(hProvider, 0);
        return bResult;
      }
  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
                     int nShowCmd) {
    BYTE                 pbEntropy[20];
    INITCOMMONCONTROLSEX CommonControls;
  
    CommonControls.dwSize = sizeof(CommonControls);
    CommonControls.dwICC  = ICC_PROGRESS_CLASS;
    InitCommonControlsEx(&amp;CommonControls);
    SpcGatherMouseEntropy(hInstance, 0, pbEntropy, sizeof(pbEntropy));
    return 0;
  }
  </code></pre>
  
  <p>If anyone can shed some light onto how to achieve this via .NET (C# or VB.Net is fine) would be most helpful.</p>
  
  <p>Thanks in Advance.</p>
  
  <p>Chris </p>