1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2010-2020. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #include "bn.h"
22
23
get_bn_from_mpint(ErlNifEnv * env,ERL_NIF_TERM term,BIGNUM ** bnp)24 int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
25 {
26 BIGNUM *ret;
27 ErlNifBinary bin;
28 int sz;
29
30 if (!enif_inspect_binary(env, term, &bin))
31 goto err;
32 if (bin.size > INT_MAX - 4)
33 goto err;
34
35 if (bin.size < 4)
36 goto err;
37 sz = (int)bin.size - 4;
38 if (get_int32(bin.data) != sz)
39 goto err;
40
41 if ((ret = BN_bin2bn(bin.data+4, sz, NULL)) == NULL)
42 goto err;
43
44 *bnp = ret;
45 return 1;
46
47 err:
48 return 0;
49 }
50
get_bn_from_bin(ErlNifEnv * env,ERL_NIF_TERM term,BIGNUM ** bnp)51 int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
52 {
53 return get_bn_from_bin_sz(env, term, bnp, NULL);
54 }
55
get_bn_from_bin_sz(ErlNifEnv * env,ERL_NIF_TERM term,BIGNUM ** bnp,size_t * binsize)56 int get_bn_from_bin_sz(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp, size_t* binsize)
57 {
58 BIGNUM *ret;
59 ErlNifBinary bin;
60
61 if (!enif_inspect_binary(env, term, &bin))
62 goto err;
63 if (bin.size > INT_MAX)
64 goto err;
65
66 if ((ret = BN_bin2bn(bin.data, (int)bin.size, NULL)) == NULL)
67 goto err;
68
69 if (binsize != NULL)
70 *binsize = bin.size;
71 *bnp = ret;
72 return 1;
73
74 err:
75 return 0;
76 }
77
bin_from_bn(ErlNifEnv * env,const BIGNUM * bn)78 ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn)
79 {
80 int bn_len;
81 unsigned char *bin_ptr;
82 ERL_NIF_TERM term;
83
84 /* Copy the bignum into an erlang binary. */
85 if ((bn_len = BN_num_bytes(bn)) < 0)
86 goto err;
87 if ((bin_ptr = enif_make_new_binary(env, (size_t)bn_len, &term)) == NULL)
88 goto err;
89
90 if (BN_bn2bin(bn, bin_ptr) < 0)
91 goto err;
92
93 return term;
94
95 err:
96 return atom_error;
97 }
98
mod_exp_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])99 ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
100 {/* (Base,Exponent,Modulo,bin_hdr) */
101 BIGNUM *bn_base = NULL, *bn_exponent = NULL, *bn_modulo = NULL, *bn_result = NULL;
102 BN_CTX *bn_ctx = NULL;
103 unsigned char* ptr;
104 int dlen;
105 unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
106 unsigned extra_byte;
107 ERL_NIF_TERM ret;
108
109 if (!get_bn_from_bin(env, argv[0], &bn_base))
110 goto bad_arg;
111 if (!get_bn_from_bin(env, argv[1], &bn_exponent))
112 goto bad_arg;
113 if (!get_bn_from_bin(env, argv[2], &bn_modulo))
114 goto bad_arg;
115 if (!enif_get_uint(env, argv[3], &bin_hdr))
116 goto bad_arg;
117 if (bin_hdr != 0 && bin_hdr != 4)
118 goto bad_arg;
119
120 if ((bn_result = BN_new()) == NULL)
121 goto err;
122 if ((bn_ctx = BN_CTX_new()) == NULL)
123 goto err;
124
125 if (!BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx))
126 goto err;
127
128 dlen = BN_num_bytes(bn_result);
129 if (dlen < 0 || dlen > INT_MAX / 8)
130 goto bad_arg;
131 extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen * 8 - 1);
132
133 if ((ptr = enif_make_new_binary(env, bin_hdr + extra_byte + (unsigned int)dlen, &ret)) == NULL)
134 goto err;
135
136 if (bin_hdr) {
137 put_uint32(ptr, extra_byte + (unsigned int)dlen);
138 ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
139 ptr += bin_hdr + extra_byte;
140 }
141
142 BN_bn2bin(bn_result, ptr);
143 goto done;
144
145 bad_arg:
146 err:
147 ret = enif_make_badarg(env);
148
149 done:
150 if (bn_base)
151 BN_free(bn_base);
152 if (bn_exponent)
153 BN_free(bn_exponent);
154 if (bn_modulo)
155 BN_free(bn_modulo);
156 if (bn_result)
157 BN_free(bn_result);
158 if (bn_ctx)
159 BN_CTX_free(bn_ctx);
160 return ret;
161 }
162
163 #ifdef HAVE_EC
bn2term(ErlNifEnv * env,size_t size,const BIGNUM * bn)164 ERL_NIF_TERM bn2term(ErlNifEnv* env, size_t size, const BIGNUM *bn)
165 {
166 int dlen;
167 unsigned char* ptr;
168 ERL_NIF_TERM ret;
169
170 if (bn == NULL)
171 return atom_undefined;
172
173 dlen = BN_num_bytes(bn);
174 if (dlen < 0)
175 goto err;
176 if (dlen > (int)size)
177 goto err;
178 if ((ptr = enif_make_new_binary(env, size, &ret)) == NULL)
179 goto err;
180
181 #ifdef HAS_BN_bn2binpad
182 BN_bn2binpad(bn, ptr, (int) size);
183 #else
184 /* First, maybe pad with zeroes */
185 memset(ptr, 0, (size-dlen) );
186 BN_bn2bin(bn, ptr + (size-dlen));
187 #endif
188
189 return ret;
190
191 err:
192 return enif_make_badarg(env);
193 }
194 #endif
195