No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / pci / n8 / common / api / commands / n8_cb_rsa.c
blobd4efc6fb0e25dbac956f78a2e6b880a34af8f40b
1 /*-
2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
3 * All rights reserved.
5 * NBMK Encryption Technologies provides no support of any kind for
6 * this software. Questions or concerns about it may be addressed to
7 * the members of the relevant open-source community at
8 * <tech-crypto@netbsd.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
12 * met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 static char const n8_id[] = "$Id: n8_cb_rsa.c,v 1.1 2008/10/30 12:02:15 darran Exp $";
36 /*****************************************************************************/
37 /** @file n8_cb_rsa.c
38 * @brief RSA Command Block Generator
40 * Generates all command blocks for RSA-related functions.
42 *****************************************************************************/
44 /*****************************************************************************
45 * Revision history:
46 * 12/17/03 bac Added cb_rsaPublicDecrypt
47 * 09/10/02 brr Set command complete bit on last command block.
48 * 05/07/02 bac Fix Bug #758: command blocks generated were incorrect if the
49 * modulus length was less than 2 BNC digits. The commands
50 * blocks were restructured to behave correctly.
51 * 05/09/02 brr Modified allocateBNCConstants to use constant setup by driver.
52 * 04/08/02 bac Minor change to use precomputed key_p->pDigits and qDigits.
53 * 03/26/02 brr Allocate the data buffer as part of the API request.
54 * 02/21/02 brr Perform BNC constant initialization once upon startup.
55 * 02/20/02 brr Removed references to the queue structure.
56 * 12/12/01 bac Use precomputes for RSA encrypt. Created a new static method
57 * cb_exp_with_precomputes. Fixes Bug #371.
58 * 11/08/01 mel Fixed bug #289 : Some calls use N8_SINGLE_CHIP in the
59 * commands directory
60 * 10/19/01 bac Added support for SKS operations and RSA Decrypt for non-CRT.
61 * 10/28/01 msz Added locking allocateBNCConstants.
62 * 10/08/01 bac Changes for the case where len(p) != len(q) (BUG #180).
63 * Everywhere a data length was assumed to half the key length,
64 * it has been replaced with the specific dependency on the
65 * length of p or q.
66 * 09/14/01 bac Use new DBG_PRINT_PK_CMD_BLOCKS macros.
67 * 09/05/01 bac Minor formatting change.
68 * 08/24/01 bac Changed all methods to accept the pre-allocated command
69 * buffer.
70 * 08/16/01 mmd Now including n8_driver_api.h instead of simon_driver_api.h.
71 * 08/21/01 bac Fixes to allow the use of odd key lengths (Bug #174).
72 * 07/30/01 bac Pass queue pointer to all length calculation macros.
73 * 07/02/01 mel Fixed comments.
74 * 06/28/01 bac Changed size of load on computeCX as it did not work for 'n',
75 * changed the interface to cb_rsaEncrypt and cb_rsaDecrypt to
76 * take physical addresses not N8_MemoryHandle_t. Other minor
77 * naming/formatting fixes.
78 * 06/27/01 bac Removed calls to free request blocks on error. This is
79 * handled in the caller.
80 * 06/25/01 bac Added static allocation of BNC constants, more conversion to
81 * physical addresses.
82 * 06/19/01 bac Corrected use of kernel memory.
83 * 05/30/01 bac Fixed printCommandBlock to display pleasingly for little
84 * endian machines.
85 * 05/03/01 bac Added include for string.h
86 * 04/30/01 bac Added support for rsaDecrypt use with non-PKH command generation.
87 * 04/24/01 bac Rearranged N8DEBUG fences
88 * 04/11/01 bac Standardization -- mainly support for _t suffix for types.
89 * 04/05/01 bac Changed return codes to be N8_Status instead of ints.
90 * 04/05/01 bac Removed unused debugging variable sz.
91 * 04/05/01 bac Changed all key length info to be in bytes, not digits.
92 * 03/01/01 bac Original version.
93 ****************************************************************************/
94 /** @defgroup cb_rsa RSA Command Block Generator
97 #include "n8_common.h"
98 #include "n8_pk_common.h"
99 #include "n8_pub_errors.h"
100 #include "n8_cb_rsa.h"
101 #include "n8_util.h"
102 #include "n8_driver_api.h"
103 #include "n8_semaphore.h"
105 /* #define ZERO_CMD_BLOCK(X) memset((X), 0, sizeof(PK_CMD_BLOCK_t)) */
106 #define ZERO_CMD_BLOCK(X)
108 /* globals */
109 static uint32_t bnc_one_ga;
110 static uint32_t bnc_2_D_ga;
113 /* predeclarations */
114 static N8_Boolean_t cb_RSAOperationSupported(const N8_RSAKeyObject_t *key_p);
116 /*****************************************************************************
117 * cb_computeU
118 *****************************************************************************/
119 /** @ingroup cb_rsa
120 * @brief Creates the command blocks to compute the value for u where
121 * u = (p^-1) mod q [ (multiplicative inverse of p) mod q ]
123 * @param req_p RW: Pointer to command
124 * blocks.
125 * @param p RO: Physical address of p.
126 * @param q RO: Physical address of q.
127 * @param p_length_bytes RO: Length of parameter p in bytes
128 * @param q_length_bytes RO: Length of parameter q in bytes
129 * @param result_a WO: Physical address of result
130 * @param key_length_bytes RO: Private key length.
132 * @return
133 * returnResult - returns N8_STATUS_OK if successful or Error value.
135 * @par Errors
136 * N8_MALLOC_FAILED - memory allocation failed<BR>
138 * @par Assumptions
139 * None.<br>
140 *****************************************************************************/
141 N8_Status_t cb_computeU(API_Request_t *req_p,
142 const uint32_t p,
143 const uint32_t q,
144 uint32_t result_a,
145 const int p_length_bytes,
146 const int q_length_bytes,
147 PK_CMD_BLOCK_t *cb_p,
148 PK_CMD_BLOCK_t **next_cb_pp)
151 PK_CMD_BLOCK_t *math_wr_ptr;
152 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
154 uint32_t p_length = BYTES_TO_PKDIGITS(p_length_bytes);
155 uint32_t q_length = BYTES_TO_PKDIGITS(q_length_bytes);
156 /* since p<q, then len(p) <= len(q). we want the offsets to be in units of
157 * the longer of the two, so we use q_length. */
158 unsigned int offset[3];
159 unsigned int i;
160 N8_Status_t ret = N8_STATUS_OK;
165 * BNC map:
166 * 0: p
167 * 1 q
168 * 2 p^-1 mod q
171 for (i = 0; i < sizeof(offset)/sizeof(unsigned int); i++)
173 offset[i] = i * q_length;
175 /* 1: Construct a command to load p */
176 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
178 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
179 ldst_wr_ptr->r_offset = offset[0];
180 ldst_wr_ptr->data_addr_ls = p;
181 ldst_wr_ptr->data_length = p_length_bytes;
183 /* 2: Construct a command to load q */
184 ldst_wr_ptr++;
185 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
186 ldst_wr_ptr->r_offset = offset[1];
187 ldst_wr_ptr->data_addr_ls = q;
188 ldst_wr_ptr->data_length = q_length_bytes;
190 /* 3: Construct a command for the operation p^-1 mod q */
191 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
192 math_wr_ptr->opcode_si = PK_Cmd_Inverse_A_Mod_M;
193 math_wr_ptr->r_offset = offset[2];
194 math_wr_ptr->m_length_offset =
195 (q_length << PK_Cmd_Length_Shift) | offset[1]; /* q */
196 math_wr_ptr->a_length_offset =
197 (p_length << PK_Cmd_Length_Shift) | offset[0]; /* p */
200 * 4: Construct a command to store u
202 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
203 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R;
204 ldst_wr_ptr->r_offset = offset[2];
205 ldst_wr_ptr->data_addr_ls = result_a;
206 ldst_wr_ptr->data_length = q_length_bytes;
208 /* save next address for future use */
209 *next_cb_pp = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
211 DBG_PRINT_PK_CMD_BLOCKS("Compute U",
212 (PK_CMD_BLOCK_t *) req_p->PK_CommandBlock_ptr,
213 N8_CB_COMPUTE_U_NUMCMDS);
214 } while (FALSE);
216 return ret;
217 } /* cb_computeU */
219 /*****************************************************************************
220 * cb_computeDX
221 *****************************************************************************/
222 /** @ingroup cb_rsa
223 * @brief Creates the command blocks to compute the value for dX where
224 * dX = d mod ((X-1) mod X). This is used to compute dp and dq.
226 * since (X-1) = additive_inverse(1), it can be computed as:
228 * dX = d mod(additive_inverse(1) mod X), which is more
229 * straightforward to compute
232 * @param req_p RW: Pointer to command
233 * blocks.
234 * @param X RO: Physical address of X.
235 * @param d RO: Physical address of d.
236 * @param result_a WO: Physical address of result
237 * @param key_length_bytes RO: Private key length.
239 * @return
240 * returnResult - returns N8_STATUS_OK if successful or Error value.
242 * @par Errors
243 * N8_MALLOC_FAILED - memory allocation failed<BR>
245 * @par Assumptions
246 * None.<br>
247 *****************************************************************************/
248 N8_Status_t cb_computeDX(API_Request_t *req_p,
249 const uint32_t X,
250 const uint32_t d,
251 uint32_t result_a,
252 const int key_length_bytes,
253 const int X_length_bytes,
254 PK_CMD_BLOCK_t *cb_p,
255 PK_CMD_BLOCK_t **next_cb_pp,
256 const int chip)
258 PK_CMD_BLOCK_t *math_wr_ptr;
259 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
261 uint32_t key_length = BYTES_TO_PKDIGITS(key_length_bytes);
262 uint32_t X_length = BYTES_TO_PKDIGITS(X_length_bytes);
263 unsigned int offset[5];
264 unsigned int i;
265 N8_Status_t ret = N8_STATUS_OK;
270 * BNC Layout
272 * 0 : result_a
273 * 1 : X
274 * 2 : 1
275 * 3 : -1 mod X
276 * 4 : d
277 * 5 :
279 for (i = 0; i < sizeof(offset)/sizeof(unsigned int); i++)
281 offset[i] = i * key_length;
284 /* Construct a command to load X */
285 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
287 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
288 ldst_wr_ptr->r_offset = offset[1];
289 ldst_wr_ptr->data_addr_ls = X;
290 ldst_wr_ptr->data_length = X_length_bytes;
292 /* Construct a command to load a 1 into one BNC digit */
293 ldst_wr_ptr++;
294 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
295 ldst_wr_ptr->r_offset = offset[2];
296 ldst_wr_ptr->data_addr_ls = bnc_one_ga;
297 ldst_wr_ptr->data_length = PK_Bytes_Per_BigNum_Digit;
299 /* Construct a command to load d */
300 ldst_wr_ptr++;
301 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
302 ldst_wr_ptr->r_offset = offset[4];
303 ldst_wr_ptr->data_addr_ls = d;
304 ldst_wr_ptr->data_length = key_length_bytes;
307 * Construct a command for the operation (additive_inverse(1) mod X)
309 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
310 math_wr_ptr->opcode_si = PK_Cmd_Minus_A_Mod_M;
311 math_wr_ptr->r_offset = offset[3];
312 math_wr_ptr->m_length_offset =
313 (X_length << PK_Cmd_Length_Shift) | offset[1];
314 math_wr_ptr->a_length_offset = (1 << PK_Cmd_Length_Shift) | offset[2];
317 * Construct a command for the operation:
318 * d mod ((X-1) mod X)
320 math_wr_ptr++;
321 math_wr_ptr->opcode_si = PK_Cmd_A_Mod_M;
322 math_wr_ptr->r_offset = offset[0];
323 math_wr_ptr->m_length_offset =
324 (X_length << PK_Cmd_Length_Shift) | offset[3];
325 math_wr_ptr->a_length_offset =
326 (key_length << PK_Cmd_Length_Shift) | offset[4];
330 * Construct a command to store dX
332 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
333 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R;
334 ldst_wr_ptr->r_offset = offset[0];
335 ldst_wr_ptr->data_addr_ls = result_a;
336 ldst_wr_ptr->data_length = X_length_bytes;
338 /* save next address for future use */
339 *next_cb_pp = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
341 DBG_PRINT_PK_CMD_BLOCKS("Compute DX",
342 (PK_CMD_BLOCK_t *) req_p->PK_CommandBlock_ptr,
343 N8_CB_COMPUTE_DX_NUMCMDS);
344 } while (FALSE);
346 return ret;
347 } /* computeDX */
349 /*****************************************************************************
350 * cb_computeCX
351 *****************************************************************************/
352 /** @ingroup cb_rsa
353 * @brief Creates the command blocks to compute the value for cX where
354 * cX = -X[0]^-1: the additive inverse of the multiplicative inverse
355 * of the least significant digit of X.
356 * This is used to compute cp and cq.
359 * @param req_p RW: Pointer to command
360 * blocks.
361 * @param X RO: Physical address of X.
362 * @param result_a WO: Physical address of result
363 * @param X_length_bytes RO: X length in bytes.
365 * @return
366 * returnResult - returns N8_STATUS_OK if successful or Error value.
368 * @par Errors
369 * N8_INVALID_OBJECT - command block pointer is NULL<BR>
370 * N8_MALLOC_FAILED - memory allocation failed<BR>
372 * @par Assumptions
373 * None.<br>
374 *****************************************************************************/
375 N8_Status_t cb_computeCX(const API_Request_t *req_p,
376 const uint32_t X,
377 const uint32_t result_a,
378 const int X_length_bytes,
379 PK_CMD_BLOCK_t *cb_p,
380 PK_CMD_BLOCK_t **next_cb_pp,
381 const N8_Unit_t unitID,
382 int lastCmdBlock)
384 PK_CMD_BLOCK_t *math_wr_ptr;
385 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
387 uint32_t X_length = BYTES_TO_PKDIGITS(X_length_bytes);
388 unsigned int offset[4];
390 N8_Status_t ret = N8_STATUS_OK;
391 unsigned int i;
395 * Initialize the offset values. These are to address temporary
396 * storage in the BNC. The offsets accomodate operand sizes up to
397 * the key length
399 * The BNC layout will look like the following:
401 * -----------------------------------
402 * 0: results 2 digits
403 * -----------------------------------
404 * 1: t = p[0]^-1 2 digits
405 * -----------------------------------
406 * 2: 2**128 2 digits
407 * -----------------------------------
408 * 3: p X_length
409 * -----------------------------------
411 for (i = 0; i < sizeof(offset)/sizeof(unsigned int); i++)
413 offset[i] = i * 2;
415 /* Compute cX = -(p[0]^-1 mod 2^128) mod 2^128 */
416 /* Command 1 */
417 /* Construct a command to load p[0] to Slot 3 */
418 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
420 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
421 ldst_wr_ptr->r_offset = offset[3];
422 ldst_wr_ptr->data_addr_ls = X;
423 ldst_wr_ptr->data_length = X_length_bytes;
425 /* Command 2 */
426 /* Construct a command to load a 2-digit 2^128 to Slot 2*/
427 ldst_wr_ptr++;
428 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
429 ldst_wr_ptr->r_offset = offset[2];
430 ldst_wr_ptr->data_addr_ls = bnc_2_D_ga;
431 ldst_wr_ptr->data_length = PKDIGITS_TO_BYTES(2);
433 /* Command 3 */
434 /* Construct a command for the operation t = p[0]^-1 mod 2^128 to Slot 1 */
435 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
436 math_wr_ptr->opcode_si = PK_Cmd_Inverse_A_Mod_M;
437 math_wr_ptr->r_offset = offset[1];
438 math_wr_ptr->m_length_offset =
439 (2 << PK_Cmd_Length_Shift) | offset[2];
440 math_wr_ptr->a_length_offset =
441 (1 << PK_Cmd_Length_Shift) | (offset[3] + X_length - 1);
443 /* Command 4 */
444 /* Construct a command for the operation cX = -t mod 2^128 to Slot 0 */
445 math_wr_ptr++;
446 math_wr_ptr->opcode_si = PK_Cmd_Minus_A_Mod_M;
447 math_wr_ptr->r_offset = offset[0];
448 math_wr_ptr->m_length_offset =
449 (2 << PK_Cmd_Length_Shift) | offset[2];
450 math_wr_ptr->a_length_offset =
451 (1 << PK_Cmd_Length_Shift) | (offset[1] + 1);
453 /* Command 5 */
454 /* Construct a command to store cX (second digit of previous result) */
455 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
456 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R;
457 if (lastCmdBlock == N8_TRUE)
459 ldst_wr_ptr->opcode_si |= PK_Cmd_SI_Mask;
461 ldst_wr_ptr->r_offset = offset[0] + 1;
462 ldst_wr_ptr->data_addr_ls = result_a;
463 ldst_wr_ptr->data_length = PK_Bytes_Per_BigNum_Digit;
465 /* save next address for future use */
466 *next_cb_pp = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
468 DBG_PRINT_PK_CMD_BLOCKS("Compute CX",
469 cb_p,
470 N8_CB_COMPUTE_CX_NUMCMDS);
472 } while (FALSE);
474 return ret;
476 } /* computeCX */
479 /*****************************************************************************
480 * cb_computeRmodX
481 *****************************************************************************/
482 /** @ingroup cb_rsa
483 * @brief Creates the command blocks to compute the value for R mod X.
486 * @param req_p RW: Pointer to command
487 * blocks.
488 * @param X RO: Physical address of X.
489 * @param result_a WO: Physical address of result
490 * @param key_length_bytes RO: Length of X in bytes
492 * @return
493 * returnResult - returns N8_STATUS_OK if successful or Error value.
495 * @par Errors
496 * N8_MALLOC_FAILED - memory allocation failed<BR>
498 * @par Assumptions
499 * None.<br>
500 *****************************************************************************/
501 N8_Status_t cb_computeRmodX(const API_Request_t *req_p,
502 const uint32_t X,
503 const uint32_t result_a,
504 const unsigned int key_length_bytes,
505 PK_CMD_BLOCK_t *cb_p,
506 PK_CMD_BLOCK_t **next_cb_pp,
507 int lastCmdBlock)
509 PK_CMD_BLOCK_t *math_wr_ptr;
510 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
512 uint32_t key_length = BYTES_TO_PKDIGITS(key_length_bytes);
513 uint32_t offset0 = 0;
514 uint32_t offset1 = key_length;
515 N8_Status_t ret = N8_STATUS_OK;
519 /* Compute R mod X */
520 /* 1: Construct a command to load X */
521 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
522 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
523 ldst_wr_ptr->r_offset = offset1;
524 ldst_wr_ptr->data_addr_ls = X;
525 ldst_wr_ptr->data_length = key_length_bytes;
527 /* 2: Construct a command for the operation R mod X */
528 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
529 math_wr_ptr->opcode_si = PK_Cmd_R_Mod_M;
530 math_wr_ptr->r_offset = offset0;
531 math_wr_ptr->m_length_offset =
532 (key_length << PK_Cmd_Length_Shift) | offset1;
534 /* 3: Construct a command to store R mod p */
535 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
536 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R;
537 if (lastCmdBlock == N8_TRUE)
539 ldst_wr_ptr->opcode_si |= PK_Cmd_SI_Mask;
541 ldst_wr_ptr->r_offset = offset0;
542 ldst_wr_ptr->data_addr_ls = result_a;
543 ldst_wr_ptr->data_length = key_length_bytes;
545 /* save next address for future use */
546 *next_cb_pp = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
548 DBG_PRINT_PK_CMD_BLOCKS("Compute R mod X",
549 cb_p,
550 N8_CB_COMPUTE_RMODX_NUMCMDS);
551 } while (FALSE);
553 return ret;
554 } /* compute RmodX */
556 N8_Status_t cb_exponentiate(API_Request_t *req_p,
557 const uint32_t origMsg_a,
558 const uint32_t modulus_a,
559 const unsigned int modulus_length_bytes,
560 const uint32_t exponent_a,
561 const unsigned int exp_length_bytes,
562 const uint32_t result_a,
563 PK_CMD_BLOCK_t *cb_p,
564 const N8_Unit_t unitID)
566 PK_CMD_BLOCK_t *math_wr_ptr;
567 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
568 uint32_t modulus_length_digits;
569 uint32_t exp_length_digits;
570 uint32_t offset[7];
571 unsigned int i;
572 N8_Status_t ret = N8_STATUS_OK;
576 modulus_length_digits = BYTES_TO_PKDIGITS(modulus_length_bytes);
577 exp_length_digits = BYTES_TO_PKDIGITS(exp_length_bytes);
579 DBG(("constructing exponentiate command blocks\n"));
582 * Initialize the offset values. These are to address temporary
583 * storage in the BNC. The offsets accomodate operand sizes up to
584 * the key length
586 * The BNC layout will look like the following:
588 * -----------------------------------
589 * 0: n, results
590 * -----------------------------------
591 * 1: R mod n , o * Rmodn mod n
592 * -----------------------------------
593 * 2: o (original message)
594 * -----------------------------------
595 * 3: exponent
596 * -----------------------------------
597 * 4: 2**128
598 * -----------------------------------
599 * 5: cn
600 * -----------------------------------
601 * 6: t
602 * -----------------------------------
604 * Slots 0-2 are of width |n|, the modulus length in BNC digits.
605 * Slot 3 is width |e|, the exponent length in BNC digits.
606 * Slots 4-6 are of width 2.
609 for (i = 0; i < 4; i++)
611 offset[i] = i * modulus_length_digits;
613 for (i = 0; i < 3; i++)
615 offset[i+4] = offset[3] + exp_length_digits + i * 2;
618 /* 1) Compute R mod n. */
620 /* Construct a command to load n to Slot 0 */
621 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
622 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
623 ldst_wr_ptr->r_offset = offset[0];
624 ldst_wr_ptr->data_addr_ls = modulus_a;
625 ldst_wr_ptr->data_length = modulus_length_bytes;
627 /* Construct a command for the operation R mod n to Slot 1 */
628 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
629 math_wr_ptr->opcode_si = PK_Cmd_R_Mod_M;
630 math_wr_ptr->r_offset = offset[1];
631 math_wr_ptr->m_length_offset = (modulus_length_digits << PK_Cmd_Length_Shift) | offset[0];
634 * 2) Compute cn = -(n[0]^-1 mod 2^128) mod 2^128
635 * n is already loaded in Slot 0
639 * Construct a command to load a
640 * 2-digit 2^128 to Slot 4
642 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
643 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
644 ldst_wr_ptr->r_offset = offset[4];
645 ldst_wr_ptr->data_addr_ls = bnc_2_D_ga;
646 ldst_wr_ptr->data_length = PKDIGITS_TO_BYTES(2);
648 /* Construct a command for the operation t = n[0]^-1 mod 2^128 to Slot 6 */
649 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
650 math_wr_ptr->opcode_si = PK_Cmd_Inverse_A_Mod_M;
651 math_wr_ptr->r_offset = offset[6];
652 math_wr_ptr->m_length_offset =
653 (2 << PK_Cmd_Length_Shift) | offset[4];
654 math_wr_ptr->a_length_offset =
655 (1 << PK_Cmd_Length_Shift) | (offset[0] + modulus_length_digits - 1);
657 /* Construct a command for the operation cn = -t mod 2^128 to Slot 5*/
658 math_wr_ptr++;
659 math_wr_ptr->opcode_si = PK_Cmd_Minus_A_Mod_M;
660 math_wr_ptr->r_offset = offset[5];
661 math_wr_ptr->m_length_offset =
662 (2 << PK_Cmd_Length_Shift) | offset[4];
663 math_wr_ptr->a_length_offset =
664 (1 << PK_Cmd_Length_Shift) | (offset[6] + 1);
667 * 3) Compute o * R mod n (mod n)
670 /* Construct a command to load the original message to Slot 2*/
671 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
672 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
673 ldst_wr_ptr->r_offset = offset[2];
674 ldst_wr_ptr->data_addr_ls = origMsg_a;
675 ldst_wr_ptr->data_length = modulus_length_bytes;
677 /* Construct a command for the operation o * Rmodn mod n to Slot 1*/
678 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
679 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
680 math_wr_ptr->r_offset = offset[1];
681 math_wr_ptr->m_length_offset =
682 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[0]; /* n */
683 math_wr_ptr->a_length_offset =
684 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[2]; /* o */
685 math_wr_ptr->b_length_offset =
686 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1]; /* R mod n */
689 * 4) Compute o^e mod n
692 /* Construct a command to load e to Slot 3 */
693 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
694 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
695 ldst_wr_ptr->r_offset = offset[3];
696 ldst_wr_ptr->data_addr_ls = exponent_a;
697 ldst_wr_ptr->data_length = exp_length_bytes;
699 /* Construct a command for the operation o^e mod n to Slot 0 */
700 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
701 math_wr_ptr->opcode_si = PK_Cmd_Exp_G_Mod_M;
702 math_wr_ptr->r_offset = offset[0];
703 math_wr_ptr->m_length_offset =
704 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[0]; /* n */
705 math_wr_ptr->a_length_offset =
706 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1]; /* o * R mod n */
707 math_wr_ptr->b_length_offset = (exp_length_digits << PK_Cmd_Length_Shift) | offset[3]; /* exponent */
708 math_wr_ptr->c_offset = offset[5] + 1; /* cn */
710 /* Construct a command to store o^e mod n */
711 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
712 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R | PK_Cmd_SI_Mask;
713 ldst_wr_ptr->r_offset = offset[0];
714 ldst_wr_ptr->data_addr_ls = result_a;
715 ldst_wr_ptr->data_length = modulus_length_bytes;
717 DBG_PRINT_PK_CMD_BLOCKS("rsa exponentiate",
718 req_p->PK_CommandBlock_ptr,
719 N8_CB_EXPONENTIATE_NUMCMDS);
720 } while (FALSE);
721 return ret;
722 } /* n8_cb_exponentiate */
724 static N8_Status_t cb_exp_with_precomputes(API_Request_t *req_p,
725 const uint32_t origMsg_a,
726 const uint32_t modulus_a,
727 const unsigned int modulus_length_bytes,
728 const uint32_t exponent_a,
729 const unsigned int exp_length_bytes,
730 const uint32_t cn_a,
731 const uint32_t R_mod_n_a,
732 const uint32_t result_a,
733 PK_CMD_BLOCK_t *cb_p,
734 const N8_Unit_t unitID)
736 PK_CMD_BLOCK_t *math_wr_ptr;
737 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
738 uint32_t modulus_length_digits;
739 uint32_t exp_length_digits;
740 uint32_t offset[6];
741 int i;
742 N8_Status_t ret = N8_STATUS_OK;
746 modulus_length_digits = BYTES_TO_PKDIGITS(modulus_length_bytes);
747 exp_length_digits = BYTES_TO_PKDIGITS(exp_length_bytes);
749 DBG(("constructing exponentiate with precomputes command blocks\n"));
752 * Initialize the offset values. These are to address temporary
753 * storage in the BNC. The offsets accomodate operand sizes up to
754 * the key length
757 for (i = 0; i < sizeof(offset)/sizeof(unsigned int); i++)
759 offset[i] = i * modulus_length_digits;
763 * 1) Construct a command to load n to offset[1]
765 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
766 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
767 ldst_wr_ptr->r_offset = offset[1];
768 ldst_wr_ptr->data_addr_ls = modulus_a;
769 ldst_wr_ptr->data_length = modulus_length_bytes;
772 * 2) Load R mod n to offset[2]
774 ldst_wr_ptr++;
775 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
776 ldst_wr_ptr->r_offset = offset[2];
777 ldst_wr_ptr->data_addr_ls = R_mod_n_a;
778 ldst_wr_ptr->data_length = modulus_length_bytes;
781 * 3) Load cn to offset[3]
783 ldst_wr_ptr++;
784 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
785 ldst_wr_ptr->r_offset = offset[3];
786 ldst_wr_ptr->data_addr_ls = cn_a;
787 ldst_wr_ptr->data_length = PK_RSA_CN_Byte_Length;
790 * Compute o * R mod n (mod n)
794 * 4) Construct a command to load the original message to offset[5]
796 ldst_wr_ptr++;
797 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
798 ldst_wr_ptr->r_offset = offset[5];
799 ldst_wr_ptr->data_addr_ls = origMsg_a;
800 ldst_wr_ptr->data_length = modulus_length_bytes;
803 * 5) Construct a command for the operation o * Rmodn mod n to offset[2]
805 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
806 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
807 math_wr_ptr->r_offset = offset[2];
808 math_wr_ptr->m_length_offset =
809 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1];
810 math_wr_ptr->a_length_offset =
811 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[5];
812 math_wr_ptr->b_length_offset =
813 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[2];
816 * Compute o^e mod n
820 * 6) Construct a command to load e to offset[4]
822 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
823 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
824 ldst_wr_ptr->r_offset = offset[4];
825 ldst_wr_ptr->data_addr_ls = exponent_a;
826 ldst_wr_ptr->data_length = exp_length_bytes;
829 * 7) Construct a command for the operation o^e mod n to offset[0]
831 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
832 math_wr_ptr->opcode_si = PK_Cmd_Exp_G_Mod_M;
833 math_wr_ptr->r_offset = offset[0];
834 math_wr_ptr->m_length_offset =
835 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1];
836 math_wr_ptr->a_length_offset =
837 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[2];
838 math_wr_ptr->b_length_offset = (exp_length_digits << PK_Cmd_Length_Shift) | offset[4];
839 math_wr_ptr->c_offset = offset[3];
842 * 8) Construct a command to store o^e mod n from offset[0]
844 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
845 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R | PK_Cmd_SI_Mask;
846 ldst_wr_ptr->r_offset = offset[0];
847 ldst_wr_ptr->data_addr_ls = result_a;
848 ldst_wr_ptr->data_length = modulus_length_bytes;
850 DBG_PRINT_PK_CMD_BLOCKS("rsa exponentiate with precomputes",
851 req_p->PK_CommandBlock_ptr,
852 N8_CB_RSA_ENCRYPT_NUMCMDS);
853 } while (FALSE);
854 return ret;
855 } /* cb_exponentiate_with_precomputes */
857 /*****************************************************************************
858 * cb_rsaEncrypt
859 *****************************************************************************/
860 /** @ingroup cb_rsa
861 * @brief Takes an incoming message and encrypts it via exponentiation with
862 * the public key.
864 * @param req_p RW: Pointer to command
865 * blocks.
866 * @param key RO: Key object with precomputed values for
867 * speedier computation
868 * @param origMsg RO: Physical address of original message.
869 * @param result_a WO: Physical address of result
871 * @return
872 * returnResult - returns N8_STATUS_OK if successful or Error value.
874 * @par Errors
875 * N8_MALLOC_FAILED - memory allocation failed<BR>
877 * @par Assumptions
878 * None.<br>
879 *****************************************************************************/
880 N8_Status_t cb_rsaEncrypt(API_Request_t *req_p,
881 const N8_RSAKeyObject_t *key_p,
882 const uint32_t origMsg_a,
883 const uint32_t result_a,
884 PK_CMD_BLOCK_t *cb_p,
885 const N8_Unit_t unitID)
887 /* To compute an encryption of the plaintext using the recipients public key,
888 * a simple exponentiation is required.
889 * cipher_text = plain_text ** public_key mod n.
891 return cb_exp_with_precomputes(req_p, /* API request pointer */
892 origMsg_a, /* plain text */
893 key_p->n, /* modulus */
894 key_p->privateKeyLength, /* modulus length */
895 key_p->key, /* public key */
896 key_p->publicKeyLength, /* public key length */
897 key_p->cn, /* precomputed cn */
898 key_p->R_mod_n, /* precomputed R mod n */
899 result_a, /* result buffer */
900 cb_p, /* command block pointer */
901 unitID); /* chip ID */
905 /*****************************************************************************
906 * cb_rsaDecrypt
907 *****************************************************************************/
908 /** @ingroup cb_rsa
909 * @brief Takes an incoming message and decrypts it by using the PKE RSA
910 * private function
912 * @param req_p RW: Pointer to command
913 * blocks.
914 * @param key RO: Key object with precomputed values for
915 * speedier computation
916 * @param origMsg RO: Physical address of original message.
917 * @param result_a WO: Physical address of result
919 * @return
920 * returnResult - returns N8_STATUS_OK if successful or Error value.
922 * @par Errors
923 * N8_MALLOC_FAILED - memory allocation failed<BR>
925 * @par Assumptions
926 * None.<br>
927 *****************************************************************************/
928 N8_Status_t cb_rsaDecrypt(API_Request_t *req_p,
929 const N8_RSAKeyObject_t *key_p,
930 const uint32_t origMsg_a,
931 const uint32_t result_a,
932 PK_CMD_BLOCK_t *cb_p,
933 const N8_Unit_t unitID)
935 PK_RSA_CMD_BLOCK_t *rsa_wr_ptr = NULL;
936 PK_CMD_BLOCK_t *math_wr_ptr = NULL;
937 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr = NULL;
938 uint32_t key_length;
939 uint32_t half_key_length;
940 uint32_t key_length_bytes;
941 uint32_t sks_word;
942 N8_Status_t ret = N8_STATUS_OK;
943 uint32_t paramBlockOffset;
944 unsigned int offset[3];
945 uint32_t i;
946 uint32_t p_offset;
947 uint32_t q_offset;
948 uint32_t n_offset;
949 uint32_t dp_offset;
950 uint32_t dq_offset;
951 uint32_t cp_offset;
952 uint32_t cq_offset;
953 uint32_t rmodp_offset;
954 uint32_t rmodq_offset;
955 uint32_t u_offset;
959 /* If the key type is N8_PRIVATE, we are to do a private decrypt without
960 * the knowledge of p and q, thus we cannot utilize the Chinese Remainder
961 * Theorem algorithm. Instead we must simply compute the plaintext using:
962 * plain = msg ** private_key mod n.
964 if (key_p->keyType == N8_PRIVATE)
966 return cb_exponentiate(req_p, /* API request pointer */
967 origMsg_a, /* cipher text */
968 key_p->n, /* modulus */
969 key_p->privateKeyLength, /* modulus length */
970 key_p->key, /* private key */
971 key_p->privateKeyLength, /* private key length */
972 result_a, /* result buffer */
973 cb_p, /* command block pointer */
974 unitID);
976 key_length_bytes = key_p->privateKeyLength;
977 key_length = BYTES_TO_PKDIGITS(key_length_bytes);
978 half_key_length = BYTES_TO_PKDIGITS(key_length_bytes/2);
980 for (i = 0; i < sizeof(offset)/sizeof(unsigned int); i++)
982 offset[i] = i * key_length;
984 /* set up the offsets */
985 paramBlockOffset = offset[2];
986 p_offset = paramBlockOffset + PK_RSA_P_Param_Offset(key_p);
987 q_offset = paramBlockOffset + PK_RSA_Q_Param_Offset(key_p);
988 n_offset = paramBlockOffset + PK_RSA_N_Param_Offset(key_p);
989 dp_offset = paramBlockOffset + PK_RSA_DP_Param_Offset(key_p);
990 dq_offset = paramBlockOffset + PK_RSA_DQ_Param_Offset(key_p);
991 cp_offset = paramBlockOffset + PK_RSA_CP_Param_Offset(key_p);
992 cq_offset = paramBlockOffset + PK_RSA_CQ_Param_Offset(key_p);
993 rmodp_offset = paramBlockOffset + PK_RSA_R_MOD_P_Param_Offset(key_p);
994 rmodq_offset = paramBlockOffset + PK_RSA_R_MOD_Q_Param_Offset(key_p);
995 u_offset = paramBlockOffset + PK_RSA_U_Param_Offset(key_p);
997 /* 1: Construct a command to load the original message */
998 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
999 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
1000 ldst_wr_ptr->r_offset = offset[0];
1001 ldst_wr_ptr->data_addr_ls = origMsg_a;
1002 ldst_wr_ptr->data_length = key_length_bytes;
1004 if (key_p->keyType != N8_PRIVATE_SKS)
1006 /* 2: Construct a command to load the RSA parameter block */
1007 ldst_wr_ptr++;
1008 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
1009 ldst_wr_ptr->r_offset = paramBlockOffset;
1010 ldst_wr_ptr->data_addr_ls = key_p->paramBlock;
1011 ldst_wr_ptr->data_length = PK_RSA_Param_Byte_Length(key_p);
1012 sks_word = PK_Cmd_N_Mask;
1014 else
1016 /* we are using the sks. set the sks_word variable to the correct
1017 * offset */
1018 sks_word = key_p->SKSKeyHandle.sks_offset;
1021 if (key_p->keyType == N8_PRIVATE_SKS ||
1022 cb_RSAOperationSupported(key_p))
1024 /* 2: Construct a command for the RSA operation */
1025 rsa_wr_ptr = (PK_RSA_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
1026 ZERO_CMD_BLOCK(rsa_wr_ptr);
1027 rsa_wr_ptr->opcode_si = PK_Cmd_RSA_Private_Key_Op;
1028 rsa_wr_ptr->sks = ((key_length) << PK_Cmd_Key_Length_Shift) | sks_word;
1030 /* Set up the ldst pointer for the next command. */
1031 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (rsa_wr_ptr + 1);
1033 else
1035 /* 3: o = i mod p */
1036 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
1037 math_wr_ptr->opcode_si = PK_Cmd_A_Mod_M;
1038 math_wr_ptr->r_offset = offset[1];
1039 math_wr_ptr->m_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | p_offset;
1040 math_wr_ptr->a_length_offset = (key_length << PK_Cmd_Length_Shift) | offset[0];
1042 /* 4: o = (o * R mod p) mod p */
1043 math_wr_ptr++;
1044 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
1045 math_wr_ptr->r_offset = offset[1];
1046 math_wr_ptr->m_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | p_offset;
1047 math_wr_ptr->a_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | offset[1];
1048 math_wr_ptr->b_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | rmodp_offset;
1050 /* 5: dp = o ^ dp mod p */
1051 math_wr_ptr++;
1052 math_wr_ptr->opcode_si = PK_Cmd_Exp_G_Mod_M;
1053 math_wr_ptr->r_offset = dp_offset;
1054 math_wr_ptr->m_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | p_offset;
1055 math_wr_ptr->a_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | offset[1];
1056 math_wr_ptr->b_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | dp_offset;
1057 math_wr_ptr->c_offset = cp_offset;
1059 /* 6: o = i mod q */
1060 math_wr_ptr++;
1061 math_wr_ptr->opcode_si = PK_Cmd_A_Mod_M;
1062 math_wr_ptr->r_offset = offset[1];
1063 math_wr_ptr->m_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | q_offset;
1064 math_wr_ptr->a_length_offset = (key_length << PK_Cmd_Length_Shift) | offset[0];
1066 /* 7: o = o * R mod q (mod q) */
1067 math_wr_ptr++;
1068 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
1069 math_wr_ptr->r_offset = offset[1];
1070 math_wr_ptr->m_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | q_offset;
1071 math_wr_ptr->a_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | offset[1];
1072 math_wr_ptr->b_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | rmodq_offset;
1074 /* 8: dq = o ^ dq mod q */
1075 math_wr_ptr++;
1076 math_wr_ptr->opcode_si = PK_Cmd_Exp_G_Mod_M;
1077 math_wr_ptr->r_offset = dq_offset;
1078 math_wr_ptr->m_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | q_offset;
1079 math_wr_ptr->a_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | offset[1];
1080 math_wr_ptr->b_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | dq_offset;
1081 math_wr_ptr->c_offset = cq_offset;
1083 /* 9: o = dq - dp mod q */
1084 math_wr_ptr++;
1085 math_wr_ptr->opcode_si = PK_Cmd_A_Minus_B_Mod_M;
1086 math_wr_ptr->r_offset = offset[1];
1087 math_wr_ptr->m_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | q_offset;
1088 math_wr_ptr->a_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | dq_offset;
1089 math_wr_ptr->b_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | dp_offset;
1091 /* 10: o = o * u mod q */
1092 math_wr_ptr++;
1093 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
1094 math_wr_ptr->r_offset = offset[1];
1095 math_wr_ptr->m_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | q_offset;
1096 math_wr_ptr->a_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | offset[1];
1097 math_wr_ptr->b_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | u_offset;
1099 /* 11: o = o * p mod n */
1100 math_wr_ptr++;
1101 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
1102 math_wr_ptr->r_offset = offset[1];
1103 math_wr_ptr->m_length_offset = (key_length << PK_Cmd_Length_Shift) | n_offset;
1104 math_wr_ptr->a_length_offset = (key_p->qDigits << PK_Cmd_Length_Shift) | offset[1];
1105 math_wr_ptr->b_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | p_offset;
1107 /* 12: o = o + dp mod n */
1108 math_wr_ptr++;
1109 math_wr_ptr->opcode_si = PK_Cmd_A_Plus_B_Mod_M;
1110 math_wr_ptr->r_offset = offset[1];
1111 math_wr_ptr->m_length_offset = (key_length << PK_Cmd_Length_Shift) | n_offset;
1112 math_wr_ptr->a_length_offset = (key_length << PK_Cmd_Length_Shift) | offset[1];
1113 math_wr_ptr->b_length_offset = (key_p->pDigits << PK_Cmd_Length_Shift) | dp_offset;
1115 /* Set up the ldst pointer for the next command. */
1116 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
1118 /* 3/13: Construct a command to store r */
1119 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R | PK_Cmd_SI_Mask;
1120 ldst_wr_ptr->r_offset = offset[1];
1121 ldst_wr_ptr->data_addr_ls = result_a;
1122 ldst_wr_ptr->data_length = key_length_bytes;
1124 DBG_PRINT_PK_CMD_BLOCKS("rsa decrypt",
1125 (PK_CMD_BLOCK_t *) req_p->PK_CommandBlock_ptr,
1126 N8_CB_RSA_DECRYPT_NUMCMDS(key_p));
1128 } while (FALSE);
1130 return ret;
1132 } /* rsaDecrypt */
1134 /*****************************************************************************
1135 * cb_RSADecryptOperations
1136 *****************************************************************************/
1137 /** @ingroup cb_rsa
1138 * @brief Calculate the number of operations required for an RSA Decrypt.
1140 * The operations used to perform an RSA Decrypt depend upon the key type and
1141 * the lengths of p, q, and the private key. If the type is N8_PRIVATE_SKS,
1142 * then the RSA Operation can be used and the data is taken from the SKS, saving
1143 * a load. If it is not SKS and len(p) == len(q) AND len(p) + len(q) ==
1144 * len(private key), then the RSA Operation can be used. If the above does not
1145 * hold, then this presents a situation where the RSA Operation does not work
1146 * and the command blocks must be generated by hand.
1148 * @param key_p RO: Pointer to the key object.
1150 * @par Externals
1151 * None
1153 * @return
1154 * number of commands necessary
1156 * @par Errors
1157 * None
1159 * @par Assumptions
1160 * The key pointer is valid. We assume this has been checked by the API.
1161 *****************************************************************************/
1162 unsigned int cb_RSADecryptOperations(const N8_RSAKeyObject_t *key_p)
1164 unsigned int ret = 0;
1165 const unsigned int USING_SKS_NUM_CMDS = 3;
1166 const unsigned int USING_RSA_OPERATION_NUM_CMDS = 4;
1167 const unsigned int USING_RSA_WORKAROUND_NUM_CMDS = 13;
1169 if (key_p->keyType == N8_PRIVATE_SKS)
1171 ret = USING_SKS_NUM_CMDS;
1173 else if (key_p->keyType == N8_PRIVATE)
1175 ret = N8_CB_EXPONENTIATE_NUMCMDS;
1177 else if (cb_RSAOperationSupported(key_p))
1179 ret = USING_RSA_OPERATION_NUM_CMDS;
1181 else
1183 ret = USING_RSA_WORKAROUND_NUM_CMDS;
1185 return ret;
1186 } /* cb_RSADecryptOperations */
1188 /*****************************************************************************
1189 * cb_rsaPublicDecrypt
1190 *****************************************************************************/
1191 /** @ingroup cb_rsa
1192 * @brief Creates the command blocks to compute a public decrypt for
1193 * openssl. This command computes the pre-computes ComputeCX and
1194 * ComputeRmodX and then performs the exponentiation
1196 * @param req_p RO: Pointer to request
1197 * @param modulus RO: modulus (n)
1198 * @param modulus_length_bytes RO: length of modulus in bytes
1199 * @param origMsg_a RO: Physical address of original message
1200 * @param result_a RO: Physical address of result buffer
1201 * @param exponent_a RO: Physical address of exponent (key)
1202 * @param exp_length_bytes RO: length of exponent in bytes
1203 * @param cb_p WO: command block pointer
1204 * @param unitID RO: execution unit identifier
1206 * @return
1207 * returnResult - returns N8_STATUS_OK if successful or Error value.
1209 * @par Errors
1210 * N8_INVALID_OBJECT - command block pointer is NULL<BR>
1211 * N8_MALLOC_FAILED - memory allocation failed<BR>
1213 * @par Assumptions
1214 * None.<br>
1215 *****************************************************************************/
1216 N8_Status_t cb_rsaPublicDecrypt(const API_Request_t *req_p,
1217 const uint32_t modulus,
1218 const unsigned int modulus_length_bytes,
1219 const uint32_t origMsg_a,
1220 const uint32_t result_a,
1221 const uint32_t exponent_a,
1222 const unsigned int exp_length_bytes,
1223 PK_CMD_BLOCK_t *cb_p,
1224 const N8_Unit_t unitID)
1227 PK_CMD_BLOCK_t *math_wr_ptr;
1228 PK_LDST_CMD_BLOCK_t *ldst_wr_ptr;
1230 uint32_t modulus_length_digits;
1231 uint32_t exp_length_digits;
1232 uint32_t offset[6];
1234 N8_Status_t ret = N8_STATUS_OK;
1235 unsigned int i;
1239 * Initialize the offset values. These are to address temporary
1240 * storage in the BNC. The offsets accomodate operand sizes up to
1241 * the key length
1243 * The BNC layout will look like the following:
1245 * -----------------------------------
1246 * 0: results 2 digits
1247 * -----------------------------------
1248 * 1: t = p[0]^-1 2 digits
1249 * -----------------------------------
1250 * 2: 2**128 2 digits
1251 * -----------------------------------
1252 * 3: p modulus_length
1253 * -----------------------------------
1256 modulus_length_digits = BYTES_TO_PKDIGITS(modulus_length_bytes);
1257 exp_length_digits = BYTES_TO_PKDIGITS(exp_length_bytes);
1260 * Initialize the offset values. These are to address temporary
1261 * storage in the BNC. The offsets accomodate operand sizes up to
1262 * the key length
1264 for (i = 0; i < sizeof(offset)/sizeof(unsigned int); i++)
1266 offset[i] = i * modulus_length_digits;
1269 /* 1. Compute cX = -(p[0]^-1 mod 2^128) mod 2^128 */
1270 /* 2. Compute R mod X */
1271 /* 3. Compute o * Rmodn mod n */
1273 /*Note - offset and slot mean the same thing */
1277 * 1) Construct a command to load n to slot[1]
1279 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) cb_p;
1280 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
1281 ldst_wr_ptr->r_offset = offset[1];
1282 ldst_wr_ptr->data_addr_ls = modulus;
1283 ldst_wr_ptr->data_length = modulus_length_bytes;
1285 /* Command 2 */
1286 /* Construct a command to load a 2-digit 2^128 to Slot 2*/
1287 ldst_wr_ptr++;
1288 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
1289 ldst_wr_ptr->r_offset = offset[2];
1290 ldst_wr_ptr->data_addr_ls = bnc_2_D_ga;
1291 ldst_wr_ptr->data_length = PKDIGITS_TO_BYTES(2);
1293 /* Command 3 */
1294 /* Construct a command for the operation t = n[0]^-1 mod 2^128 to Slot 3 */
1295 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
1296 math_wr_ptr->opcode_si = PK_Cmd_Inverse_A_Mod_M;
1297 math_wr_ptr->r_offset = offset[3];
1298 math_wr_ptr->m_length_offset =
1299 (2 << PK_Cmd_Length_Shift) | offset[2];
1300 math_wr_ptr->a_length_offset =
1301 (1 << PK_Cmd_Length_Shift) | (offset[1] + modulus_length_digits - 1);
1303 /* Command 4 */
1304 /* Construct a command for the operation cX = -t mod 2^128 to Slot 3 */
1305 math_wr_ptr++;
1306 math_wr_ptr->opcode_si = PK_Cmd_Minus_A_Mod_M;
1307 math_wr_ptr->r_offset = offset[3];
1308 math_wr_ptr->m_length_offset =
1309 (2 << PK_Cmd_Length_Shift) | offset[2];
1310 math_wr_ptr->a_length_offset =
1311 (1 << PK_Cmd_Length_Shift) | (offset[3] + 1);
1313 /* 5: Construct a command for the operation R mod X */
1314 /* math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1); */
1315 math_wr_ptr++;
1316 math_wr_ptr->opcode_si = PK_Cmd_R_Mod_M;
1317 math_wr_ptr->r_offset = offset[2];
1318 math_wr_ptr->m_length_offset =
1319 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1];
1322 * Compute o * R mod n (mod n)
1326 * 6) Construct a command to load the original message to offset[0]
1328 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
1329 /* ldst_wr_ptr++; */
1330 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
1331 ldst_wr_ptr->r_offset = offset[0];
1332 ldst_wr_ptr->data_addr_ls = origMsg_a;
1333 ldst_wr_ptr->data_length = modulus_length_bytes;
1336 * 7) Construct a command for the operation o * Rmodn mod n to offset[0]
1338 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
1339 math_wr_ptr->opcode_si = PK_Cmd_AB_Mod_M;
1340 math_wr_ptr->r_offset = offset[0];
1341 math_wr_ptr->m_length_offset =
1342 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1];
1343 math_wr_ptr->a_length_offset =
1344 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[0];
1345 math_wr_ptr->b_length_offset =
1346 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[2];
1349 * Compute o^e mod n
1353 * 8) Construct a command to load e to offset[4]
1355 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
1356 ldst_wr_ptr->opcode_si = PK_Cmd_Load_R;
1357 ldst_wr_ptr->r_offset = offset[4];
1358 ldst_wr_ptr->data_addr_ls = exponent_a;
1359 ldst_wr_ptr->data_length = exp_length_bytes;
1362 * 9) Construct a command for the operation o^e mod n to offset[0]
1364 math_wr_ptr = (PK_CMD_BLOCK_t *) (ldst_wr_ptr + 1);
1365 math_wr_ptr->opcode_si = PK_Cmd_Exp_G_Mod_M;
1366 math_wr_ptr->r_offset = offset[0];
1367 math_wr_ptr->m_length_offset =
1368 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[1];
1369 math_wr_ptr->a_length_offset =
1370 (modulus_length_digits << PK_Cmd_Length_Shift) | offset[0];
1371 math_wr_ptr->b_length_offset = (exp_length_digits << PK_Cmd_Length_Shift) | offset[4];
1372 /* take the least significant digit of the cn result */
1373 math_wr_ptr->c_offset = offset[3]+1;
1376 * 10) Construct a command to store o^e mod n from offset[0]
1378 ldst_wr_ptr = (PK_LDST_CMD_BLOCK_t *) (math_wr_ptr + 1);
1379 ldst_wr_ptr->opcode_si = PK_Cmd_Store_R | PK_Cmd_SI_Mask;
1380 ldst_wr_ptr->r_offset = offset[0];
1381 ldst_wr_ptr->data_addr_ls = result_a;
1382 ldst_wr_ptr->data_length = modulus_length_bytes;
1384 DBG_PRINT_PK_CMD_BLOCKS("compute public precompute whaley-style",
1385 req_p->PK_CommandBlock_ptr,
1386 10);
1387 } while (FALSE);
1388 return ret;
1389 } /* cb_compute_public_decrypt */
1391 /**************************************************
1392 * Local Functions
1393 **************************************************/
1395 /*****************************************************************************
1396 * allocateBNCConstants
1397 *****************************************************************************/
1398 /** @ingroup cb_rsa
1399 * @brief Sets addresses for constants allocated in kernel space that are
1400 * needed for various commands.
1402 * Some command need one of two constants to be loaded into the BNC. One is the
1403 * constant '1', in a single BNC digit. This is 'bnc_one'. The other is the
1404 * value 2^D where D is the size in bits of a BNC digit. This changes whether
1405 * the actual hardware or FPGA is in use. Note the values needed are:<br>
1406 * bnc_one = 0001 (for the case where D=4)<BR>
1407 * bnc_2_D = 0001 0000<BR>
1408 * We will take advantage of this by allocating two digits and setting the
1409 * values. In actuality, bnc_one and bnc_2_D will point to the same memory but
1410 * the length used will determine the value.
1412 * @param bncAddress RO: address of BNC constants allocated by
1413 * the driver.
1415 * @par Externals
1417 * @return
1418 * Return codes - N8_STATUS_OK
1420 * @par Errors
1422 * @par Assumptions
1423 *****************************************************************************/
1424 N8_Status_t allocateBNCConstants(unsigned long bncAddress)
1426 N8_Status_t ret = N8_STATUS_OK;
1428 bnc_one_ga = bncAddress;
1429 bnc_2_D_ga = bncAddress;
1431 return ret;
1432 } /* allocateBNCConstants */
1434 static N8_Boolean_t cb_RSAOperationSupported(const N8_RSAKeyObject_t *key_p)
1436 N8_Boolean_t ret = N8_FALSE;
1438 if ((key_p->pLength == key_p->qLength) &&
1439 ((key_p->pLength+key_p->qLength) == key_p->privateKeyLength) &&
1440 ((key_p->pDigits+key_p->qDigits) == key_p->privateKeyDigits))
1442 ret = N8_TRUE;
1444 return ret;
1445 } /* RSAOperationSupported */