1 /**
2 * Win32 CAPI EntropySource
3 * 
4 * Copyright:
5 * (C) 1999-2007,2015 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.entropy.es_capi;
12 
13 version(Windows):
14 import botan.constants;
15 static if (BOTAN_HAS_ENTROPY_SRC_CAPI):
16 
17 import botan.entropy.entropy_src;
18 import botan.utils.types;
19 import botan.utils.parsing;
20 
21 /**
22 * Win32 CAPI Entropy Source
23 */
24 final class Win32CAPIEntropySource : EntropySource
25 {
26 public:
27     @property string name() const { return "Win32 CryptoGenRandom"; }
28 
29     /*
30     * Gather Entropy from Win32 CAPI
31     */
32     void poll(ref EntropyAccumulator accum)
33     {
34         m_buf.length = 32;
35         
36         foreach (prov_type; m_prov_types[])
37         {
38             auto csp = new CSPHandle(prov_type);
39 			scope(exit) csp.destroy();
40             
41             if (size_t got = csp.genRandom(m_buf.ptr, m_buf.length))
42             {
43                 accum.add(m_buf.ptr, got, 6);
44                 break;
45             }
46         }
47     }
48 
49     /**
50     * Win32_Capi_Entropysource Constructor
51     * Params:
52     *  provs = list of providers, separated by ':'
53     */
54     this(in string provs = "")
55     {
56         Vector!string capi_provs = splitter(provs, ':');
57         
58         foreach (capi_prov; capi_provs[])
59         {
60             if (capi_prov == "RSA_FULL")  m_prov_types.pushBack(PROV_RSA_FULL);
61             if (capi_prov == "INTEL_SEC") m_prov_types.pushBack(PROV_INTEL_SEC);
62             if (capi_prov == "FORTEZZA")  m_prov_types.pushBack(PROV_FORTEZZA);
63             if (capi_prov == "RNG")       m_prov_types.pushBack(PROV_RNG);
64         }
65         
66         if (m_prov_types.length == 0)
67             m_prov_types.pushBack(PROV_RSA_FULL);
68     }
69 
70 private:
71     Vector!( ulong ) m_prov_types;
72     SecureVector!ubyte m_buf;
73 }
74 
75 final class CSPHandle
76 {
77 public:
78     this(ulong capi_provider)
79     {
80         DWORD prov_type = cast(DWORD)capi_provider;
81         
82         if (CryptAcquireContext(&m_handle, null, null, prov_type, cast(DWORD) CRYPT_VERIFYCONTEXT))
83             m_valid = true;
84     }
85     
86     ~this()
87     {
88         if (isValid())
89             CryptReleaseContext(m_handle, 0);
90     }
91     
92     size_t genRandom(ubyte* output, size_t length) const
93     {
94         if (isValid() && CryptGenRandom(m_handle, cast(DWORD) length, output))
95             return length;
96         return 0;
97     }
98     
99     bool isValid() const { return m_valid; }
100     
101     HCRYPTPROV getHandle() const { return m_handle; }
102 private:
103     HCRYPTPROV m_handle;
104     bool m_valid;
105 }
106 
107 private:
108 
109 alias ULONG = uint;
110 alias DWORD = ULONG;
111 alias HCRYPTPROV = ULONG;
112 alias PBYTE = ubyte*;
113 enum {
114     PROV_RSA_FULL = 1,
115     PROV_FORTEZZA = 4,
116     PROV_RNG = 21,
117     PROV_INTEL_SEC = 22
118 }
119 alias BOOL = int;
120 alias LPCSTR = const(char)*;
121 alias LPCWSTR = const(wchar)*;
122 enum {
123     CRYPT_VERIFYCONTEXT = 0xF0000000,
124 }
125 
126 extern (Windows) {
127     BOOL CryptReleaseContext(HCRYPTPROV, DWORD);
128     BOOL CryptGenRandom(HCRYPTPROV, DWORD, PBYTE);
129     
130     version(Unicode) { 
131         BOOL CryptAcquireContextW(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD);
132         alias CryptAcquireContext = CryptAcquireContextW;
133     }
134     else {
135         BOOL CryptAcquireContextA(HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD);
136         alias CryptAcquireContext = CryptAcquireContextA;
137     }
138 }