sync with tizen_2.0
[platform/framework/native/appfw.git] / src / security / FSec_GenerateParameters.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FSec_GenerateParameters.cpp
20  * @brief       This file contains implementation of Generating Key Exchange Parameters p and g using ANSFS X9.31 Standard.
21  */
22 #include <stdlib.h>
23 #include <openssl/crypto.h>
24 #include <openssl/evp.h>
25 #include <openssl/bn.h>
26 #include <openssl/sha.h>
27 #include <openssl/dh.h>
28 #include <unique_ptr.h>
29 #include <FBaseResult.h>
30 #include <FBaseSysLog.h>
31 #include "FSec_GenerateParameters.h"
32 #include "FSec_Prng.h"
33
34 using namespace Tizen::Base;
35
36
37 namespace Tizen { namespace Security
38 {
39
40 static const int _MAX_FACTOR_PRIVATE_KEY = 4;
41 static const int _BITS_IN_BYTE = 8;
42 static const int _SHA_DIGEST_LENGTH = 32;
43 static const int _MAX_SHA_DIGEST_LENGTH = 64;
44 static const int _MAX_NUMBER_OF_CHECKS = 64;
45 static const int _PRIVATE_KEY_LENGTH_PAIR_1 = 160;
46 static const int _PRIVATE_KEY_LENGTH_PAIR_2 = 224;
47 static const int _PRIVATE_KEY_LENGTH_PAIR_3 = 256;
48 static const int _PUBLIC_KEY_LENGTH_PAIR_1 = 1024;
49 static const int _PUBLIC_KEY_LENGTH_PAIR_2 = 2048;
50 static const int _PUBLIC_KEY_LENGTH_PAIR_3 = 3072;
51
52 result
53 _GenerateParameters::GenerateParametersX186(void* pDh, long primeNumberLength, long generatorLength, long seedLengthInBytes)
54 {
55         result r = E_SUCCESS;
56         int ret = 0;
57         long tempVal = 0;
58         unsigned long count = 0;
59         unsigned long counter = 0;
60         unsigned long offset = 0;
61         unsigned long seedLengthInBits = 0;
62         unsigned long hashSize = SHA_DIGEST_LENGTH;
63         unsigned long outlen = 0;
64         unsigned long index = 0;
65         unsigned long power = 0;
66         byte val1[_MAX_SHA_DIGEST_LENGTH] = {0, };
67         std::unique_ptr <byte[]> pSeedBuffer;
68         const EVP_CIPHER* pAlgorithm = null;
69         BN_CTX* pCtx = null;
70         BIGNUM* pBn = null;
71         BIGNUM* pBnTemp = null;
72         BIGNUM* pValueBn = null;
73         BIGNUM* pSeedBn = null;
74         BIGNUM* pU = null;
75         BIGNUM* pTwoPower = null;
76         BIGNUM* pV = null;
77         BIGNUM* pTemp = null;
78         BIGNUM* pjBn = null;
79         BIGNUM* pBnTemp1 = null;
80         BIGNUM* pW = null;
81         BIGNUM* pX = null;
82         byte*  (*shaSelected)(const byte* pData, size_t dataLen, byte* pOutBuf) = SHA1;
83
84         pCtx = BN_CTX_new();
85         SysTryReturn(NID_SEC, pCtx != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
86
87         BN_CTX_init(pCtx);
88
89         //STEP 1. Check that the (primeNumberLength, generatorLength) pair is in the list of acceptable (primeNumberLength, generatorLength pairs) (see Section 4.2). If
90         //the pair is not in the list, then return INVALID.
91         if (!(((primeNumberLength == _PUBLIC_KEY_LENGTH_PAIR_1) && (generatorLength == _PRIVATE_KEY_LENGTH_PAIR_1)) || ((primeNumberLength == _PUBLIC_KEY_LENGTH_PAIR_2) && (generatorLength == _PRIVATE_KEY_LENGTH_PAIR_2)) || ((primeNumberLength == _PUBLIC_KEY_LENGTH_PAIR_2) && (generatorLength == _PRIVATE_KEY_LENGTH_PAIR_3)) || ((primeNumberLength == _PUBLIC_KEY_LENGTH_PAIR_3) && (generatorLength == _PRIVATE_KEY_LENGTH_PAIR_3))))
92         {
93                 BN_CTX_free(pCtx);
94                 return E_INVALID_ARG;
95         }
96
97         //STEP 2. If (seedlen < generatorLength), then return INVALID.
98         tempVal = generatorLength / _BITS_IN_BYTE;
99         SysTryCatch(NID_SEC, pDh != null && seedLengthInBytes >= tempVal, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Input data should be valid.");
100
101         if (generatorLength > _PRIVATE_KEY_LENGTH_PAIR_1)
102         {
103                 shaSelected = SHA256;
104                 hashSize = _SHA_DIGEST_LENGTH;
105
106         }
107
108         outlen = hashSize * _BITS_IN_BYTE;
109
110         //STEP 3. index = primeNumberLength / outlen ?1.
111         index = (primeNumberLength / outlen) - 1;
112         if (primeNumberLength % outlen)
113         {
114                 index++;
115         }
116
117         //STEP 4. power = primeNumberLength ?1 ?(index * outlen).
118         power = primeNumberLength - 1 - (index * outlen);
119
120         pBn = BN_new();
121         SysTryCatch(NID_SEC, pBn != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
122
123         pBnTemp = BN_new();
124         SysTryCatch(NID_SEC, pBnTemp != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
125
126         pSeedBuffer = std::unique_ptr <byte[]> (new (std::nothrow) byte[seedLengthInBytes]);
127         SysTryCatch(NID_SEC, pSeedBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Allocating new byte array failed.");
128
129         BN_CTX_start(pCtx);
130
131         pValueBn = BN_CTX_get(pCtx);
132         SysTryCatch(NID_SEC, pValueBn != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
133
134         pSeedBn = BN_CTX_get(pCtx);
135         SysTryCatch(NID_SEC, pSeedBn != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
136
137         pU = BN_CTX_get(pCtx);
138         SysTryCatch(NID_SEC, pU != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
139
140         pTwoPower = BN_CTX_get(pCtx);
141         SysTryCatch(NID_SEC, pTwoPower != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
142
143         pTemp = BN_CTX_get(pCtx);
144         SysTryCatch(NID_SEC, pTemp != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
145
146         do
147         {
148                 //STEP 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
149                 //if (GetRandomBytes(SEC_BCIPHER_AES_ECB_128 , seedBuffer, seedLengthInBytes) == FALSE)
150
151                 pAlgorithm = EVP_aes_128_ecb();
152
153                 std::unique_ptr <ByteBuffer> pBuffer (_Prng::GetRandomBytesN(pAlgorithm, seedLengthInBytes));
154                 SysTryCatch(NID_SEC, pBuffer != null, , GetLastResult(), "[%s] Allocating new ByteBuffer failed.", GetErrorMessage(GetLastResult()));
155
156                 memcpy(pSeedBuffer.get(), pBuffer->GetPointer(), pBuffer->GetRemaining());
157
158                 BN_bin2bn(pSeedBuffer.get(), seedLengthInBytes, pSeedBn);
159                 SysTryCatch(NID_SEC, pSeedBn != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
160
161                 //STEP 5. Set U = 0
162                 ret = BN_zero(pU);
163                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
164
165                 //STEP 6. U = Hash (domain_parameter_seed) mod 2^generatorLength?.
166
167                 //Hash (domain_parameter_seed)
168                 shaSelected(pSeedBuffer.get(), seedLengthInBytes, val1);
169
170                 BN_bin2bn(val1, hashSize, pTemp);
171                 SysTryCatch(NID_SEC, pTemp != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
172
173                 //2^generatorLength?.
174                 ret = BN_lshift(pTwoPower, BN_value_one(), generatorLength - 1);
175                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
176
177                 //U = Hash mod 2^generatorLength?.
178                 ret = BN_mod(pU, pTemp, pTwoPower, pCtx);
179                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
180
181                 //generate q
182                 //STEP 7. q = 2^generatorLength? + U + 1 ?( U mod 2).
183                 //( U mod 2).
184                 if (BN_is_bit_set(pU, 0))
185                 {
186                         //q = 2^generatorLength? + U + 1 - 1
187                         ret = BN_add(pBnTemp, pTwoPower, pU);
188                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
189                 }
190                 else
191                 {
192                         //q = 2^generatorLength? + U + 1
193                         ret = BN_add(pTemp, pU, BN_value_one());
194                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
195
196                         ret = BN_add(pBnTemp, pTwoPower, pTemp);
197                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
198                 }
199
200                 //STEP 8.Test whether or not q is prime as specified in Appendix C.3.
201                 //STEP 9. If q is not prime then go to 4
202         }
203         while (BN_is_prime_fasttest_ex(pBnTemp, _MAX_NUMBER_OF_CHECKS, pCtx, 1, null) <= 0);
204
205         //generate p
206         //STEP 10: offset = 1
207         offset = 1;
208         pW = BN_CTX_get(pCtx);
209         SysTryCatch(NID_SEC, pW != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
210
211         pV = BN_CTX_get(pCtx);
212         SysTryCatch(NID_SEC, pV != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
213
214         pX = BN_CTX_get(pCtx);
215         SysTryCatch(NID_SEC, pX != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
216
217         seedLengthInBits = BN_num_bits(pSeedBn);
218
219         //STEP 11. For counter = 0 to (4L ?1) do
220         for (counter = 0; counter < ((_MAX_FACTOR_PRIVATE_KEY * primeNumberLength) - 1); counter++)
221         {
222                 ret = BN_zero(pW);
223                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
224
225                 //STEP 11.1 For count = 0 to index do
226                 //Vj = Hash ((domain_parameter_seed + offset + count) mod 2^seedlen)).
227                 for (count = 0; count <= index; count++)
228                 {
229                         ret = BN_set_word(pValueBn, offset + count);
230                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
231
232                         ret = BN_add(pTemp, pSeedBn, pValueBn);
233                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
234
235                         //2^seedLen.
236                         ret = BN_lshift(pTwoPower, BN_value_one(), seedLengthInBits);
237                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
238
239                         //U = Hash mod 2^seedLen.
240                         ret = BN_mod(pValueBn, pTemp, pTwoPower, pCtx);
241                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
242
243                         ret = BN_bn2bin(pValueBn, pSeedBuffer.get());
244                         SysTryCatch(NID_SEC, pSeedBuffer != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
245
246                         shaSelected(pSeedBuffer.get(), seedLengthInBytes, val1);
247
248                         BN_bin2bn(val1, hashSize, pV);
249                         SysTryCatch(NID_SEC, pV != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
250
251                         if (count == index)
252                         {
253                                 //2^power.
254                                 ret = BN_lshift(pTwoPower, BN_value_one(), power);
255                                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
256
257                                 //Vn mod 2^power
258                                 ret = BN_mod(pTemp, pV, pTwoPower, pCtx);
259                                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
260
261                                 BN_copy(pV, pTemp);
262                                 SysTryCatch(NID_SEC, pTemp != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
263                         }
264
265                         //STEP 11.2 W = V0 + (V1 * 2^outlen) + ?+ (Vn? * 2^(index?) * outlen) + ((Vn mod 2b) * 2^(index * outlen)).
266                         //BN_lshift(pTwoPower, BN_value_one(), (count * outlen));
267                         //BN_mul(pTemp, pV, pTwoPower);
268
269                         ret = BN_lshift(pTemp, pV, (count * outlen));
270                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
271
272                         ret = BN_add(pW, pW, pTemp);
273                         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
274                 }
275
276                 //11.3 X = W + 2^primeNumberLength?. Comment: 0 = W < 2L?; hence, 2L? = X < 2L.
277                 //=> 2^(primeNumberLength-1)
278                 ret = BN_lshift(pTwoPower, BN_value_one(), (primeNumberLength - 1));
279                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
280
281                 //X = W + 2^(primeNumberLength-1)
282                 ret = BN_add(pX, pW, pTwoPower);
283                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
284
285                 //STEP 11.4 c = X mod 2q.
286                 //(2*q)
287                 ret = BN_lshift(pTemp, pBnTemp, 1);
288                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
289
290                 //(X mod (2*q))
291                 ret = BN_mod(pValueBn, pX, pTemp, pCtx);
292                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
293
294                 //(c - 1)
295                 ret = BN_sub(pTemp, pValueBn, BN_value_one());
296                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
297
298                 //STEP 11.5 p = X ?(c ?1). Comment: p = 1 (mod 2q).
299                 ret = BN_sub(pBn, pX, pTemp);
300                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
301
302                 if ((BN_num_bits(pBn) > (primeNumberLength - 1)) && BN_is_prime_fasttest_ex(pBn, _MAX_NUMBER_OF_CHECKS, pCtx, 1, null) > 0)
303                 {
304                         break;
305                 }
306
307                 offset += index + 1;
308         }
309
310         tempVal = (_MAX_FACTOR_PRIVATE_KEY * primeNumberLength) - 1;
311         SysTryCatch(NID_SEC, counter < static_cast< unsigned long >(tempVal), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed in evaluating proper values.");
312
313         //generate g
314         pjBn = BN_CTX_get(pCtx);
315         SysTryCatch(NID_SEC, pjBn != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
316
317         //STEP 1. Let count = (p - 1)/q.
318         ret = BN_sub(pTemp, pBn, BN_value_one());
319         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
320
321         ret = BN_div(pjBn, null, pTemp, pBnTemp, pCtx);
322         SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
323
324         pBnTemp1 = BN_new();
325         SysTryCatch(NID_SEC, pBnTemp1 != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
326
327         seedLengthInBytes = (BN_num_bits(pBn) - 1) / _BITS_IN_BYTE;
328
329         pSeedBuffer = std::unique_ptr <byte[]> (new (std::nothrow) byte[seedLengthInBytes]);
330         SysTryCatch(NID_SEC, pSeedBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Allocating new byte array failed.");
331
332         do
333         {
334                 //STEP 2. Set h = any integer, where 1 < h < p - 1 and h differs
335                 //from any value previously tried.
336                 //if (GetRandomBytes(SEC_BCIPHER_AES_ECB_128 , seedBuffer, seedLengthInBytes) == FALSE) // -1 to ensure h is smaller then p
337
338                 pAlgorithm = EVP_aes_128_ecb();
339
340                 std::unique_ptr <ByteBuffer> pBuffer (_Prng::GetRandomBytesN(pAlgorithm, seedLengthInBytes));
341                 SysTryCatch(NID_SEC, pBuffer != null, , GetLastResult(), "[%s] Allocating new ByteBuffer failed.", GetErrorMessage(GetLastResult()));
342
343                 memcpy(pSeedBuffer.get(), pBuffer->GetPointer(), pBuffer->GetRemaining());
344
345                 BN_bin2bn(pSeedBuffer.get(), seedLengthInBytes, pSeedBn);  //pSeedBn <=> h
346                 SysTryCatch(NID_SEC, pSeedBn != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
347
348                 //3. Set g = h^count mod p
349                 ret = BN_mod_exp(pBnTemp1, pSeedBn, pjBn, pBn, pCtx);
350                 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
351
352                 //4. If g == 1 go to step 2
353         }
354         while (BN_is_one(pBnTemp1));
355
356         (static_cast< DH* >(pDh))->g = pBnTemp1;
357         (static_cast< DH* >(pDh))->p = pBn;
358         (static_cast< DH* >(pDh))->length = BN_num_bytes(pBnTemp);
359
360 CATCH:
361         if (IsFailed(r) && pBnTemp1 != null)
362         {
363                 BN_free(pBnTemp1);
364         }
365
366         if (IsFailed(r) && pBn != null)
367         {
368                 BN_free(pBn);
369         }
370
371         if (pBnTemp != null)
372         {
373                 BN_free(pBnTemp);
374         }
375
376         if (pCtx != null)
377         {
378                 BN_CTX_end(pCtx);
379                 BN_CTX_free(pCtx);
380         }
381
382         return r;
383 }
384
385 } } // Tizen::Security