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