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*)&param, 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                                                  &paramItem));
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