2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
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>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
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_dh.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
36 /*****************************************************************************/
38 * @brief Public DH functions.
40 * Implementation of all public DH functions.
42 *****************************************************************************/
44 /*****************************************************************************
47 * 05/16/03 brr Fix Bug 902 by allocating a kernel buffer to hold key,
48 * modulus etc. to avoid copies in N8_DHCompute.
49 * 05/30/03 brr Set the structure ID in N8_DHInitializeKey when the key is set
50 * up so the error case frees memory correctly. (Bug 901)
51 * 05/20/02 brr Free the request for all error conditions.
52 * 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support.
53 * 04/09/02 bac A DH key was trying to be freed even though it wasn't
55 * 04/01/02 brr Validate structureID in N8_DHFreeKey before deallocation.
56 * 03/26/02 brr Allocate the data buffer as part of the API request.
57 * 02/28/02 brr Do not include any QMgr include files.
58 * 02/25/02 brr Removed last references to validatedUnit.
59 * 02/20/02 brr Removed references to the queue structure.
60 * 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files.
61 * 11/08/01 mel Added unit ID parameter to commend block calls.
62 * 11/05/01 hml Added the structure verification.
63 * 10/02/01 bac Added use of RESULT_HANDLER_WARNING in all result handlers.
64 * 10/01/01 hml Added multi-unit functionality.
65 * 09/14/01 bac Changes from code review. Added precomputation of gRmodP and
67 * 09/13/01 mel Added event parameter to N8_DHInitializeKey.
68 * 08/29/01 bac Added N8_DHFreeKey method.
69 * 08/24/01 bac Re-worked to correctly initialize the pre-computed values
70 * and calculate the DHCompute correctly. Per (BUG #125),
71 * check valid modulus size at initialization.
72 * 07/31/01 bac Added call to N8_preamble for all public interfaces.
73 * 07/23/01 bac Created new result handler for DHInit and DHCompute.
74 * 07/20/01 bac Changed calls to create__RequestBuffer to pass the chip id.
75 * 07/12/01 bac Added copyright notice.
76 * 07/12/01 bac General cleanup.
77 * 05/22/01 mel Original version.
78 ****************************************************************************/
79 /** @defgroup dh DH Functions.
82 #include "n8_common.h"
83 #include "n8_pub_errors.h"
84 #include "n8_pk_common.h"
85 #include "n8_enqueue_common.h"
87 #include "n8_API_Initialize.h"
91 /**********************************************************************
93 ***********************************************************************/
95 * @brief Initializes the specified DHKeyObject so that it can be used
96 * in Diffie-Hellman operations. The KeyMaterial object (structure)
97 * contains the appropriate group generator g, modulus p, and modulus size.
100 * This call pre-computes various constant values from the supplied
101 * parameters and initializes DHKeyObject with these values. By
102 * pre-computing these values, Diffie-Hellman computations can be done
103 * faster than if these constants must be computed on each operation.
104 * Once a DHKeyObject has been initialized, it can be used repeatedly
105 * in multiple DH operations. It does not ever need to be re-initialized,
106 * unless the actual key value(s) change (i.e., unless the key itself
109 * @param key_p RW: The caller allocated DHKeyObject, initialized
110 * by this call with the appropriate DH key
111 * material and pre-computed DH constants
112 * depending on the value of the KeyType parameter
113 * @param material_p RO: Pointer to the key material to use in initializing
117 * ret - returns N8_STATUS_OK if successful or Error value.
120 * N8_INVALID_OBJECT - DH key or key material object is NULL<BR>
124 **********************************************************************/
125 N8_Status_t
N8_DHInitializeKey(N8_DH_KeyObject_t
*key_p
,
126 N8_DH_KeyMaterial_t
*material_p
,
129 N8_Status_t ret
= N8_STATUS_OK
;
131 API_Request_t
*req_p
= NULL
;
138 CHECK_OBJECT(key_p
, ret
);
139 CHECK_OBJECT(material_p
, ret
);
141 key_p
->unitID
= material_p
->unitID
;
143 /* check the modulus size to ensure it is 1 <= ms <= 512. return
144 * N8_INVALID_SIZE if not. */
145 if (material_p
->modulusSize
< N8_DH_MIN_MODULUS_SIZE
||
146 material_p
->modulusSize
> N8_DH_MAX_MODULUS_SIZE
)
148 ret
= N8_INVALID_KEY_SIZE
;
152 /* Allocate space for the initialized key. we must compute 'R mod p' and 'cp'
153 * for use in subsequent DHComputes. */
154 key_p
->modulusLength
= material_p
->modulusSize
;
155 nBytes
= (NEXT_WORD_SIZE(key_p
->modulusLength
) + /* g */
156 NEXT_WORD_SIZE(key_p
->modulusLength
) + /* p */
157 NEXT_WORD_SIZE(key_p
->modulusLength
) + /* R mod p */
158 NEXT_WORD_SIZE(key_p
->modulusLength
) + /* g R mod p */
159 NEXT_WORD_SIZE(PK_DH_CP_Byte_Length
));/* cp */
161 /* Allocate a kernel buffer to hold data accessed by the NSP2000 */
162 key_p
->kmem_p
= N8_KMALLOC_PK(nBytes
);
163 CHECK_OBJECT(key_p
->kmem_p
, ret
);
164 memset(key_p
->kmem_p
->VirtualAddress
, 0, nBytes
);
166 /* Compute virtual addresses within the kernel buffer */
167 key_p
->g
= (N8_Buffer_t
*) key_p
->kmem_p
->VirtualAddress
;
168 key_p
->p
= key_p
->g
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
169 key_p
->R_mod_p
= key_p
->p
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
170 key_p
->gR_mod_p
= key_p
->R_mod_p
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
171 key_p
->cp
= key_p
->gR_mod_p
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
173 /* Compute physical addresses within the kernel buffer */
174 key_p
->g_a
= key_p
->kmem_p
->PhysicalAddress
;
175 key_p
->p_a
= key_p
->g_a
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
176 key_p
->RmodP_a
= key_p
->p_a
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
177 key_p
->gRmodP_a
= key_p
->RmodP_a
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
178 key_p
->cp_a
= key_p
->gRmodP_a
+ NEXT_WORD_SIZE(key_p
->modulusLength
);
180 /* Set up the memory for p and g and copy from the key material */
181 memcpy(key_p
->p
, material_p
->p
, material_p
->modulusSize
);
182 memcpy(key_p
->g
, material_p
->g
, material_p
->modulusSize
);
184 /* Set the structure ID */
185 key_p
->structureID
= N8_DH_STRUCT_ID
;
187 /* allocate user-space command buffer */
188 ret
= createPKRequestBuffer(&req_p
, key_p
->unitID
,
189 N8_CB_PRECOMPUTE_DHVALUES_NUMCMDS
,
194 ret
= cb_precomputeDHValues(req_p
, key_p
->g_a
, key_p
->p_a
,
195 key_p
->RmodP_a
, key_p
->gRmodP_a
, key_p
->cp_a
,
196 key_p
->modulusLength
,
197 req_p
->PK_CommandBlock_ptr
,
200 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
201 HANDLE_EVENT(event_p
, req_p
, ret
);
205 * Deallocate the request if we arrived from an error condition.
207 if (ret
!= N8_STATUS_OK
)
209 /* free the request */
211 /* free the key also, if it has been allocated */
214 /* ignore the return code as we want to return the original anyway */
215 (void) N8_DHFreeKey(key_p
);
220 } /* N8_DHInitializeKey */
222 /**********************************************************************
224 ***********************************************************************/
226 * @brief Computes a Diffie-Hellman exponentiation as required to compute
227 * Diffie-Hellman public values from a secret value and a Diffie-Hellman
231 * The key or group is specified by DHKeyObject which must have been
232 * previously initialized with the appropriate group generator g, modulus p,
233 * and modulus size by a call to N8_DHInitializeKey. The DH secret value
234 * used as the exponent is specified in XValue, and must be of the same
235 * size as the modulus size in DHKeyObject. GValue specifies the value
236 * to be exponentiated and must also be the same size as the modulus.
237 * GValue may be null, in which case the generator g from DHKeyObject is
238 * used as the GValue. The result of the calculation is returned in
239 * GXValue and is the same size as the modulus. The value computed is
240 * GXValue = ( GValue ** XValue ) mod p. Thus this routine computes a
241 * modular exponentiation.
242 * This call can be used to compute from a private x value the value
243 * X = g**x mod p that is the public X value sent to the other respondent
244 * in a Diffie-Hellman exchange. (In this case the GValue is set to null,
245 * and x is used for XValue.) When the respondent's corresponding Y value
246 * (Y = g**y mod p, y = the respondent's private y) is received, this call
247 * can then be used to compute the common shared secret XY = g**(xy) = YX by
248 * using X for the GValue and the received Y as the XValue.
251 * @param key_p RO: The caller supplied DHKeyObject containing
252 * the appropriate Diffie-Hellman values
253 * and pre-computed DH constants.
254 * @param gValue RO: The value to be raised to a power.
255 * If null, then the generator g value from
256 * DHKeyObject is used. GValue must be the
257 * same size as the modulus p from DHKeyObject.
258 * @param xValue RO: The exponent. Must be supplied. XValue
259 * must be the same size as the
260 * modulus p from DHKeyObject
261 * @param gxValue WO: GValue raised to the XValue power, mod p.
262 * GXValue will be the same
263 * size as the modulus p from DHKeyObject.
264 * @param event_p RW: On input, if null the call is synchronous
265 * and no event is returned. The operation
266 * is complete when the call returns. If
267 * non-null, then the call is asynchronous;
268 * an event is returned that can be used to
269 * determine when the operation completes.
272 * ret - returns N8_STATUS_OK if successful or Error value.
275 * N8_INVALID_OBJECT - context request object is NULL<BR>
276 * N8_INVALID_KEY - The DHKeyObject is not a valid key
278 * for this operation.
281 **********************************************************************/
282 N8_Status_t
N8_DHCompute(N8_DH_KeyObject_t
*key_p
,
283 N8_Buffer_t
*gValue_p
,
284 N8_Buffer_t
*xValue_p
,
285 N8_Buffer_t
*gxValue_p
,
288 N8_Status_t ret
= N8_STATUS_OK
;
289 API_Request_t
*req_p
= NULL
;
302 unsigned int res_len
;
304 N8_Boolean_t useShortCommandBlock
= N8_FALSE
;
310 CHECK_OBJECT(key_p
, ret
);
311 CHECK_OBJECT(xValue_p
, ret
);
312 CHECK_OBJECT(gxValue_p
, ret
);
313 CHECK_STRUCTURE(key_p
->structureID
, N8_DH_STRUCT_ID
, ret
);
315 /* compute the lengths of all of the parameters as a convenience */
316 g_len
= key_p
->modulusLength
;
317 x_len
= key_p
->modulusLength
;
318 res_len
= key_p
->modulusLength
;
320 nBytes
= (NEXT_WORD_SIZE(x_len
) +
321 NEXT_WORD_SIZE(res_len
));
323 /* gValue_p is allowed to be NULL. if so, use the g from the key object. */
324 if (gValue_p
== NULL
)
326 useShortCommandBlock
= N8_TRUE
;
328 /* allocate user-space buffer */
329 ret
= createPKRequestBuffer(&req_p
,
331 N8_CB_COMPUTE_G_XMODP_NUMCMDS_SHORT
,
332 resultHandlerGeneric
, nBytes
);
336 nBytes
+= NEXT_WORD_SIZE(g_len
);
338 /* allocate user-space buffer */
339 ret
= createPKRequestBuffer(&req_p
,
341 N8_CB_COMPUTE_G_XMODP_NUMCMDS_LONG
,
342 resultHandlerGeneric
, nBytes
);
347 /* set up the addressing for the pointers */
348 x_p
= (N8_Buffer_t
*) ((int)req_p
+ req_p
->dataoffset
);
349 x_a
= req_p
->qr
.physicalAddress
+ req_p
->dataoffset
;
350 res_p
= x_p
+ NEXT_WORD_SIZE(x_len
);
351 res_a
= x_a
+ NEXT_WORD_SIZE(x_len
);
353 memcpy(x_p
, xValue_p
, x_len
);
355 req_p
->copyBackSize
= x_len
;
356 req_p
->copyBackFrom_p
= res_p
;
357 req_p
->copyBackTo_p
= gxValue_p
;
359 if (useShortCommandBlock
== N8_TRUE
)
361 ret
= cb_computeGXmodp_short(req_p
,
367 key_p
->modulusLength
,
368 req_p
->PK_CommandBlock_ptr
);
372 /* gValue_p is not NULL, copy the user-space */
373 /* data into our kernel space buffers */
374 g_p
= res_p
+ NEXT_WORD_SIZE(res_len
);
375 g_a
= res_a
+ NEXT_WORD_SIZE(res_len
);
376 memcpy(g_p
, gValue_p
, g_len
);
378 ret
= cb_computeGXmodp_long(req_p
,
385 key_p
->modulusLength
,
386 req_p
->PK_CommandBlock_ptr
);
391 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
392 HANDLE_EVENT(event_p
, req_p
, ret
);
395 DBG(("DH computed\n"));
398 * Deallocate the request if we arrived from an error condition.
400 if (ret
!= N8_STATUS_OK
)
409 /*****************************************************************************
411 *****************************************************************************/
413 * @brief Free an initialized Diffie-Hellman key object
415 * At initialization, the key object has several components allocated. This
416 * method will release those resources. This method should be called when the
417 * key is no longer used. It is the user's responsibility to avoid memory leaks
418 * by invoking this method.
420 * @param key_p RW: Pointer to key object to be freed.
426 * Status: N8_STATUS_OK -- no errors<br>
427 * N8_INVALID_KEY -- the key passed was not a valid key.
430 * No errors are reported except as noted above.
434 *****************************************************************************/
435 N8_Status_t
N8_DHFreeKey(N8_DH_KeyObject_t
*key_p
)
437 N8_Status_t ret
= N8_STATUS_OK
;
444 if ((key_p
== NULL
) || (key_p
->structureID
!= N8_DH_STRUCT_ID
))
446 ret
= N8_INVALID_KEY
;
449 if (key_p
->kmem_p
!= NULL
)
451 N8_KFREE(key_p
->kmem_p
);
452 key_p
->kmem_p
= NULL
;
455 key_p
->structureID
= 0;