Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Crypto / RandGen.cpp
1 // RandGen.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include <stdio.h>\r
6 #include "Windows/Synchronization.h"\r
7 #include "RandGen.h"\r
8 \r
9 #ifndef _WIN32\r
10 #include <unistd.h>\r
11 #define USE_POSIX_TIME\r
12 #define USE_POSIX_TIME2\r
13 #endif\r
14 \r
15 #ifdef USE_POSIX_TIME\r
16 #include <time.h>\r
17 #ifdef USE_POSIX_TIME2\r
18 #include <sys/time.h>\r
19 #endif\r
20 #endif\r
21 \r
22 // This is not very good random number generator.\r
23 // Please use it only for salt.\r
24 // First generated data block depends from timer and processID.\r
25 // Other generated data blocks depend from previous state\r
26 // Maybe it's possible to restore original timer value from generated value.\r
27 \r
28 void CRandomGenerator::Init()\r
29 {\r
30   NCrypto::NSha1::CContext hash;\r
31   hash.Init();\r
32 \r
33   #ifdef _WIN32\r
34   DWORD w = ::GetCurrentProcessId();\r
35   hash.Update((const Byte *)&w, sizeof(w));\r
36   w = ::GetCurrentThreadId();\r
37   hash.Update((const Byte *)&w, sizeof(w));\r
38   #else\r
39   pid_t pid = getpid();\r
40   hash.Update((const Byte *)&pid, sizeof(pid));\r
41   pid = getppid();\r
42   hash.Update((const Byte *)&pid, sizeof(pid));\r
43   #endif\r
44 \r
45   for (int i = 0; i < 1000; i++)\r
46   {\r
47     #ifdef _WIN32\r
48     LARGE_INTEGER v;\r
49     if (::QueryPerformanceCounter(&v))\r
50       hash.Update((const Byte *)&v.QuadPart, sizeof(v.QuadPart));\r
51     #endif\r
52 \r
53     #ifdef USE_POSIX_TIME\r
54     #ifdef USE_POSIX_TIME2\r
55     timeval v;\r
56     if (gettimeofday(&v, 0) == 0)\r
57     {\r
58       hash.Update((const Byte *)&v.tv_sec, sizeof(v.tv_sec));\r
59       hash.Update((const Byte *)&v.tv_usec, sizeof(v.tv_usec));\r
60     }\r
61     #endif\r
62     time_t v2 = time(NULL);\r
63     hash.Update((const Byte *)&v2, sizeof(v2));\r
64     #endif\r
65 \r
66     DWORD tickCount = ::GetTickCount();\r
67     hash.Update((const Byte *)&tickCount, sizeof(tickCount));\r
68     \r
69     for (int j = 0; j < 100; j++)\r
70     {\r
71       hash.Final(_buff);\r
72       hash.Init();\r
73       hash.Update(_buff, NCrypto::NSha1::kDigestSize);\r
74     }\r
75   }\r
76   hash.Final(_buff);\r
77   _needInit = false;\r
78 }\r
79 \r
80 static NWindows::NSynchronization::CCriticalSection g_CriticalSection;\r
81 \r
82 void CRandomGenerator::Generate(Byte *data, unsigned int size)\r
83 {\r
84   g_CriticalSection.Enter();\r
85   if (_needInit)\r
86     Init();\r
87   while (size > 0)\r
88   {\r
89     NCrypto::NSha1::CContext hash;\r
90     \r
91     hash.Init();\r
92     hash.Update(_buff, NCrypto::NSha1::kDigestSize);\r
93     hash.Final(_buff);\r
94     \r
95     hash.Init();\r
96     UInt32 salt = 0xF672ABD1;\r
97     hash.Update((const Byte *)&salt, sizeof(salt));\r
98     hash.Update(_buff, NCrypto::NSha1::kDigestSize);\r
99     Byte buff[NCrypto::NSha1::kDigestSize];\r
100     hash.Final(buff);\r
101     for (unsigned int i = 0; i < NCrypto::NSha1::kDigestSize && size > 0; i++, size--)\r
102       *data++ = buff[i];\r
103   }\r
104   g_CriticalSection.Leave();\r
105 }\r
106 \r
107 CRandomGenerator g_RandomGenerator;\r