405570c1ce1537864dc0bd64655352fd7f792399
[aaf/sshsm.git] / SoftHSMv2 / src / lib / crypto / BotanCryptoFactory.cpp
1 /*
2  * Copyright (c) 2010 SURFnet bv
3  * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /*****************************************************************************
29  BotanCryptoFactory.cpp
30
31  This is a Botan based cryptographic algorithm factory
32  *****************************************************************************/
33 #include "config.h"
34 #include "BotanCryptoFactory.h"
35 #include "BotanAES.h"
36 #include "BotanDES.h"
37 #include "BotanDSA.h"
38 #include "BotanDH.h"
39 #ifdef WITH_ECC
40 #include "BotanECDH.h"
41 #include "BotanECDSA.h"
42 #endif
43 #include "BotanMD5.h"
44 #include "BotanRNG.h"
45 #include "BotanRSA.h"
46 #include "BotanSHA1.h"
47 #include "BotanSHA224.h"
48 #include "BotanSHA256.h"
49 #include "BotanSHA384.h"
50 #include "BotanSHA512.h"
51 #ifdef WITH_GOST
52 #include "BotanGOST.h"
53 #include "BotanGOSTR3411.h"
54 #endif
55 #include "BotanMAC.h"
56 #ifdef WITH_EDDSA
57 #include "BotanEDDSA.h"
58 #endif
59
60 #include <botan/init.h>
61
62 #if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
63 #include <botan/libstate.h>
64 #endif
65
66 // Constructor
67 BotanCryptoFactory::BotanCryptoFactory()
68 {
69 #if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
70         wasInitialized = false;
71
72         // Check if Botan has already been initialized
73         if (Botan::Global_State_Management::global_state_exists())
74         {
75                 wasInitialized = true;
76         }
77
78         // Init the Botan crypto library
79         if (!wasInitialized)
80         {
81                 Botan::LibraryInitializer::initialize("thread_safe=true");
82         }
83 #else
84         Botan::LibraryInitializer::initialize("thread_safe=true");
85 #endif
86
87         // Create mutex
88         rngsMutex = MutexFactory::i()->getMutex();
89 }
90
91 // Destructor
92 BotanCryptoFactory::~BotanCryptoFactory()
93 {
94         // Delete the RNGs
95 #ifdef HAVE_PTHREAD_H
96         std::map<pthread_t,RNG*>::iterator it;
97         for (it=rngs.begin(); it != rngs.end(); it++)
98         {
99                 delete (BotanRNG*)it->second;
100         }
101 #elif _WIN32
102         std::map<DWORD,RNG*>::iterator it;
103         for (it=rngs.begin(); it != rngs.end(); it++)
104         {
105                 delete (BotanRNG*)it->second;
106         }
107 #endif
108
109         // Delete the mutex
110         MutexFactory::i()->recycleMutex(rngsMutex);
111
112         // Deinitialize the Botan crypto lib
113 #if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,14)
114         if (!wasInitialized)
115         {
116                 Botan::LibraryInitializer::deinitialize();
117         }
118 #else
119         Botan::LibraryInitializer::deinitialize();
120 #endif
121 }
122
123 // Return the one-and-only instance
124 BotanCryptoFactory* BotanCryptoFactory::i()
125 {
126         if (!instance.get())
127         {
128                 instance.reset(new BotanCryptoFactory());
129         }
130
131         return instance.get();
132 }
133
134 // This will destroy the one-and-only instance.
135 void BotanCryptoFactory::reset()
136 {
137         instance.reset();
138 }
139
140 // Create a concrete instance of a symmetric algorithm
141 SymmetricAlgorithm* BotanCryptoFactory::getSymmetricAlgorithm(SymAlgo::Type algorithm)
142 {
143         switch (algorithm)
144         {
145                 case SymAlgo::AES:
146                         return new BotanAES();
147                 case SymAlgo::DES:
148                 case SymAlgo::DES3:
149                         return new BotanDES();
150                 default:
151                         // No algorithm implementation is available
152                         ERROR_MSG("Unknown algorithm '%i'", algorithm);
153
154                         return NULL;
155         }
156
157         // No algorithm implementation is available
158         return NULL;
159 }
160
161 // Create a concrete instance of an asymmetric algorithm
162 AsymmetricAlgorithm* BotanCryptoFactory::getAsymmetricAlgorithm(AsymAlgo::Type algorithm)
163 {
164         switch (algorithm)
165         {
166                 case AsymAlgo::RSA:
167                         return new BotanRSA();
168                 case AsymAlgo::DSA:
169                         return new BotanDSA();
170                 case AsymAlgo::DH:
171                         return new BotanDH();
172 #ifdef WITH_ECC
173                 case AsymAlgo::ECDH:
174                         return new BotanECDH();
175                 case AsymAlgo::ECDSA:
176                         return new BotanECDSA();
177 #endif
178 #ifdef WITH_GOST
179                 case AsymAlgo::GOST:
180                         return new BotanGOST();
181 #endif
182 #ifdef WITH_EDDSA
183                 case AsymAlgo::EDDSA:
184                         return new BotanEDDSA();
185 #endif
186                 default:
187                         // No algorithm implementation is available
188                         ERROR_MSG("Unknown algorithm '%i'", algorithm);
189
190                         return NULL;
191         }
192
193         // No algorithm implementation is available
194         return NULL;
195 }
196
197 // Create a concrete instance of a hash algorithm
198 HashAlgorithm* BotanCryptoFactory::getHashAlgorithm(HashAlgo::Type algorithm)
199 {
200         switch (algorithm)
201         {
202                 case HashAlgo::MD5:
203                         return new BotanMD5();
204                 case HashAlgo::SHA1:
205                         return new BotanSHA1();
206                 case HashAlgo::SHA224:
207                         return new BotanSHA224();
208                 case HashAlgo::SHA256:
209                         return new BotanSHA256();
210                 case HashAlgo::SHA384:
211                         return new BotanSHA384();
212                 case HashAlgo::SHA512:
213                         return new BotanSHA512();
214 #ifdef WITH_GOST
215                 case HashAlgo::GOST:
216                         return new BotanGOSTR3411();
217 #endif
218                 default:
219                         // No algorithm implementation is available
220                         ERROR_MSG("Unknown algorithm '%i'", algorithm);
221
222                         return NULL;
223         }
224
225         // No algorithm implementation is available
226         return NULL;
227 }
228
229 // Create a concrete instance of a MAC algorithm
230 MacAlgorithm* BotanCryptoFactory::getMacAlgorithm(MacAlgo::Type algorithm)
231 {
232         switch (algorithm)
233         {
234                 case MacAlgo::HMAC_MD5:
235                         return new BotanHMACMD5();
236                 case MacAlgo::HMAC_SHA1:
237                         return new BotanHMACSHA1();
238                 case MacAlgo::HMAC_SHA224:
239                         return new BotanHMACSHA224();
240                 case MacAlgo::HMAC_SHA256:
241                         return new BotanHMACSHA256();
242                 case MacAlgo::HMAC_SHA384:
243                         return new BotanHMACSHA384();
244                 case MacAlgo::HMAC_SHA512:
245                         return new BotanHMACSHA512();
246 #ifdef WITH_GOST
247                 case MacAlgo::HMAC_GOST:
248                         return new BotanHMACGOSTR3411();
249 #endif
250                 case MacAlgo::CMAC_DES:
251                         return new BotanCMACDES();
252                 case MacAlgo::CMAC_AES:
253                         return new BotanCMACAES();
254                 default:
255                         // No algorithm implementation is available
256                         ERROR_MSG("Unknown algorithm '%i'", algorithm);
257
258                         return NULL;
259         }
260
261         // No algorithm implementation is available
262         return NULL;
263 }
264
265 // Get the global RNG (may be an unique RNG per thread)
266 RNG* BotanCryptoFactory::getRNG(RNGImpl::Type name /* = RNGImpl::Default */)
267 {
268         if (name == RNGImpl::Default)
269         {
270                 RNG *threadRNG = NULL;
271
272                 // Lock access to the map
273                 MutexLocker lock(rngsMutex);
274
275 #ifdef HAVE_PTHREAD_H
276                 // Get thread ID
277                 pthread_t threadID = pthread_self();
278
279                 // Find the RNG
280                 std::map<pthread_t,RNG*>::iterator findIt;
281                 findIt=rngs.find(threadID);
282                 if (findIt != rngs.end())
283                 {
284                         return findIt->second;
285                 }
286
287                 threadRNG = new BotanRNG();
288                 rngs[threadID] = threadRNG;
289 #elif _WIN32
290                 // Get thread ID
291                 DWORD threadID = GetCurrentThreadId();
292
293                 // Find the RNG
294                 std::map<DWORD,RNG*>::iterator findIt;
295                 findIt=rngs.find(threadID);
296                 if (findIt != rngs.end())
297                 {
298                         return findIt->second;
299                 }
300
301                 threadRNG = new BotanRNG();
302                 rngs[threadID] = threadRNG;
303 #else
304 #error "There are no thread-specific data implementations for your operating system yet"
305 #endif
306                 return threadRNG;
307         }
308         else
309         {
310                 // No RNG implementation is available
311                 ERROR_MSG("Unknown RNG '%i'", name);
312
313                 return NULL;
314         }
315 }