• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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