xref: /trunk/ns_server/deps/enacl/c_src/sign.c (revision e35c584a)
1 #include <sodium.h>
2 
3 #include <erl_nif.h>
4 
5 #include "enacl.h"
6 #include "sign.h"
7 
8 typedef struct enacl_sign_ctx {
9   ErlNifMutex *mtx;
10   crypto_sign_state *state; // The underlying signature state
11   int alive; // Is the context still valid for updates/finalization
12 } enacl_sign_ctx;
13 
14 ErlNifResourceType *enacl_sign_ctx_rtype = NULL;
15 
16 void enacl_sign_ctx_dtor(ErlNifEnv *env, enacl_sign_ctx *);
17 
enacl_init_sign_ctx(ErlNifEnv * env)18 int enacl_init_sign_ctx(ErlNifEnv *env) {
19   enacl_sign_ctx_rtype =
20       enif_open_resource_type(env, NULL, "enacl_sign_context",
21                               (ErlNifResourceDtor *)enacl_sign_ctx_dtor,
22                               ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
23 
24   if (enacl_sign_ctx_rtype == NULL)
25     return 0;
26 
27   return 1;
28 }
29 
enacl_sign_ctx_dtor(ErlNifEnv * env,enacl_sign_ctx * obj)30 void enacl_sign_ctx_dtor(ErlNifEnv *env, enacl_sign_ctx *obj) {
31   if (!obj->alive)
32     return;
33 
34   if (obj->state) {
35     sodium_memzero(obj->state, crypto_sign_statebytes());
36     enif_free(obj->state);
37   }
38 
39   if (obj->mtx != NULL)
40     enif_mutex_destroy(obj->mtx);
41 
42   return;
43 }
44 
45 /*
46   int crypto_sign_init(crypto_sign_state *state)
47  */
48 
enacl_crypto_sign_init(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])49 ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc,
50                                     ERL_NIF_TERM const argv[]) {
51   ERL_NIF_TERM ret;
52   enacl_sign_ctx *obj = NULL;
53 
54   if (argc != 0)
55     goto bad_arg;
56 
57   if ((obj = enif_alloc_resource(enacl_sign_ctx_rtype,
58                                  sizeof(enacl_sign_ctx))) == NULL) {
59     ret = enacl_internal_error(env);
60     goto done;
61   }
62   obj->alive = 0;
63   obj->state = enif_alloc(crypto_sign_statebytes());
64   if (obj->state == NULL) {
65     goto release;
66   }
67   obj->alive = 1;
68 
69   if ((obj->mtx = enif_mutex_create("enacl.sign")) == NULL) {
70     goto free;
71   }
72 
73   if (0 != crypto_sign_init(obj->state)) {
74     goto free;
75   }
76 
77   // Create return values
78   ret = enif_make_resource(env, obj);
79 
80   goto release;
81 
82 bad_arg:
83   return enif_make_badarg(env);
84 free:
85   if (obj->alive)
86     if (obj->state != NULL) {
87       sodium_memzero(obj->state, crypto_sign_statebytes());
88       enif_free(obj->state);
89       obj->state = NULL;
90     }
91 release:
92   // This also frees the mutex via the destructor
93   enif_release_resource(obj);
94 done:
95   return ret;
96 }
97 
98 /*
99   int crypto_sign_update(crypto_sign_state *state,
100                         const unsigned char *m,
101                         unsigned long long mlen);
102  */
103 
enacl_crypto_sign_update(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])104 ERL_NIF_TERM enacl_crypto_sign_update(ErlNifEnv *env, int argc,
105                                       ERL_NIF_TERM const argv[]) {
106   ERL_NIF_TERM ret;
107   enacl_sign_ctx *obj = NULL;
108   ErlNifBinary data;
109 
110   // Validate the arguments
111   if (argc != 2)
112     goto bad_arg;
113   if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
114     goto bad_arg;
115   if (!enif_inspect_binary(env, argv[1], &data))
116     goto bad_arg;
117 
118   enif_mutex_lock(obj->mtx);
119   if (!obj->alive) {
120     ret = enacl_error_finalized(env);
121     goto done;
122   }
123 
124   if (0 != crypto_sign_update(obj->state, data.data, data.size)) {
125     ret = enacl_internal_error(env); // This should never be hit
126     goto done;
127   }
128 
129   ret = argv[0];
130   goto done;
131 
132 bad_arg:
133   return enif_make_badarg(env);
134 done:
135   enif_mutex_unlock(obj->mtx);
136   return ret;
137 }
138 
enacl_crypto_sign_final_create(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])139 ERL_NIF_TERM enacl_crypto_sign_final_create(ErlNifEnv *env, int argc,
140                                             ERL_NIF_TERM const argv[]) {
141   ERL_NIF_TERM ret;
142   enacl_sign_ctx *obj = NULL;
143   ErlNifBinary sk, sig;
144   unsigned long long siglen;
145 
146   if (argc != 2)
147     goto bad_arg;
148   if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
149     goto bad_arg;
150   if (!enif_inspect_binary(env, argv[1], &sk))
151     goto bad_arg;
152   if (sk.size != crypto_sign_SECRETKEYBYTES)
153     goto bad_arg;
154 
155   enif_mutex_lock(obj->mtx);
156   if (!obj->alive) {
157     ret = enacl_error_finalized(env);
158     goto done;
159   }
160 
161   if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
162     ret = enacl_internal_error(env);
163     goto done;
164   }
165 
166   crypto_sign_final_create(obj->state, sig.data, &siglen, sk.data);
167 
168   ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
169   ERL_NIF_TERM signature = enif_make_binary(env, &sig);
170 
171   ret = enif_make_tuple2(env, ok, signature);
172   goto cleanup;
173 
174 bad_arg:
175   return enif_make_badarg(env);
176 cleanup:
177   obj->alive = 0;
178   sodium_memzero(obj->state, crypto_sign_statebytes());
179   enif_free(obj->state);
180   obj->state = NULL;
181 done:
182   enif_mutex_unlock(obj->mtx);
183   return ret;
184 }
185 
enacl_crypto_sign_final_verify(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])186 ERL_NIF_TERM enacl_crypto_sign_final_verify(ErlNifEnv *env, int argc,
187                                             ERL_NIF_TERM const argv[]) {
188   ErlNifBinary pk, sig;
189   enacl_sign_ctx *obj = NULL;
190   ERL_NIF_TERM ret;
191 
192   if (argc != 3)
193     goto bad_arg;
194   if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
195     goto bad_arg;
196   if (!enif_inspect_binary(env, argv[1], &sig))
197     goto bad_arg;
198   if (!enif_inspect_binary(env, argv[2], &pk))
199     goto bad_arg;
200   if (pk.size != crypto_sign_PUBLICKEYBYTES)
201     goto bad_arg;
202 
203   enif_mutex_lock(obj->mtx);
204   if (!obj->alive) {
205     ret = enacl_error_finalized(env);
206     goto done;
207   }
208 
209   if (0 == crypto_sign_final_verify(obj->state, sig.data, pk.data)) {
210     ret = enif_make_atom(env, "true");
211   } else {
212     ret = enif_make_atom(env, "false");
213   }
214   // Mark as done
215   goto cleanup;
216 
217 bad_arg:
218   return enif_make_badarg(env);
219 cleanup:
220   // Get rid of the context and mark it as dead
221   obj->alive = 0;
222   sodium_memzero(obj->state, crypto_sign_statebytes());
223   enif_free(obj->state);
224   obj->state = NULL;
225 done:
226   enif_mutex_unlock(obj->mtx);
227   return ret;
228 }
229 
230 /* Ed 25519 */
231 ERL_NIF_TERM
enacl_crypto_sign_ed25519_keypair(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])232 enacl_crypto_sign_ed25519_keypair(ErlNifEnv *env, int argc,
233                                   ERL_NIF_TERM const argv[]) {
234   ErlNifBinary pk, sk;
235 
236   if (argc != 0) {
237     return enif_make_badarg(env);
238   }
239 
240   if (!enif_alloc_binary(crypto_sign_ed25519_PUBLICKEYBYTES, &pk)) {
241     return enacl_internal_error(env);
242   }
243 
244   if (!enif_alloc_binary(crypto_sign_ed25519_SECRETKEYBYTES, &sk)) {
245     enif_release_binary(&pk);
246     return enacl_internal_error(env);
247   }
248 
249   crypto_sign_ed25519_keypair(pk.data, sk.data);
250 
251   return enif_make_tuple2(env, enif_make_binary(env, &pk),
252                           enif_make_binary(env, &sk));
253 }
254 
255 ERL_NIF_TERM
enacl_crypto_sign_ed25519_sk_to_pk(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])256 enacl_crypto_sign_ed25519_sk_to_pk(ErlNifEnv *env, int argc,
257                                    ERL_NIF_TERM const argv[]) {
258   ErlNifBinary pk, sk;
259 
260   if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &sk)) ||
261       (sk.size != crypto_sign_ed25519_SECRETKEYBYTES)) {
262     return enif_make_badarg(env);
263   }
264 
265   if (!enif_alloc_binary(crypto_sign_ed25519_PUBLICKEYBYTES, &pk)) {
266     return enacl_internal_error(env);
267   }
268 
269   crypto_sign_ed25519_sk_to_pk(pk.data, sk.data);
270 
271   return enif_make_binary(env, &pk);
272 }
273 
274 ERL_NIF_TERM
enacl_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])275 enacl_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv *env, int argc,
276                                                ERL_NIF_TERM const argv[]) {
277   ErlNifBinary curve25519_pk, ed25519_pk;
278 
279   if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &ed25519_pk)) ||
280       (ed25519_pk.size != crypto_sign_ed25519_PUBLICKEYBYTES)) {
281     return enif_make_badarg(env);
282   }
283 
284   if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_pk)) {
285     return enacl_internal_error(env);
286   }
287 
288   crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.data, ed25519_pk.data);
289 
290   return enif_make_binary(env, &curve25519_pk);
291 }
292 
293 ERL_NIF_TERM
enacl_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])294 enacl_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv *env, int argc,
295                                                ERL_NIF_TERM const argv[]) {
296   ErlNifBinary curve25519_sk, ed25519_sk;
297 
298   if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &ed25519_sk)) ||
299       (ed25519_sk.size != crypto_sign_ed25519_SECRETKEYBYTES)) {
300     return enif_make_badarg(env);
301   }
302 
303   if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_sk)) {
304     return enacl_internal_error(env);
305   }
306 
307   crypto_sign_ed25519_sk_to_curve25519(curve25519_sk.data, ed25519_sk.data);
308 
309   return enif_make_binary(env, &curve25519_sk);
310 }
311 
312 ERL_NIF_TERM
enacl_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])313 enacl_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
314                                          ERL_NIF_TERM const argv[]) {
315   return enif_make_int64(env, crypto_sign_ed25519_PUBLICKEYBYTES);
316 }
317 
318 ERL_NIF_TERM
enacl_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])319 enacl_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv *env, int argc,
320                                          ERL_NIF_TERM const argv[]) {
321   return enif_make_int64(env, crypto_sign_ed25519_SECRETKEYBYTES);
322 }
323 
enacl_crypto_sign_PUBLICKEYBYTES(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])324 ERL_NIF_TERM enacl_crypto_sign_PUBLICKEYBYTES(ErlNifEnv *env, int argc,
325                                               ERL_NIF_TERM const argv[]) {
326   return enif_make_int64(env, crypto_sign_PUBLICKEYBYTES);
327 }
328 
enacl_crypto_sign_SECRETKEYBYTES(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])329 ERL_NIF_TERM enacl_crypto_sign_SECRETKEYBYTES(ErlNifEnv *env, int argc,
330                                               ERL_NIF_TERM const argv[]) {
331   return enif_make_int64(env, crypto_sign_SECRETKEYBYTES);
332 }
333 
enacl_crypto_sign_SEEDBYTES(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])334 ERL_NIF_TERM enacl_crypto_sign_SEEDBYTES(ErlNifEnv *env, int argc,
335                                          ERL_NIF_TERM const argv[]) {
336   return enif_make_int64(env, crypto_sign_SEEDBYTES);
337 }
338 
enacl_crypto_sign_keypair(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])339 ERL_NIF_TERM enacl_crypto_sign_keypair(ErlNifEnv *env, int argc,
340                                        ERL_NIF_TERM const argv[]) {
341   ErlNifBinary pk, sk;
342 
343   if (argc != 0) {
344     return enif_make_badarg(env);
345   }
346 
347   if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
348     return enacl_internal_error(env);
349   }
350 
351   if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
352     enif_release_binary(&pk);
353     return enacl_internal_error(env);
354   }
355 
356   crypto_sign_keypair(pk.data, sk.data);
357 
358   return enif_make_tuple2(env, enif_make_binary(env, &pk),
359                           enif_make_binary(env, &sk));
360 }
361 
enacl_crypto_sign_seed_keypair(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])362 ERL_NIF_TERM enacl_crypto_sign_seed_keypair(ErlNifEnv *env, int argc,
363                                             ERL_NIF_TERM const argv[]) {
364   ErlNifBinary pk, sk, seed;
365 
366   if ((argc != 1) || (!enif_inspect_binary(env, argv[0], &seed))) {
367     return enif_make_badarg(env);
368   }
369 
370   if (!enif_alloc_binary(crypto_sign_PUBLICKEYBYTES, &pk)) {
371     return enacl_internal_error(env);
372   }
373 
374   if (!enif_alloc_binary(crypto_sign_SECRETKEYBYTES, &sk)) {
375     enif_release_binary(&pk);
376     return enacl_internal_error(env);
377   }
378 
379   crypto_sign_seed_keypair(pk.data, sk.data, seed.data);
380 
381   return enif_make_tuple2(env, enif_make_binary(env, &pk),
382                           enif_make_binary(env, &sk));
383 }
384 
enacl_crypto_sign(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])385 ERL_NIF_TERM enacl_crypto_sign(ErlNifEnv *env, int argc,
386                                ERL_NIF_TERM const argv[]) {
387   ErlNifBinary m, sk, sm;
388   unsigned long long smlen;
389 
390   if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
391       (!enif_inspect_binary(env, argv[1], &sk))) {
392     return enif_make_badarg(env);
393   }
394 
395   if (sk.size != crypto_sign_SECRETKEYBYTES) {
396     return enif_make_badarg(env);
397   }
398 
399   if (!enif_alloc_binary(m.size + crypto_sign_BYTES, &sm)) {
400     return enacl_internal_error(env);
401   }
402 
403   crypto_sign(sm.data, &smlen, m.data, m.size, sk.data);
404 
405   return enif_make_sub_binary(env, enif_make_binary(env, &sm), 0, smlen);
406 }
407 
enacl_crypto_sign_open(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])408 ERL_NIF_TERM enacl_crypto_sign_open(ErlNifEnv *env, int argc,
409                                     ERL_NIF_TERM const argv[]) {
410   ErlNifBinary m, sm, pk;
411   unsigned long long mlen;
412 
413   if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &sm)) ||
414       (!enif_inspect_binary(env, argv[1], &pk))) {
415     return enif_make_badarg(env);
416   }
417 
418   if (pk.size != crypto_sign_PUBLICKEYBYTES) {
419     return enif_make_badarg(env);
420   }
421 
422   if (!enif_alloc_binary(sm.size, &m)) {
423     return enacl_internal_error(env);
424   }
425 
426   if (0 == crypto_sign_open(m.data, &mlen, sm.data, sm.size, pk.data)) {
427     ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
428     ERL_NIF_TERM ret_bin =
429         enif_make_sub_binary(env, enif_make_binary(env, &m), 0, mlen);
430     return enif_make_tuple2(env, ret_ok, ret_bin);
431   } else {
432     enif_release_binary(&m);
433     return enacl_error_tuple(env, "failed_verification");
434   }
435 }
436 
enacl_crypto_sign_detached(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])437 ERL_NIF_TERM enacl_crypto_sign_detached(ErlNifEnv *env, int argc,
438                                         ERL_NIF_TERM const argv[]) {
439   ErlNifBinary m, sk, sig;
440   unsigned long long siglen;
441 
442   if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
443       (!enif_inspect_binary(env, argv[1], &sk))) {
444     return enif_make_badarg(env);
445   }
446 
447   if (sk.size != crypto_sign_SECRETKEYBYTES) {
448     return enif_make_badarg(env);
449   }
450 
451   if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
452     return enacl_internal_error(env);
453   }
454 
455   crypto_sign_detached(sig.data, &siglen, m.data, m.size, sk.data);
456 
457   return enif_make_binary(env, &sig);
458 }
459 
460 ERL_NIF_TERM
enacl_crypto_sign_verify_detached(ErlNifEnv * env,int argc,ERL_NIF_TERM const argv[])461 enacl_crypto_sign_verify_detached(ErlNifEnv *env, int argc,
462                                   ERL_NIF_TERM const argv[]) {
463   ErlNifBinary m, sig, pk;
464 
465   if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &sig)) ||
466       (!enif_inspect_iolist_as_binary(env, argv[1], &m)) ||
467       (!enif_inspect_binary(env, argv[2], &pk))) {
468     return enif_make_badarg(env);
469   }
470 
471   if (sig.size != crypto_sign_BYTES) {
472     return enif_make_badarg(env);
473   }
474 
475   if (pk.size != crypto_sign_PUBLICKEYBYTES) {
476     return enif_make_badarg(env);
477   }
478 
479   if (0 == crypto_sign_verify_detached(sig.data, m.data, m.size, pk.data)) {
480     return enif_make_atom(env, ATOM_TRUE);
481   } else {
482     return enif_make_atom(env, ATOM_FALSE);
483   }
484 }
485