1 /*
2  **      $Id: io.c 1003 2008-06-24 14:35:09Z aaron $
3  */
4 /************************************************************************
5  *                                                                      *
6  *                             Copyright (C)  2002                      *
7  *                                Internet2                             *
8  *                             All Rights Reserved                      *
9  *                                                                      *
10  ************************************************************************/
11 /*
12  **        File:        io.c
13  **
14  **        Author:      Jeff W. Boote
15  **                     Anatoly Karp
16  **
17  **        Date:        Wed Apr  24 10:42:12  2002
18  **
19  **        Description: This file contains the private functions to
20  **                     to facilitate IO that the library needs to do.
21  */
22 #include <owampP.h>
23 
24 #include <I2util/pbkdf2.h>
25 #include <I2util/hmac-sha1.h>
26 
27 int
_OWPSendBlocksIntr(OWPControl cntrl,uint8_t * buf,int num_blocks,int * retn_on_intr)28 _OWPSendBlocksIntr(
29         OWPControl  cntrl,
30         uint8_t     *buf,
31         int         num_blocks,
32         int         *retn_on_intr
33         )
34 {
35     ssize_t n;
36 
37     if (cntrl->mode & OWP_MODE_DOCIPHER)
38         _OWPEncryptBlocks(cntrl, buf, num_blocks, buf);
39 
40     n = I2Writeni(cntrl->sockfd,buf,num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE,
41             retn_on_intr);
42     if(n < 0){
43         return -1;
44     }
45 
46     return num_blocks;
47 }
48 
49 int
_OWPReceiveBlocksIntr(OWPControl cntrl,uint8_t * buf,int num_blocks,int * retn_on_intr)50 _OWPReceiveBlocksIntr(
51         OWPControl  cntrl,
52         uint8_t     *buf,
53         int         num_blocks,
54         int         *retn_on_intr
55         )
56 {
57     ssize_t n;
58 
59     n = I2Readni(cntrl->sockfd,buf,num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE,
60             retn_on_intr);
61     if(n < 0){
62         return -1;
63     }
64 
65     /*
66      * Short reads mean socket was closed.
67      */
68     if(n != (num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE))
69         return 0;
70 
71     if (cntrl->mode & OWP_MODE_DOCIPHER)
72         _OWPDecryptBlocks(cntrl, buf, num_blocks, buf);
73 
74     return num_blocks;
75 }
76 
77 int
_OWPSendBlocks(OWPControl cntrl,uint8_t * buf,int num_blocks)78 _OWPSendBlocks(
79         OWPControl  cntrl,
80         uint8_t     *buf,
81         int         num_blocks
82         )
83 {
84     int intr=1;
85     int *retn_on_intr = &intr;
86 
87     if(cntrl->retn_on_intr){
88         retn_on_intr = cntrl->retn_on_intr;
89     }
90 
91     return _OWPSendBlocksIntr(cntrl,buf,num_blocks,retn_on_intr);
92 }
93 
94 int
_OWPReceiveBlocks(OWPControl cntrl,uint8_t * buf,int num_blocks)95 _OWPReceiveBlocks(
96         OWPControl  cntrl,
97         uint8_t     *buf,
98         int         num_blocks
99         )
100 {
101     int intr=1;
102     int *retn_on_intr = &intr;
103 
104     if(cntrl->retn_on_intr){
105         retn_on_intr = cntrl->retn_on_intr;
106     }
107 
108     return _OWPReceiveBlocksIntr(cntrl,buf,num_blocks,retn_on_intr);
109 }
110 
111 /*
112  ** The following two functions encrypt/decrypt a given number
113  ** of (_OWP_RIJNDAEL_BLOCK_SIZE-byte) blocks. IV is currently updated within
114  ** the rijndael api (blockEncrypt/blockDecrypt).
115  */
116 int
_OWPEncryptBlocks(OWPControl cntrl,uint8_t * buf,int num_blocks,uint8_t * out)117 _OWPEncryptBlocks(
118         OWPControl  cntrl,
119         uint8_t     *buf,
120         int         num_blocks,
121         uint8_t     *out
122         )
123 {
124     int r;
125     r = blockEncrypt(cntrl->writeIV,&cntrl->encrypt_key,
126             (uint8_t *)buf, num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE*8,
127             (uint8_t *)out);
128     if (r != num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE*8)
129         return -1;
130     return 0;
131 }
132 
133 
134 int
_OWPDecryptBlocks(OWPControl cntrl,uint8_t * buf,int num_blocks,uint8_t * out)135 _OWPDecryptBlocks(
136         OWPControl  cntrl,
137         uint8_t     *buf,
138         int         num_blocks,
139         uint8_t     *out
140         )
141 {
142     int r;
143     r = blockDecrypt(cntrl->readIV,&cntrl->decrypt_key,
144             (uint8_t *)buf, num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE*8,
145             (uint8_t *)out);
146     if (r != num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE*8)
147         return -1;
148     return 0;
149 }
150 
151 /*
152  ** This function sets up the key field of a OWPControl structure,
153  ** using the binary key located in <binKey>.
154  */
155 
156 void
_OWPMakeKey(OWPControl cntrl,uint8_t binKey[_OWP_RIJNDAEL_BLOCK_SIZE])157 _OWPMakeKey(
158         OWPControl  cntrl,
159         uint8_t     binKey[_OWP_RIJNDAEL_BLOCK_SIZE]
160         )
161 {
162     cntrl->encrypt_key.Nr = rijndaelKeySetupEnc(cntrl->encrypt_key.rk,binKey,
163                 _OWP_RIJNDAEL_BLOCK_SIZE*8);
164     cntrl->decrypt_key.Nr = rijndaelKeySetupDec(cntrl->decrypt_key.rk,binKey,
165                 _OWP_RIJNDAEL_BLOCK_SIZE*8);
166 }
167 
168 
169 /*
170  * The next two functions perform a single encryption/decryption
171  * of the Token in the SetupResponse message from the Control protocol.
172  *
173  * (AES CBC, IV=0) key=pbkdf2(pf,salt,count)
174  */
175 
176 int
OWPEncryptToken(const uint8_t * pf,size_t pf_len,const uint8_t salt[_OWP_SALT_SIZE],uint32_t count,const uint8_t token_in[_OWP_TOKEN_SIZE],uint8_t token_out[_OWP_TOKEN_SIZE])177 OWPEncryptToken(
178         const uint8_t   *pf,
179         size_t          pf_len,
180         const uint8_t   salt[_OWP_SALT_SIZE],
181         uint32_t        count,
182         const uint8_t   token_in[_OWP_TOKEN_SIZE],
183         uint8_t         token_out[_OWP_TOKEN_SIZE]
184         )
185 {
186     int         r;
187     uint8_t     IV[_OWP_RIJNDAEL_BLOCK_SIZE];
188     uint8_t     dk[_OWP_RIJNDAEL_BLOCK_SIZE];
189     keyInstance key;
190 
191     /*
192      * Derive key
193      */
194     if( (I2pbkdf2(I2HMACSha1,(uint32_t)I2SHA1_DIGEST_SIZE,
195                     pf,pf_len,salt,_OWP_SALT_SIZE,count,sizeof(dk),dk))){
196         return -1;
197     }
198 
199     memset(IV, 0, _OWP_RIJNDAEL_BLOCK_SIZE);
200 
201     key.Nr = rijndaelKeySetupEnc(key.rk, dk, sizeof(dk)*8);
202     r = blockEncrypt(IV,&key,token_in,_OWP_TOKEN_SIZE*8,token_out);
203 
204     if (r != (_OWP_TOKEN_SIZE*8))
205         return -1;
206 
207     return 0;
208 }
209 
210 int
OWPDecryptToken(const uint8_t * pf,size_t pf_len,const uint8_t salt[_OWP_SALT_SIZE],uint32_t count,const uint8_t token_in[_OWP_TOKEN_SIZE],uint8_t token_out[_OWP_TOKEN_SIZE])211 OWPDecryptToken(
212         const uint8_t   *pf,
213         size_t          pf_len,
214         const uint8_t   salt[_OWP_SALT_SIZE],
215         uint32_t        count,
216         const uint8_t   token_in[_OWP_TOKEN_SIZE],
217         uint8_t         token_out[_OWP_TOKEN_SIZE]
218         )
219 {
220     int         r;
221     uint8_t    IV[_OWP_RIJNDAEL_BLOCK_SIZE];
222     uint8_t    dk[_OWP_RIJNDAEL_BLOCK_SIZE];
223     keyInstance key;
224 
225     /*
226      * Derive key
227      */
228     if( (I2pbkdf2(I2HMACSha1,(uint32_t)I2SHA1_DIGEST_SIZE,
229                     pf,pf_len,salt,_OWP_SALT_SIZE,count,sizeof(dk),dk))){
230         return -1;
231     }
232 
233     memset(IV, 0, _OWP_RIJNDAEL_BLOCK_SIZE);
234 
235     key.Nr = rijndaelKeySetupDec(key.rk, dk, 128);
236     r = blockDecrypt(IV,&key,token_in,_OWP_TOKEN_SIZE*8,token_out);
237 
238     if (r != (_OWP_TOKEN_SIZE*8))
239         return -1;
240 
241     return 0;
242 }
243 
244 /*
245  * Function:    _OWPSendHMACAdd
246  *
247  * Description:
248  *              Adds data to the 'send' HMAC.
249  *
250  * In Args:
251  *
252  * Out Args:
253  *
254  * Scope:
255  * Returns:
256  * Side Effect:
257  */
258 void
_OWPSendHMACAdd(OWPControl cntrl,const char * txt,uint32_t num_blocks)259 _OWPSendHMACAdd(
260         OWPControl  cntrl,
261         const char  *txt,
262         uint32_t    num_blocks
263         )
264 {
265     if( !(cntrl->mode & OWP_MODE_DOCIPHER)){
266         return;
267     }
268 
269     I2HMACSha1Append(cntrl->send_hmac_ctx,(uint8_t *)txt,
270             num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE);
271 
272     return;
273 }
274 
275 /*
276  * Function:    _OWPSendHMACDigestClear
277  *
278  * Description:
279  *              Fetches the digest from the 'send' HMAC and
280  *              clears the digest in preparation for the next
281  *              "message".
282  *
283  * In Args:
284  *
285  * Out Args:
286  *
287  * Scope:
288  * Returns:
289  * Side Effect:
290  */
291 void
_OWPSendHMACDigestClear(OWPControl cntrl,char digest[_OWP_RIJNDAEL_BLOCK_SIZE])292 _OWPSendHMACDigestClear(
293         OWPControl  cntrl,
294         char        digest[_OWP_RIJNDAEL_BLOCK_SIZE]
295         )
296 {
297     uint8_t hmacd[I2HMAC_SHA1_DIGEST_SIZE];
298 
299     memset(digest,0,_OWP_RIJNDAEL_BLOCK_SIZE);
300 
301     if( !(cntrl->mode & OWP_MODE_DOCIPHER)){
302         return;
303     }
304 
305     memset(hmacd,0,sizeof(hmacd));
306 
307     I2HMACSha1Finish(cntrl->send_hmac_ctx,hmacd);
308     memcpy(digest,hmacd,MIN(_OWP_RIJNDAEL_BLOCK_SIZE,sizeof(hmacd)));
309 
310     I2HMACSha1Init(cntrl->send_hmac_ctx,cntrl->hmac_key,
311             sizeof(cntrl->hmac_key));
312     return;
313 }
314 
315 /*
316  * Function:    _OWPRecvHMACAdd
317  *
318  * Description:
319  *              Adds data to the 'send' HMAC.
320  *
321  * In Args:
322  *
323  * Out Args:
324  *
325  * Scope:
326  * Returns:
327  * Side Effect:
328  */
329 void
_OWPRecvHMACAdd(OWPControl cntrl,const char * txt,uint32_t num_blocks)330 _OWPRecvHMACAdd(
331         OWPControl  cntrl,
332         const char  *txt,
333         uint32_t    num_blocks
334         )
335 {
336     if( !(cntrl->mode & OWP_MODE_DOCIPHER)){
337         return;
338     }
339 
340     I2HMACSha1Append(cntrl->recv_hmac_ctx,(uint8_t *)txt,
341             num_blocks*_OWP_RIJNDAEL_BLOCK_SIZE);
342 
343     return;
344 }
345 
346 /*
347  * Function:    _OWPRecvHMACCheckClear
348  *
349  * Description:
350  *              Determines if the hmac sent from the remote
351  *              party matches the locally computed one. Then
352  *              clears the hmac and prepares it for the next
353  *              message.
354  *
355  * In Args:
356  *
357  * Out Args:
358  *
359  * Scope:
360  * Returns:
361  * Side Effect:
362  */
363 OWPBoolean
_OWPRecvHMACCheckClear(OWPControl cntrl,char check[_OWP_RIJNDAEL_BLOCK_SIZE])364 _OWPRecvHMACCheckClear(
365         OWPControl  cntrl,
366         char        check[_OWP_RIJNDAEL_BLOCK_SIZE]
367         )
368 {
369     uint8_t     hmacd[I2HMAC_SHA1_DIGEST_SIZE];
370     OWPBoolean  rval;
371 
372     if( !(cntrl->mode & OWP_MODE_DOCIPHER)){
373         return True;
374     }
375 
376     memset(hmacd,0,sizeof(hmacd));
377 
378     I2HMACSha1Finish(cntrl->recv_hmac_ctx,hmacd);
379     rval = (memcmp(check,hmacd,
380                 MIN(_OWP_RIJNDAEL_BLOCK_SIZE,sizeof(hmacd))) == 0);
381 
382     I2HMACSha1Init(cntrl->recv_hmac_ctx,cntrl->hmac_key,
383             sizeof(cntrl->hmac_key));
384 
385     return rval;
386 }
387