1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_CRYPTO_BN_RAND
18
19 #include <stdint.h>
20 #include "securec.h"
21 #include "bsl_err_internal.h"
22 #include "bsl_sal.h"
23 #include "crypt_errno.h"
24 #include "bn_basic.h"
25 #include "bn_bincal.h"
26 #include "crypt_util_rand.h"
27
RandGenerate(void * libCtx,BN_BigNum * r,uint32_t bits)28 static int32_t RandGenerate(void *libCtx, BN_BigNum *r, uint32_t bits)
29 {
30 int32_t ret;
31 uint32_t room = BITS_TO_BN_UNIT(bits);
32 BN_UINT mask;
33 // Maxbits = (1 << 29) --> MaxBytes = (1 << 26), hence BN_BITS_TO_BYTES(bits) will not exceed the upper limit.
34 uint32_t byteSize = BN_BITS_TO_BYTES(bits);
35 uint8_t *buf = BSL_SAL_Malloc(byteSize);
36 if (buf == NULL) {
37 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
38 return CRYPT_MEM_ALLOC_FAIL;
39 }
40 ret = CRYPT_RandEx(libCtx, buf, byteSize);
41 if (ret == CRYPT_NO_REGIST_RAND) {
42 BSL_ERR_PUSH_ERROR(ret);
43 goto ERR;
44 }
45 if (ret != CRYPT_SUCCESS) {
46 BSL_ERR_PUSH_ERROR(CRYPT_BN_RAND_GEN_FAIL);
47 ret = CRYPT_BN_RAND_GEN_FAIL;
48 goto ERR;
49 }
50 ret = BN_Bin2Bn(r, buf, byteSize);
51 BSL_SAL_CleanseData(buf, byteSize);
52 if (ret != CRYPT_SUCCESS) {
53 BSL_ERR_PUSH_ERROR(ret);
54 goto ERR;
55 }
56 mask = (BN_UINT)(-1) >> ((BN_UINT_BITS - bits % BN_UINT_BITS) % BN_UINT_BITS);
57 r->data[room - 1] &= mask;
58 r->size = BinFixSize(r->data, room);
59 ERR:
60 BSL_SAL_FREE(buf);
61 return ret;
62 }
63
CheckTopAndBottom(uint32_t bits,uint32_t top,uint32_t bottom)64 static int32_t CheckTopAndBottom(uint32_t bits, uint32_t top, uint32_t bottom)
65 {
66 if (top > BN_RAND_TOP_TWOBIT) {
67 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_RAND_TOP_BOTTOM);
68 return CRYPT_BN_ERR_RAND_TOP_BOTTOM;
69 }
70 if (bottom > BN_RAND_BOTTOM_TWOBIT) {
71 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_RAND_TOP_BOTTOM);
72 return CRYPT_BN_ERR_RAND_TOP_BOTTOM;
73 }
74 if (top > bits || bottom > bits) {
75 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_RAND_BITS_NOT_ENOUGH);
76 return CRYPT_BN_ERR_RAND_BITS_NOT_ENOUGH;
77 }
78 return CRYPT_SUCCESS;
79 }
80
BN_Rand(BN_BigNum * r,uint32_t bits,uint32_t top,uint32_t bottom)81 int32_t BN_Rand(BN_BigNum *r, uint32_t bits, uint32_t top, uint32_t bottom)
82 {
83 return BN_RandEx(NULL, r, bits, top, bottom);
84 }
85
BN_RandEx(void * libCtx,BN_BigNum * r,uint32_t bits,uint32_t top,uint32_t bottom)86 int32_t BN_RandEx(void *libCtx, BN_BigNum *r, uint32_t bits, uint32_t top, uint32_t bottom)
87 {
88 if (r == NULL) {
89 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
90 return CRYPT_NULL_INPUT;
91 }
92 int32_t ret = CheckTopAndBottom(bits, top, bottom);
93 if (ret != CRYPT_SUCCESS) {
94 BSL_ERR_PUSH_ERROR(ret);
95 return ret;
96 }
97
98 if (bits == 0) {
99 return BN_Zeroize(r);
100 }
101
102 if (bits > BN_MAX_BITS) {
103 BSL_ERR_PUSH_ERROR(CRYPT_BN_BITS_TOO_MAX);
104 return CRYPT_BN_BITS_TOO_MAX;
105 }
106 ret = BnExtend(r, BITS_TO_BN_UNIT(bits));
107 if (ret != CRYPT_SUCCESS) {
108 return ret;
109 }
110 ret = RandGenerate(libCtx, r, bits);
111 if (ret != CRYPT_SUCCESS) {
112 BSL_ERR_PUSH_ERROR(ret);
113 return ret;
114 }
115 r->data[0] |= (bottom == BN_RAND_BOTTOM_TWOBIT) ? 0x3 : (BN_UINT)bottom; // CheckTopAndBottom ensure that bottom>0
116 if (top == BN_RAND_TOP_ONEBIT) {
117 (void)BN_SetBit(r, bits - 1);
118 } else if (top == BN_RAND_TOP_TWOBIT) {
119 (void)BN_SetBit(r, bits - 1);
120 (void)BN_SetBit(r, bits - 2); /* the most significant 2 bits are 1 */
121 }
122 r->size = BinFixSize(r->data, r->room);
123 return ret;
124 }
125
InputCheck(BN_BigNum * r,const BN_BigNum * p)126 static int32_t InputCheck(BN_BigNum *r, const BN_BigNum *p)
127 {
128 if (r == NULL || p == NULL) {
129 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
130 return CRYPT_NULL_INPUT;
131 }
132
133 if (BN_IsZero(p)) {
134 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_RAND_ZERO);
135 return CRYPT_BN_ERR_RAND_ZERO;
136 }
137 if (p->sign == true) {
138 BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_RAND_NEGATIVE);
139 return CRYPT_BN_ERR_RAND_NEGATIVE;
140 }
141 return BnExtend(r, p->size);
142 }
143
BN_RandRange(BN_BigNum * r,const BN_BigNum * p)144 int32_t BN_RandRange(BN_BigNum *r, const BN_BigNum *p)
145 {
146 return BN_RandRangeEx(NULL, r, p);
147 }
148
BN_RandRangeEx(void * libCtx,BN_BigNum * r,const BN_BigNum * p)149 int32_t BN_RandRangeEx(void *libCtx, BN_BigNum *r, const BN_BigNum *p)
150 {
151 const int32_t maxCnt = 100; /* try 100 times */
152 int32_t tryCnt = 0;
153 int32_t ret;
154
155 ret = InputCheck(r, p);
156 if (ret != CRYPT_SUCCESS) {
157 BSL_ERR_PUSH_ERROR(ret);
158 return ret;
159 }
160 ret = BN_Zeroize(r);
161 if (ret != CRYPT_SUCCESS) {
162 return ret;
163 }
164 if (BN_IsOne(p)) {
165 return CRYPT_SUCCESS;
166 }
167 uint32_t bits = BN_Bits(p);
168 do {
169 tryCnt++;
170 if (tryCnt > maxCnt) {
171 /* The success rate is more than 50%. */
172 /* Return a failure if failed to generated after try 100 times */
173 BSL_ERR_PUSH_ERROR(CRYPT_BN_RAND_GEN_FAIL);
174 return CRYPT_BN_RAND_GEN_FAIL;
175 }
176 ret = RandGenerate(libCtx, r, bits);
177 if (ret != CRYPT_SUCCESS) {
178 BSL_ERR_PUSH_ERROR(ret);
179 return ret;
180 }
181 } while (BinCmp(r->data, r->size, p->data, p->size) >= 0);
182
183 return ret;
184 }
185 #endif /* HITLS_CRYPTO_BN_RAND */
186