2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file FSec_GenerateParameters.cpp
19 * @brief This file contains implementation of Generating Key Exchange Parameters p and g using ANSFS X9.31 Standard.
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"
33 using namespace Tizen::Base;
36 namespace Tizen { namespace Security
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;
52 _GenerateParameters::GenerateParametersX186(void* pDh, long primeNumberLength, long generatorLength, long seedLengthInBytes)
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;
70 BIGNUM* pBnTemp = null;
71 BIGNUM* pValueBn = null;
72 BIGNUM* pSeedBn = null;
74 BIGNUM* pTwoPower = null;
78 BIGNUM* pBnTemp1 = null;
81 byte* (*shaSelected)(const byte* pData, size_t dataLen, byte* pOutBuf) = SHA1;
84 SysTryReturn(NID_SEC, pCtx != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
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))))
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.");
100 if (generatorLength > _PRIVATE_KEY_LENGTH_PAIR_1)
102 shaSelected = SHA256;
103 hashSize = _SHA_DIGEST_LENGTH;
107 outlen = hashSize * _BITS_IN_BYTE;
109 //STEP 3. index = primeNumberLength / outlen ?1.
110 index = (primeNumberLength / outlen) - 1;
111 if (primeNumberLength % outlen)
116 //STEP 4. power = primeNumberLength ?1 ?(index * outlen).
117 power = primeNumberLength - 1 - (index * outlen);
120 SysTryCatch(NID_SEC, pBn != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
123 SysTryCatch(NID_SEC, pBnTemp != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
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.");
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.");
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.");
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.");
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.");
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.");
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)
150 pAlgorithm = EVP_aes_128_ecb();
152 std::unique_ptr <ByteBuffer> pBuffer (_Prng::GetRandomBytesN(pAlgorithm, seedLengthInBytes));
153 SysTryCatch(NID_SEC, pBuffer != null, , GetLastResult(), "[%s] Allocating new ByteBuffer failed.", GetErrorMessage(GetLastResult()));
155 memcpy(pSeedBuffer.get(), pBuffer->GetPointer(), pBuffer->GetRemaining());
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.");
162 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
164 //STEP 6. U = Hash (domain_parameter_seed) mod 2^generatorLength?.
166 //Hash (domain_parameter_seed)
167 shaSelected(pSeedBuffer.get(), seedLengthInBytes, val1);
169 BN_bin2bn(val1, hashSize, pTemp);
170 SysTryCatch(NID_SEC, pTemp != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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.");
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.");
181 //STEP 7. q = 2^generatorLength? + U + 1 ?( U mod 2).
183 if (BN_is_bit_set(pU, 0))
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.");
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.");
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.");
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
202 while (BN_is_prime_fasttest_ex(pBnTemp, _MAX_NUMBER_OF_CHECKS, pCtx, 1, null) <= 0);
205 //STEP 10: 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.");
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.");
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.");
216 seedLengthInBits = BN_num_bits(pSeedBn);
218 //STEP 11. For counter = 0 to (4L ?1) do
219 for (counter = 0; counter < ((_MAX_FACTOR_PRIVATE_KEY * primeNumberLength) - 1); counter++)
222 SysTryCatch(NID_SEC, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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++)
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.");
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.");
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.");
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.");
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.");
245 shaSelected(pSeedBuffer.get(), seedLengthInBytes, val1);
247 BN_bin2bn(val1, hashSize, pV);
248 SysTryCatch(NID_SEC, pV != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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.");
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.");
261 SysTryCatch(NID_SEC, pTemp != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
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);
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.");
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.");
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.");
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.");
284 //STEP 11.4 c = X mod 2q.
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.");
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.");
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.");
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.");
301 if ((BN_num_bits(pBn) > (primeNumberLength - 1)) && BN_is_prime_fasttest_ex(pBn, _MAX_NUMBER_OF_CHECKS, pCtx, 1, null) > 0)
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.");
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.");
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.");
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.");
324 SysTryCatch(NID_SEC, pBnTemp1 != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
326 seedLengthInBytes = (BN_num_bits(pBn) - 1) / _BITS_IN_BYTE;
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.");
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
337 pAlgorithm = EVP_aes_128_ecb();
339 std::unique_ptr <ByteBuffer> pBuffer (_Prng::GetRandomBytesN(pAlgorithm, seedLengthInBytes));
340 SysTryCatch(NID_SEC, pBuffer != null, , GetLastResult(), "[%s] Allocating new ByteBuffer failed.", GetErrorMessage(GetLastResult()));
342 memcpy(pSeedBuffer.get(), pBuffer->GetPointer(), pBuffer->GetRemaining());
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.");
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.");
351 //4. If g == 1 go to step 2
353 while (BN_is_one(pBnTemp1));
355 (static_cast< DH* >(pDh))->g = pBnTemp1;
356 (static_cast< DH* >(pDh))->p = pBn;
357 (static_cast< DH* >(pDh))->length = BN_num_bytes(pBnTemp);
360 if (IsFailed(r) && pBnTemp1 != null)
365 if (IsFailed(r) && pBn != null)
384 } } // Tizen::Security