2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @file FSec_GenerateParameters.cpp
20 * @brief This file contains implementation of Generating Key Exchange Parameters p and g using ANSFS X9.31 Standard.
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"
34 using namespace Tizen::Base;
37 namespace Tizen { namespace Security
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;
53 _GenerateParameters::GenerateParametersX186(void* pDh, long primeNumberLength, long generatorLength, long seedLengthInBytes)
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;
71 BIGNUM* pBnTemp = null;
72 BIGNUM* pValueBn = null;
73 BIGNUM* pSeedBn = null;
75 BIGNUM* pTwoPower = null;
79 BIGNUM* pBnTemp1 = null;
82 byte* (*shaSelected)(const byte* pData, size_t dataLen, byte* pOutBuf) = SHA1;
85 SysTryReturn(NID_SEC, pCtx != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
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))))
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.");
101 if (generatorLength > _PRIVATE_KEY_LENGTH_PAIR_1)
103 shaSelected = SHA256;
104 hashSize = _SHA_DIGEST_LENGTH;
108 outlen = hashSize * _BITS_IN_BYTE;
110 //STEP 3. index = primeNumberLength / outlen ?1.
111 index = (primeNumberLength / outlen) - 1;
112 if (primeNumberLength % outlen)
117 //STEP 4. power = primeNumberLength ?1 ?(index * outlen).
118 power = primeNumberLength - 1 - (index * outlen);
121 SysTryCatch(NID_SEC, pBn != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
124 SysTryCatch(NID_SEC, pBnTemp != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
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.");
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.");
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.");
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.");
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.");
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.");
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)
151 pAlgorithm = EVP_aes_128_ecb();
153 std::unique_ptr <ByteBuffer> pBuffer (_Prng::GetRandomBytesN(pAlgorithm, seedLengthInBytes));
154 SysTryCatch(NID_SEC, pBuffer != null, , GetLastResult(), "[%s] Allocating new ByteBuffer failed.", GetErrorMessage(GetLastResult()));
156 memcpy(pSeedBuffer.get(), pBuffer->GetPointer(), pBuffer->GetRemaining());
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.");
163 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
165 //STEP 6. U = Hash (domain_parameter_seed) mod 2^generatorLength?.
167 //Hash (domain_parameter_seed)
168 shaSelected(pSeedBuffer.get(), seedLengthInBytes, val1);
170 BN_bin2bn(val1, hashSize, pTemp);
171 SysTryCatch(NID_SEC, pTemp != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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.");
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.");
182 //STEP 7. q = 2^generatorLength? + U + 1 ?( U mod 2).
184 if (BN_is_bit_set(pU, 0))
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.");
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.");
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.");
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
203 while (BN_is_prime_fasttest_ex(pBnTemp, _MAX_NUMBER_OF_CHECKS, pCtx, 1, null) <= 0);
206 //STEP 10: 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.");
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.");
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.");
217 seedLengthInBits = BN_num_bits(pSeedBn);
219 //STEP 11. For counter = 0 to (4L ?1) do
220 for (counter = 0; counter < ((_MAX_FACTOR_PRIVATE_KEY * primeNumberLength) - 1); counter++)
223 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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++)
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.");
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.");
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.");
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.");
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.");
246 shaSelected(pSeedBuffer.get(), seedLengthInBytes, val1);
248 BN_bin2bn(val1, hashSize, pV);
249 SysTryCatch(NID_SEC, pV != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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.");
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.");
262 SysTryCatch(NID_SEC, pTemp != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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);
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.");
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.");
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.");
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.");
285 //STEP 11.4 c = X mod 2q.
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.");
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.");
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.");
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.");
302 if ((BN_num_bits(pBn) > (primeNumberLength - 1)) && BN_is_prime_fasttest_ex(pBn, _MAX_NUMBER_OF_CHECKS, pCtx, 1, null) > 0)
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.");
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.");
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.");
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.");
325 SysTryCatch(NID_SEC, pBnTemp1 != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
327 seedLengthInBytes = (BN_num_bits(pBn) - 1) / _BITS_IN_BYTE;
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.");
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
338 pAlgorithm = EVP_aes_128_ecb();
340 std::unique_ptr <ByteBuffer> pBuffer (_Prng::GetRandomBytesN(pAlgorithm, seedLengthInBytes));
341 SysTryCatch(NID_SEC, pBuffer != null, , GetLastResult(), "[%s] Allocating new ByteBuffer failed.", GetErrorMessage(GetLastResult()));
343 memcpy(pSeedBuffer.get(), pBuffer->GetPointer(), pBuffer->GetRemaining());
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.");
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.");
352 //4. If g == 1 go to step 2
354 while (BN_is_one(pBnTemp1));
356 (static_cast< DH* >(pDh))->g = pBnTemp1;
357 (static_cast< DH* >(pDh))->p = pBn;
358 (static_cast< DH* >(pDh))->length = BN_num_bytes(pBnTemp);
361 if (IsFailed(r) && pBnTemp1 != null)
366 if (IsFailed(r) && pBn != null)
385 } } // Tizen::Security