3

我有兴趣从 .NET 中的鼠标移动和击键生成熵(出于加密目的,这可能是在通过应用程序本身的事件接收鼠标移动和击键数据的 Forms 应用程序中,也可能是在 Web 应用程序中鼠标移动和击键数据使用 JavaScript 记录并通过 Ajax 发送到服务器。

该技术目前正在新的 MEGA 站点上使用。

我自己做了一些研究,发现了一个看起来像 C++ 的好例子,但它有点超出了我的 C/C++ 知识。

http://etutorials.org/Programming/secure+programming/Chapter+11.+Random+Numbers/11.21+Gathering+Entropy+from+Mouse+Events+on+Windows/

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

    #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->cbRequested);
          return TRUE;

        case WM_COMMAND:
          if (LOWORD(wParam) =  = IDOK && HIWORD(wParam) =  = BN_CLICKED) {
            EndDialog(hwndDlg, TRUE);
            return TRUE;
          }
          break;

        case WM_MOUSEMOVE:
          pDlgData = (SPC_DIALOGDATA *)GetWindowLong(hwndDlg, DWL_USER);
          if (pDlgData->dEntropy < pDlgData->cbRequested) {
            MousePos.ptMousePos.x = LOWORD(lParam);
            MousePos.ptMousePos.y = HIWORD(lParam);
            MousePos.dwTickCount  = GetTickCount(  );
            ClientToScreen(hwndDlg, &(MousePos.ptMousePos));
            CryptHashData(pDlgData->hHash, (BYTE *)&MousePos, sizeof(MousePos), 0);
            if ((MousePos.ptMousePos.x != pDlgData->ptLastPos.x ||
                 MousePos.ptMousePos.y != pDlgData->ptLastPos.y)  && 
                MousePos.dwTickCount - pDlgData->dwLastTime > 100) {
              pDlgData->ptLastPos = MousePos.ptMousePos;
              pDlgData->dwLastTime = MousePos.dwTickCount;
              pDlgData->dEntropy += SPC_ENTROPY_PER_SAMPLE;
              SendDlgItemMessage(hwndDlg, SPC_PROGRESS_BARID, PBM_SETPOS,
                                 (WPARAM)pDlgData->dEntropy, 0);
              if (pDlgData->dEntropy >= pDlgData->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(&hProvider, 0, MS_DEF_PROV, PROV_RSA_FULL,
                              CRYPT_VERIFYCONTEXT)) goto done;
      if (!CryptCreateHash(hProvider, CALG_SHA1, 0, 0, &hHash)) goto done;
      if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashData, &dwByteCount,
                             0)) goto done;
      if (cbOutput > 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(&(DialogData.ptLastPos));

      bResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(SPC_MOUSE_DLGID),
                               hWndParent, MouseEntropyProc, (LPARAM)&DialogData);

      if (bResult) {
        if (!CryptGetHashParam(hHash, HP_HASHVAL, pbHashData, &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(&CommonControls);
  SpcGatherMouseEntropy(hInstance, 0, pbEntropy, sizeof(pbEntropy));
  return 0;
}

如果有人可以阐明如何通过 .NET(C# 或 VB.Net 很好)来实现这一点,那将是最有帮助的。

提前致谢。

克里斯

4

1 回答 1

3

您不必这样做,Microsoft 已经为您完成了。内置的 .NET 方法 RNGCryptoServiceProvider.GetBytes() 提供了从 Windows CryptGenRandom 派生的高质量真正随机字节。引用 RFC 4086:

Windows CryptAPI 加密服务提供程序为每个用户存储一个种子状态变量。当调用 CryptGenRandom 时,它与调用中提供的任何随机性以及各种系统和用户数据(例如进程 ID、线程 ID、系统时钟、系统时间、系统计数器、内存状态、空闲磁盘集群和散列用户)相结合环境块。这些数据全部馈送到 SHA-1,输出用于播种 RC4 密钥流。该密钥流用于生成请求的伪随机数据并更新用户的种子状态变量。

Windows“.NET”的用户可能会发现使用 RNGCryptoServiceProvider.GetBytes 方法接口更容易。

无需重新发明轮子,它已经为您构建好了。

于 2013-01-21T00:00:09.413 回答