消息处理程序中的RAND_event()是否会导致UI中的小冻结? 有一个消息处理程序(在C++ Builder中),像这样: void __fastcall TMainForm::HandleMessages(tagMSG &Msg, bool &Handled) { RAND_event(Msg.message, Msg.wParam, Msg.lParam); //... }
消息处理程序中的RAND_event()是否会导致UI中的小冻结? 有一个消息处理程序(在C++ Builder中),像这样: void __fastcall TMainForm::HandleMessages(tagMSG &Msg, bool &Handled) { RAND_event(Msg.message, Msg.wParam, Msg.lParam); //... },c++,windows,winapi,openssl,c++builder,C++,Windows,Winapi,Openssl,C++builder,RAND\u event()会不会在UI中造成一些冻结 谢谢 编辑: RAND\u event()来自OpenSSL,下面是它的描述: RAND\u event()从Windows事件(如鼠标)收集熵 移动和其他用户交互。它应该被称为 发送到窗口的所有消息的iMsg、wParam和lParam参数 程序它将估计事件消息中包含的熵 (如有),并将其添加到PRNG中。然后程序可以处理 像往常一样发短信 当有疑问时-验证源代码 来自\crypto\rand\rand\u win.c(OpenSSL 1
RAND\u event()
会不会在UI中造成一些冻结
谢谢
编辑:
RAND\u event()
来自OpenSSL,下面是它的描述:
RAND\u event()
从Windows事件(如鼠标)收集熵
移动和其他用户交互。它应该被称为
发送到窗口的所有消息的iMsg、wParam和lParam参数
程序它将估计事件消息中包含的熵
(如有),并将其添加到PRNG中。然后程序可以处理
像往常一样发短信
当有疑问时-验证源代码 来自
\crypto\rand\rand\u win.c
(OpenSSL 1.0.2f)
正如您所看到的,这里没有循环、等待或类似的事情,只有一些基本的比较、分配和添加。您还可以自己验证RAND_event()
中使用的一些函数,如readtimer()
,但它们也不包含任何可能导致性能显著降低的内容(至少与使用UI相比)
编辑:
啊,我刚才看到了雷米的评论,我的错。无论如何,我将此作为一个扩展的答案(已经作为注释存在)保留在一个稍微(非常小)不同的视图中。如果有疑问,请验证源代码 来自
\crypto\rand\rand\u win.c
(OpenSSL 1.0.2f)
正如您所看到的,这里没有循环、等待或类似的事情,只有一些基本的比较、分配和添加。您还可以自己验证RAND_event()
中使用的一些函数,如readtimer()
,但它们也不包含任何可能导致性能显著降低的内容(至少与使用UI相比)
编辑:
啊,我刚才看到了雷米的评论,我的错。不管怎么说,我把它作为一个扩展的答案(已经作为一个评论存在)从一个小(非常小)点不同的观点
RAND_event()是否会导致UI中的小冻结
也许吧。熵是通过RAND_add
添加的,这意味着熵被提取然后被消化。因此,每次调用RAND\u add
时都会调用一个哈希函数
如果您使用的是默认的RAND引擎,则使用的引擎是\crypto\RAND\md\u RAND.c
中的引擎。这意味着RAND\u add
调用ssleay\u RAND\u add
。功能如下所示
如果发送了大量Windows消息,那么我可以想象桌面在消化熵的同时速度会变慢。在移动操作系统上,这个问题可能会变得更加严重。分析工具应该能够为您提供更多信息
我认为Windows上的
RAND\u事件
可能有一个优化。。。消息应累积,然后批量添加。也就是说,累积熵,然后在第8次、第16次或第32次调用时调用RAND\u add
生成器的运行状况应该不会受到影响,因为有太多的Windows消息发送到应用程序。您可以使用来了解发送的邮件数量
如果您在某处使用
RAND\u poll
,则可以看到一个明显的块。有关这方面的详细信息,请参阅OpenSSL错误跟踪器上的
static void ssleay\u rand\u add(const void*buf,int num,double add)
{
int i,j,k,st_idx;
长md_c[2];
无符号字符local_md[md_DIGEST_LENGTH];
执行副总裁MD CTX m;
int不锁定;
如果(!num)
返回;
/*
*(基于rand(3)手册页)
*
*输入被切碎为20字节的单位(对于
*最后一个块)。这些块中的每一个都通过散列运行
*函数如下:传递给哈希函数的数据
*是当前的“md”,与“状态”中的字节数相同
*(在递增循环索引中确定的位置)为
*当前“块”、新密钥数据“块”和“计数”
*(每次使用后递增)。
*此操作的结果保存在“md”中,也被xored到
*“状态”位于用作输入的相同位置
*散列函数。
*/
/*检查一下我们是否已经有锁了*/
if(加密锁){
加密线程ID cur;
加密线程ID当前(&cur);
加密锁(CRYPTO_lock_RAND2);
do_not_lock=!CRYPTO_THREADID_cmp(&locking_THREADID,&cur);
加密锁解锁(加密锁RAND2);
}否则
不锁定=0;
如果(!不锁定)
加密锁(加密锁);
st_idx=状态指数;
/*
*使用我们自己的计数器副本,这样即使是并发线程
*种子具有完全相同的数据,并使用相同的子数组
*有些不同
*/
md_c[0]=md_计数[0];
md_c[1]=md_计数[1];
memcpy(本地医学博士、医学博士、医学博士学位);
/*状态\索引状态\数量)
state_num=state_索引;
}
/*州(索引、摘要、长度)?MD_摘要_长度:j;
MD_Init(&m);
MD_更新(&m、本地MD、MD_摘要长度);
k=(st_idx+j)-状态大小;
如果(k>0){
MD_更新(&m,&(州[st_idx]),j-k;
MD_更新(&m,&(状态[0]),k);
}否则
MD_更新(&m)和(州[st_idx]),j;
/*不要删除对MD_Update()的以下调用*/
MD_更新(&m,buf,j);
/*
*我们知道该行可能导致purify和valgrind等程序
*投诉未初始化数据的使用。问题不是,,
*是打电话的人。拆下那条线会确保你得到
*非常糟糕的随机性和其他问题,例如
*不安全的密钥。
*/
MD_Update(&m,(unsigned char*)和(MD_c[0]),sizeof(MD_c));
MD_最终和m,本地
int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
{
double add_entropy = 0;
switch (iMsg) {
case WM_KEYDOWN:
{
static WPARAM key;
if (key != wParam)
add_entropy = 0.05;
key = wParam;
}
break;
case WM_MOUSEMOVE:
{
static int lastx, lasty, lastdx, lastdy;
int x, y, dx, dy;
x = LOWORD(lParam);
y = HIWORD(lParam);
dx = lastx - x;
dy = lasty - y;
if (dx != 0 && dy != 0 && dx - lastdx != 0 && dy - lastdy != 0)
add_entropy = .2;
lastx = x, lasty = y;
lastdx = dx, lastdy = dy;
}
break;
}
readtimer();
RAND_add(&iMsg, sizeof(iMsg), add_entropy);
RAND_add(&wParam, sizeof(wParam), 0);
RAND_add(&lParam, sizeof(lParam), 0);
return (RAND_status());
}
static void ssleay_rand_add(const void *buf, int num, double add)
{
int i, j, k, st_idx;
long md_c[2];
unsigned char local_md[MD_DIGEST_LENGTH];
EVP_MD_CTX m;
int do_not_lock;
if (!num)
return;
/*
* (Based on the rand(3) manpage)
*
* The input is chopped up into units of 20 bytes (or less for
* the last block). Each of these blocks is run through the hash
* function as follows: The data passed to the hash function
* is the current 'md', the same number of bytes from the 'state'
* (the location determined by in incremented looping index) as
* the current 'block', the new key data 'block', and 'count'
* (which is incremented after each use).
* The result of this is kept in 'md' and also xored into the
* 'state' at the same locations that were used as input into the
* hash function.
*/
/* check if we already have the lock */
if (crypto_lock_rand) {
CRYPTO_THREADID cur;
CRYPTO_THREADID_current(&cur);
CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
} else
do_not_lock = 0;
if (!do_not_lock)
CRYPTO_w_lock(CRYPTO_LOCK_RAND);
st_idx = state_index;
/*
* use our own copies of the counters so that even if a concurrent thread
* seeds with exactly the same data and uses the same subarray there's
* _some_ difference
*/
md_c[0] = md_count[0];
md_c[1] = md_count[1];
memcpy(local_md, md, sizeof md);
/* state_index <= state_num <= STATE_SIZE */
state_index += num;
if (state_index >= STATE_SIZE) {
state_index %= STATE_SIZE;
state_num = STATE_SIZE;
} else if (state_num < STATE_SIZE) {
if (state_index > state_num)
state_num = state_index;
}
/* state_index <= state_num <= STATE_SIZE */
/*
* state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE] are what we
* will use now, but other threads may use them as well
*/
md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
if (!do_not_lock)
CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
EVP_MD_CTX_init(&m);
for (i = 0; i < num; i += MD_DIGEST_LENGTH) {
j = (num - i);
j = (j > MD_DIGEST_LENGTH) ? MD_DIGEST_LENGTH : j;
MD_Init(&m);
MD_Update(&m, local_md, MD_DIGEST_LENGTH);
k = (st_idx + j) - STATE_SIZE;
if (k > 0) {
MD_Update(&m, &(state[st_idx]), j - k);
MD_Update(&m, &(state[0]), k);
} else
MD_Update(&m, &(state[st_idx]), j);
/* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
MD_Update(&m, buf, j);
/*
* We know that line may cause programs such as purify and valgrind
* to complain about use of uninitialized data. The problem is not,
* it's with the caller. Removing that line will make sure you get
* really bad randomness and thereby other problems such as very
* insecure keys.
*/
MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c));
MD_Final(&m, local_md);
md_c[1]++;
buf = (const char *)buf + j;
for (k = 0; k < j; k++) {
/*
* Parallel threads may interfere with this, but always each byte
* of the new state is the XOR of some previous value of its and
* local_md (itermediate values may be lost). Alway using locking
* could hurt performance more than necessary given that
* conflicts occur only when the total seeding is longer than the
* random state.
*/
state[st_idx++] ^= local_md[k];
if (st_idx >= STATE_SIZE)
st_idx = 0;
}
}
EVP_MD_CTX_cleanup(&m);
if (!do_not_lock)
CRYPTO_w_lock(CRYPTO_LOCK_RAND);
/*
* Don't just copy back local_md into md -- this could mean that other
* thread's seeding remains without effect (except for the incremented
* counter). By XORing it we keep at least as much entropy as fits into
* md.
*/
for (k = 0; k < (int)sizeof(md); k++) {
md[k] ^= local_md[k];
}
if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
entropy += add;
if (!do_not_lock)
CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
}