1 /*
2 * Copyright (c) 2018, Henry Corrigan-Gibbs
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
8
9 #include <blapit.h>
10 #include <mprio.h>
11 #include <pk11pub.h>
12 #include <string.h>
13
14 #include "prg.h"
15 #include "rand.h"
16 #include "share.h"
17 #include "util.h"
18
19 struct prg
20 {
21 PK11SlotInfo* slot;
22 PK11SymKey* key;
23 PK11Context* ctx;
24 };
25
26 SECStatus
PrioPRGSeed_randomize(PrioPRGSeed * key)27 PrioPRGSeed_randomize(PrioPRGSeed* key)
28 {
29 return rand_bytes((unsigned char*)key, PRG_SEED_LENGTH);
30 }
31
32 PRG
PRG_new(const PrioPRGSeed key_in)33 PRG_new(const PrioPRGSeed key_in)
34 {
35 PRG prg = malloc(sizeof(struct prg));
36 if (!prg)
37 return NULL;
38 prg->slot = NULL;
39 prg->key = NULL;
40 prg->ctx = NULL;
41
42 SECStatus rv = SECSuccess;
43 const CK_MECHANISM_TYPE cipher = CKM_AES_CTR;
44
45 P_CHECKA(prg->slot = PK11_GetInternalSlot());
46
47 // Create a mutable copy of the key.
48 PrioPRGSeed key_mut;
49 memcpy(key_mut, key_in, PRG_SEED_LENGTH);
50
51 SECItem keyItem = { siBuffer, key_mut, PRG_SEED_LENGTH };
52
53 // The IV can be all zeros since we only encrypt once with
54 // each AES key.
55 CK_AES_CTR_PARAMS param = { 128, {} };
56 SECItem paramItem = { siBuffer, (void*)¶m, sizeof(CK_AES_CTR_PARAMS) };
57
58 P_CHECKA(prg->key = PK11_ImportSymKey(prg->slot, cipher, PK11_OriginUnwrap,
59 CKA_ENCRYPT, &keyItem, NULL));
60
61 P_CHECKA(prg->ctx = PK11_CreateContextBySymKey(cipher, CKA_ENCRYPT, prg->key,
62 ¶mItem));
63
64 cleanup:
65 if (rv != SECSuccess) {
66 PRG_clear(prg);
67 prg = NULL;
68 }
69
70 return prg;
71 }
72
73 void
PRG_clear(PRG prg)74 PRG_clear(PRG prg)
75 {
76 if (!prg)
77 return;
78
79 if (prg->key)
80 PK11_FreeSymKey(prg->key);
81 if (prg->slot)
82 PK11_FreeSlot(prg->slot);
83 if (prg->ctx)
84 PK11_DestroyContext(prg->ctx, PR_TRUE);
85
86 free(prg);
87 }
88
89 static SECStatus
PRG_get_bytes_internal(void * prg_vp,unsigned char * bytes,size_t len)90 PRG_get_bytes_internal(void* prg_vp, unsigned char* bytes, size_t len)
91 {
92 SECStatus rv = SECSuccess;
93 PRG prg = (PRG)prg_vp;
94 unsigned char* in = NULL;
95
96 P_CHECKA(in = calloc(len, sizeof(unsigned char)));
97
98 int outlen;
99 P_CHECKC(PK11_CipherOp(prg->ctx, bytes, &outlen, len, in, len));
100 P_CHECKCB((size_t)outlen == len);
101
102 cleanup:
103 if (in)
104 free(in);
105
106 return rv;
107 }
108
109 SECStatus
PRG_get_bytes(PRG prg,unsigned char * bytes,size_t len)110 PRG_get_bytes(PRG prg, unsigned char* bytes, size_t len)
111 {
112 return PRG_get_bytes_internal((void*)prg, bytes, len);
113 }
114
115 SECStatus
PRG_get_int(PRG prg,mp_int * out,const mp_int * max)116 PRG_get_int(PRG prg, mp_int* out, const mp_int* max)
117 {
118 return rand_int_rng(out, max, &PRG_get_bytes_internal, (void*)prg);
119 }
120
121 SECStatus
PRG_get_int_range(PRG prg,mp_int * out,const mp_int * lower,const mp_int * max)122 PRG_get_int_range(PRG prg, mp_int* out, const mp_int* lower, const mp_int* max)
123 {
124 SECStatus rv;
125 mp_int width;
126 MP_DIGITS(&width) = NULL;
127 MP_CHECKC(mp_init(&width));
128
129 // Compute
130 // width = max - lower
131 MP_CHECKC(mp_sub(max, lower, &width));
132
133 // Get an integer x in the range [0, width)
134 P_CHECKC(PRG_get_int(prg, out, &width));
135
136 // Set
137 // out = lower + x
138 // which is in the range [lower, width+lower),
139 // which is [lower, max).
140 MP_CHECKC(mp_add(lower, out, out));
141
142 cleanup:
143 mp_clear(&width);
144 return rv;
145 }
146
147 SECStatus
PRG_get_array(PRG prg,MPArray dst,const mp_int * mod)148 PRG_get_array(PRG prg, MPArray dst, const mp_int* mod)
149 {
150 SECStatus rv;
151 for (int i = 0; i < dst->len; i++) {
152 P_CHECK(PRG_get_int(prg, &dst->data[i], mod));
153 }
154
155 return SECSuccess;
156 }
157
158 SECStatus
PRG_share_int(PRG prgB,mp_int * shareA,const mp_int * src,const_PrioConfig cfg)159 PRG_share_int(PRG prgB, mp_int* shareA, const mp_int* src, const_PrioConfig cfg)
160 {
161 SECStatus rv = SECSuccess;
162 mp_int tmp;
163 MP_DIGITS(&tmp) = NULL;
164
165 MP_CHECKC(mp_init(&tmp));
166 P_CHECKC(PRG_get_int(prgB, &tmp, &cfg->modulus));
167 MP_CHECKC(mp_submod(src, &tmp, &cfg->modulus, shareA));
168
169 cleanup:
170 mp_clear(&tmp);
171 return rv;
172 }
173
174 SECStatus
PRG_share_array(PRG prgB,MPArray arrA,const_MPArray src,const_PrioConfig cfg)175 PRG_share_array(PRG prgB, MPArray arrA, const_MPArray src, const_PrioConfig cfg)
176 {
177 SECStatus rv = SECSuccess;
178 if (arrA->len != src->len)
179 return SECFailure;
180
181 const int len = src->len;
182
183 for (int i = 0; i < len; i++) {
184 P_CHECK(PRG_share_int(prgB, &arrA->data[i], &src->data[i], cfg));
185 }
186
187 return rv;
188 }
189