Message ID | 1404915613-16330-1-git-send-email-bill.fischofer@linaro.org |
---|---|
State | New |
Headers | show |
On 2014-07-09 09:20, Bill Fischofer wrote: > Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> > --- > crypto_design.dox | 545 ++++++++++++++++++++++++++++++++++++++++++++++++++ > images/syncmodels.png | Bin 0 -> 17179 bytes > 2 files changed, 545 insertions(+) > create mode 100644 crypto_design.dox > create mode 100644 images/syncmodels.png > Hi Bill, Thank you for reworking the patch. I have a couple of comments. 1. @subsubfunction is not a doxygen variable I think you mean: "@subsubsection fucntion Session Creation". Doxygen was warning about that. 2. Should we add Alex Signed-off-by as well to give him credit? 3. Before you send a patch try to apply it your self, git complained see [1] 4. See reference [2] this is a diff of what I had to do to tidy up the patch, can you please do that and resend it. A nit not a blocker: > +typedef struct odp_key_t { > +}odp_key_t; Nothing inside this struct, is that correct? Should there be an explanation why it's empty? Cheers, Anders [1] http://people.linaro.org/~anders.roxell/git_am_crypto_design_doc.txt [2] http://people.linaro.org/~anders.roxell/cleanup_crypto_design_doc.patch > diff --git a/crypto_design.dox b/crypto_design.dox > new file mode 100644 > index 0000000..a46a2db > --- /dev/null > +++ b/crypto_design.dox > @@ -0,0 +1,545 @@ > +/* Copyright (c) 2043, Linaro Limited > + * All rights reserved > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/** > +@page crypto_design ODP Design - Crypto API > +For the implimentation of the ODP crypto API please see @ref odp_crypto.h > + > +@tableofcontents > + > +@section revision_history Revision History > +Revision | Issue Data | Description | Author > +---------|------------|-------------|-------- > +0.1 | 4/9/2014 | Introduction started, Basic Functions | Bill, Alexandru > +0.2 | 4/15/2014 | Completed intro, added TOC, started use cases, miscellaneous formatting, API comments | Bill > +0.3 | 4/22/2014 | Added Use Case section to include results of design discussions held during ODP team calls | Bill > +0.4 | 4/30/2014 | Design review from ODP crypto sprint--action to resolve | Bill > +0.5 | 5/5/2014 | Rewrite incorporating review comments--ready for final review | Bill > +1.0 | 5/30/2014 | Final version for LNG-SC approval | Bill > + > +@section introduction Introduction > +This document describes the ODP Crypto API. Cryptography is an important part of data plane processing as many communication protocols make use of cryptographic functions. > +Moreover, many SoCs incorporate cryptographic hardware that can significantly accelerate these operations compared to their software equivalents as well as provide validated hardware functional correctness and security boundaries necessary for system-level security certifications such as FIPS-140 Level 2 and above. > +@section requirements Requirements > +@subsection use_of_terms Use of Terms > +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119). > +@subsection uses_of_cryptography Uses of Cryptography > +Crypto functions cover a range of uses and capabilities designed to support data security, integrity, authentication, and non-repudiation. > +@subsubsection data_security Data Security > +Cryptography supports data security by making use of complex mathematical transformations that are not feasibly reversible without possession of the secret key used to encrypt message data. > +@subsubsection data_integrity Data Integrity > +Cryptography supports data integrity through the use of cryptographic checksums (also known as secure hashes) that ensure the recipient that message data has not been altered either accidentally or maliciously while in transit. > +@subsubsection data_authentication Data Authentication > +Cryptography supports data authentication through the uses of Message Authentication Codes (MACs) that enable the recipient to verify that a message was sent from an authorized counterparty, and hence was not forged. > +@subsubsection data_non_repudiation Data Non-Repudiation > +Cryptography supports data non-repudiation through the use of digital signatures that enable a recipient or third party to verify the identity of the sending party and prevents the sending party from later denying that they originated a signed message. > +@subsection scope Scope > +ODP crypto support is designed to provide a portable framework for accessing SoC-specific cryptographic functions of most use to the data plane. This is predominantly symmetric crypto operations used to support the encryption and decryption of data at line rate using hardware acceleration and offload. Specifically excluded in this support are public key operations and other crypto functions mainly used in the control plane. > +@subsection cryptographic_operations_in_the_data_plane Cryptographic Operations in the Data Plane > +ODP crypto APIs cover the following areas: > +@subsubsection ciphering Ciphering > +Ciphering refers to mathematical transformations that use a secret key to encipher data, transforming the original data (referred to as plaintext) into ciphertext, thereby making it unintelligible to anyone not in possession of the key. Similarly, ciphering is also used to decipher data, allowing someone in possession of the correct key to transform received ciphertext back into plaintext. Approved block ciphers are listed [here](http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html) and SHOULD be supported by each ODP implementation. > +@subsubsection hasing Hashing > +A hash is a cryptographic digest of a message that can be used to represent it for comparison or integrity checking. Hash functions are designed so that any alteration of a message will alter the hash and that it is computationally infeasible to craft a message that generates the same hash value as another message. Secure hash functions approved for cryptographic use are listed by NIST [here](http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html) and SHOULD be supported by each ODP implementation. > +@subsubsection zeroization Zeroization > +To preserve the security of data, certain transient data held in data buffers MUST be cleared to zeros upon buffer free. > +Such capability is referred to as zeroization. > +ODP supports zeroization as a buffer pool attribute. > +@subsubsection random_number_generation Random Number Generation > +Because cryptography relies heavily on “unguessable” keys of various sorts, random number generation (RNG) is an integral part of cryptographic processing. > +Random numbers are used in key generation, initialization vectors (IVs), various types of padding bytes, and various other uses collectively referred to as nonces, that serve to “harden” cryptographic processing. > + > +There are two types of random number support of interest. > +Hardware random data, also known as entropy, that is the result of inherently random physical processes, and deterministic random bit generation (DRBG) that is used in certain certified cryptographic operations. > +Approved DRBG algorithms are listed in [NIST SP 800-90A](http://en.wikipedia.org/wiki/NIST_SP_800-90A) and ODP does not specify which algorithms are available on a given implementation. > +As such ODP implementations MAY use any approved DRGB algorithm but SHOULD support at least one of them. > +Additionally, ODP implementations MUST NOT represent non-approved algorithms as DRBG implementations. > +Validated algorithms are listed in the [NIST DRBG Validation List](http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgval.html). > + > +@subsubsection capability_inquiry Capability Inquiry > +To enable applications to adapt to the implementation models offered across different SoC platforms, ODP provides APIs to allow applications to inquire about underlying crypto capabilities. > +A given ODP implementation may offer crypto as hardware features, software features, or not available on a given platform. > +@subsection cryptographic_algorithms Cryptographic Algorithms and Protocols > +A cryptographic algorithm is a mathematical transform that provides one of the cryptographic operations described above. > +They in turn are used as building blocks in creating cryptographic protocols. > +These are complete sets of rules for how to exchange data securely using cryptography. > +Both cryptographic algorithm and protocol design are highly specialized disciplines that involve high levels of public scrutiny and validation. > +As a result, applications simply make use of approved cryptographic algorithms and protocols. > +@subsection cryptographic_operations Cryptographic Operations > +Cryptographic operations may be initiated by software or directly by hardware as part of the RX or TX packet path processing. > +For ODP software-initiated cryptographic operations are the primary use case. > +ODP provides APIs for performing data ciphering, hashing, random number generation, and capability inquiry. > +@subsection performance_expectations Performance Expectations > +In the data plane, the total processing budget for a packet may only be a few hundred cycles, so function invocation overhead MUST be kept to a minimum. > +This has several implications. > + > +-# When work is dispatched to a thread, all information needed by the thread to process the work request SHOULD be immediately at hand. > +Ideally any context or variables needed for the operation have been pre-warmed in the cache to avoid the latency hits associated with cache misses. > +SoCs having hardware schedulers generally do this pre-staging of data to minimize such latencies, and ODP implementations are expected to exploit such platform capabilities whenever possible.\n\n > + > +-# Calls to ODP functions SHOULD NOT involve excessive amounts of parameter passing and (depending on the implementation) SHOULD be inlined as much as possible to avoid call overhead. > +One technique that has proven useful is to allow for parameters to be passed as an explicit thread-local static structure. > +Such use of “templating” means that a single function can support a rich set of options but the caller can configure a template matched to specific use and only vary the one or two parameters that differ from call to call.\n\n > + > +-# Kernel traps or interrupts SHOULD NOT be part of any non-exception path function processing. > +Kernel calls and such are acceptable only during one-time initialization logic or certain types of unusual error recovery operations. > +Often the best way to handle the latter is to pass the work to a dedicated recovery thread (or back to the control plane) rather than attempting to handle the condition inline. > +For example, a link-down condition will trigger various recovery actions that might best be handled in this manner. > + > +@subsection use_by_existing_code Use by Existing Code > +Most applications wishing to make use of ODP represent substantial existing investment that must be preserved. > +Insofar as possible, ODP functions need to be orthogonal to existing application environments and structures to permit easy intermixing with pre-existing code. > +@subsection data_references Data References > +Packet data is inherently of variable length however it is often more efficient to organize memory into fixed-sized buffers that can be chained together on demand to contain packets. > +The application SHOULD normally not need to be aware of such lower-level segmentation and should be able to treat a packet as a single object. > +Alternately, especially when dealing with existing code, data segmentation MUST be explicitly specifiable via scatter/gather lists. > +For example, data encryption or decryption may be invoked on a list of data segments as part of a single function call. > +@subsection chained_operations Chained Operations > +Crypto operations such as hashing and encryption, or decryption and verification, are very commonly used in combination. > +For ODP, it is sufficient to support one cipher and one hash/authentication operation in a single call and this combination MUST be supported to avoid the call and dispatch overhead of separate invocations. > + > +@subsection key_management Key Management and Session Data > +Keying is an area of particular sensitivity in crypto processing since keys are highly confidential and may be subject to legal requirements for safeguarding within special hardware enclosures. > + > +A session is the security context used to represent an active set of crypto operations that need to be applied to a flow on a packet-by-packet basis. Generally a session is established upon detection of a flow requiring crypto processing and retained for the life of that flow. It has been noted that this can involve cooperative processing between the control and data planes so several requirements stem from this: > + > +-# Session creation MAY need to be handled in an asynchronous manner. This is to allow these to be created in batches by thread(s) that specialize in this activity.\n\n > + > +-# Sessions MAY need to reference keying material indirectly via key handling modules.\n\n > + > +-# Session creation MAY be performed by non-ODP code and communicated to data plane routines that make use of ODP crypto functions that need to reference the session information. > + > +ODP session APIs and data structures SHOULD be represented by abstract data types that encapsulate implementation details for both platform efficiency and to accommodate these needs. > +Use Cases > +For ODP the major use cases of interest involve cryptographic algorithm acceleration. Cryptographic protocol acceleration is reserved for future ODP releases. > +Buffers and Data Blocks > +Cryptographic operations may be performed directly on data contained in ODP packet buffers, or it may be performed on “raw” data blocks operating entirely under application control. > +Note that when using raw data blocks not managed by ODP, the application must perform any needed zeroization using either its own or ODP-supplied buffer zeroization functions. > +ODP automatic support for zeroization is limited to ODP-managed buffers. > +ODP buffers allocated from buffer pools designated for crypto use will also have whatever alignment and/or addressability attributes needed by the implementation to support crypto API calls. > + > +Note: Some implementations may have difficulty dealing with application buffer addresses, as these may be virtual addresses that are mapped discontiguously into physical memory. > +For such implementations, memory SHOULD be allocated contiguously and MAY need to be “registered” to have proper addressability for crypto operations. > +This area of the design will be updated based on experience in dealing with different crypto implementations that have such requirements. > +Synchronization > +ODP operations fall into one of three categories: > + > +-# Inline (Synchronous): Upon return from a call the operation is complete. > +Operation is thus completely synchronous to the caller. > +Inline is the appropriate model when the invoked function takes relatively few cycles or when the caller cannot feasibly progress without the results of the invoked function.\n\n > + > +-# Parallel: Upon return from a call the operation has been initiated, but is expected to complete shortly. > +The caller continues to execute until it needs the result at which point it waits to complete the parallel operation. > +The effect is as if the operation were inline except that the caller was able to execute in parallel with the operation for some application-determined period of time. > +Parallel is the appropriate model when the operation being performed is relatively short (a few dozen up to perhaps 100 or 200 cycles) and the caller can usefully accomplish other processing on the same unit of work while the parallel operation is in progress, but not enough to justify the overhead of a formal queued work dispatch.\n\n > + > +-# Offloaded (Asynchronous): Upon return from the call the operation has been queued for execution. > +A completion event will be queued back to the scheduler when the event is completed. > +Offload is the appropriate model when the invoked function will take a substantial amount of cycles (thousands to tens of thousands) allowing the invoking thread/core to service other work until the operation completes. > +For offloaded work, completion is indicated by a completion event being posted back to an application-designated completion queue. > +Upon receipt the unit of work that initiated the offloaded operation continues processing with the results of the call. > + > +The synchronization models of interest are summarized in Figure 1: > + > +![Figure 1: Synchronization Models](./images/syncmodels.png) > + > +Note: Because few implementations are expected to offer the Parallel mode of operation as described above, this mode is reserved for potential future use. > +For ODP only synchronous and asynchronous crypto operations are defined. > +@section functional_definition Functional Definition > +@subsection abstract_data_types Abstract data types > +The following enumerations define various algorithms used for ciphering and hashing. > +These are the basic operations applied to input data. > + > +A particular ODP implementation should map these values to the actual information to be passed to the crypto engine. > +As such, the actual values of these enums is implementation-defined. > + > +Cipher algorithm encoding specifies the algorithm and cipher mode employed (as per security relevant RFCs - [4305](http://tools.ietf.org/html/rfc4305), [4868](http://tools.ietf.org/html/rfc4868), [4494](http://tools.ietf.org/html/rfc4494)). > + > +@code > +enum odp_cipher_alg { > + ODP_CIPHER_ALG_NULL, > + ODP_CIPHER_ALG_DES, > + ODP_CIPHER_ALG_3DES_CBC, > + ODP_CIPHER_ALG_AES_CBC, > + ODP_CIPHER_ALG_AES_GCM, > + ODP_CIPHER_ALG_AES_CTR, > + ODP_CIPHER_ALG_KASUMI, > + ODP_CIPHER_ALG_SNOW, > + ... > +}; > +@endcode > + > +Authorization algorithm encoding specifies the algorithm and the length of the authorization used (as per security relevant RFCs - [4305](http://tools.ietf.org/html/rfc4305), [4868](http://tools.ietf.org/html/rfc4868), [4494](http://tools.ietf.org/html/rfc4494)): > + > +@code > +enum odp_auth_alg { > + ODP_AUTH_ALG_NULL, > + ODP_AUTH_MD5_96, > + ODP_AUTH_ALG_SHA1_96, > + ODP_AUTH_ALG_SHA1_160 > + ODP_AUTH_ALG_SHA2_256_128, > + ODP_AUTH_ALG_SHA2_384_192, > + ODP_AUTH_ALG_SHA2_512_256, > + ODP_AUTH_ALG_AES_CMAC_96, > + ODP_AUTH_ALG_AES_XCBC_MAC_96, > + ODP_AUTH_ALG_SNOW, > + ODP_AUTH_ALG_KASUMI, > + ... > +}; > + > +typedef union odp_crypto_alg_t { > + enum odp_cipher_alg cipher; > + enum odp_auth_alg auth; > +}odp_crypto_alg_t; > +@endcode > +@subsection parameter_structures Parameter Structures > +@subsubsection crypto_sessions Crypto Sessions > +The following structure describes a crypto session. > +All packets / raw data buffers processed in a session share the data that defines the session. > +A crypto session is defined by: > + > +- Operation type : encode or decode\n\n > + > +- Algorithms specifications, keys and , if required, initialization vectors. > +When initialization vectors are not provided and they should be provided automatically by the crypto engine.\n\n > + > +- The operation mode: synchronous or asynchronous. > +Synchronous operation blocks the caller until an operation status and result are available. > +In synchronous mode there is at most only one outstanding crypto operation in the calling thread. > +In asynchronous mode, the caller starts the crypto operation and later it may receive the status and the result together with a request context. > +The operation status and result may also be received by a different thread.\n\n > + > +- Operation mode parameters: For asynchronous operation a completion event containing the status, the result and the request context is enqueued to a completion queue. > +In case the queue is under the scheduler control, the scheduler determines who will receive the completion event and when. > +When the completion queue is not scheduled, the thread which is supposed to get the operation output has to explicitly poll the completion queue. > + > +Note that this is an abstract data type and its structure is implementation-specific. > +The layout shown here is for illustrative purposes and the actual layout will vary from one implementation to the next to most closely align with the structures needed by the underlying SoC platform. > +Applications set and reference fields in the session structure via accessor functions that hide the actual layout. > + > +@code > +typedef enum odp_crypto_op_t { > + ODP_CRYPTO_OP_ENCODE, > + ODP_CRYPTO_OP_DECODE > +}odp_crypto_op_t; > + > +typedef struct odp_key_t { > +}odp_key_t; > + > +typedef struct odp_crypto_session_t { > + odp_crypto_op_t op; > + struct { > + enum odp_cipher_alg cipher_alg; > + odp_key_t *key; > + uint8_t *iv; > + size_t iv_len; > + } cipher; > + > + struct { > + enum odp_auth_alg auth_alg; > + enum odp_auth_len auth_len; > + odp_key_t *key; > + } auth; > + > + enum odp_crypto_op_mode { > + ODP_CRYPTO_SYNC, > + ODP_CRYPTO_ASYNC, > + } op_mode; > + > + struct { > + uint32_t timeout; > + struct { > + odp_queue_t completion_queue; > + } async; > + } op_mode_params; > + > + odp_session_proc_info_t session_proc_info; > +} odp_crxsypto_session_t; > +@endcode > + > +The completion queue contained in the session structure is an in/out parameter. > +If provided, then the queue specified is associated with the session and is used to ensure order preservation on that session. > +If not provided, one is created and returned to the caller. > +Note that this completion queue is used to order operations performed on this crypto session. > +It should not be confused with the completion queue specified on the odp_crypto_session_create() call (see below) that is used to control whether that call is itself processed in a synchronous vs. asynchronous manner. > + > +The following structure comprises processing information. > +This is logically divided in two parts: > + > +- Processing input info - When crypto engine provides support for protocol processing, this information is provided in a higher level common protocol terminology form and a particular implementation should be able to derive everything it needs from this definition. > +In addition, for crypto engines able to automate tasks like memory allocation for the output a buffer pool id may be specified.\n\n > + > +- Processing output information - statistics about processed bytes/packets. > +These are useful when a session expiration is based on traffic volume. > +These statistics may be updated by the software or by the hardware crypto engine. > + > +Again, this is an abstract type whose specific layout will vary based on implementation considerations. > +Access to fields contained in the structure is only via accessor functions. > + > +@code > +typedef struct { > + uint64_t pkts_processed; > + uint64_t bytes_processed; > + uint64_t pkts_errored; > + uint64_t bytes_errored; > + > + odp_buffer_pool_t out_pool; > + > +} odp_session_proc_info_t; > +@endcode > + > +This enumeration defines which operations are applied and the order. > + > +@code > +enum odp_crypto_combination { > + ODP_CRYPTO_CIPHER_ONLY, > + ODP_CRYPTO_AUTH_ONLY, > + ODP_CRYPTO_AUTH_CIPHERTEXT > +}; > +@endcode > + > +This structure defines a contiguous segment in the input data which starts at offset offset and is len bytes long. > + > +@code > +struct odp_data_range { > + unsigned offset:16; > + unsigned len:16; > +}; > +@endcode > + > +@subsection api_functions API Functions > + > +@subsubfunction Session Creation > + > +This function is used to create a crypto session. > +The required parameters are: > + > +- Operation : encode/decode > +- Processing info : cipher/auth/both > +- Preferred mode : sync or async. > +- Algorithms suites, keys and optional IV > + > +Session creation can be synchronous or asynchronous. > +Completion event argument is used to return the status and the session handle. > +When completion queue is not provided (synchronous call), the completion event is available upon function call return. > +When completion queue is provided (asynchronous call), the completion event is placed on the completion queue. > + > +@code > +typedef uint64_t odp_crypto_session_t; > + > +struct odp_session_params { > + enum odp_crypto_operation op; > + odp_session_proc_info_t proc_info; > + enum odp_crypto_op_mode pref_mode; > + enum odp_cipher_alg cipher_alg; > + odp_key_t *cipher_key; > + uint8_t *iv; > + size_t iv_len; > + enum odp_auth_alg auth_alg; > + odp_key_t *auth_key; > +}; > + > +enum odp_crypto_ses_create_err { > + ODP_CRYPTO_SES_CREATE_NONE, > + ODP_CRYPTO_SES_CREATE_ENOMEM, > + /* Session creation error codes */ > +}; > + > +void > +odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, enum odp_crypto_ses_create_err *status); > + > +void > +odp_crypto_get_ses_create_compl_handle(odp_buffer_t completion_event, odp_crypto_session_t *handle); > + > +int odp_crypto_session_create( > + struct odp_session_params *params, > + odp_buffer_t completion_event, > + odp_queue_t completion_queue); > +@endcode > +@subsection crypto_operation Crypto Operation > + > +Crypto operations are described by a parameter structure: > +@code > +struct odp_crypto_op_params { > + odp_crypto_session_t session; > + odp_packet_t pkt; > + odp_packet_t out_pkt; > + uint8_t *override_iv_ptr; > + unsigned hash_result_offset; > + struct odp_data_range cipher_range; > + struct odp_data_range auth_range; > +}; > +@endcode > + > +<table> > +<tr><th>Parameter</th><th>Meaning</th></tr> > +<tr><td>session</td><td>Session to perform the operation</td></tr> > +<tr><td>pkt</td><td>Packet / buffer to be processed</td></tr> > +<tr><td>out_pkt</td><td>Handle of an output packet / buffer to be returned as the result of the operation. > +There are three different ways this parameter is used, depending on the mode of operation requested by the caller and the capabilities of the underlying implementation:\n\n > + > +-# If out_pkt is the same as pkt this indicates that the operation should be performed in place.\n\n > +-# If out_pkt is different from pkt this indicates that output should be placed in the buffer supplied by the caller.\n\n > +-# If out_pkt is omitted (a null/invalid value supplied on input) this indicates that an output buffer should be allocated by the operation and returned as part of the completion event associated with the operation.\n\n > + > +Note that not every implementation will support all of these modes and MAY require that one mode be used in preference to others. > +Any such implementation restrictions are communicated as output from session creation.</td></tr> > +<tr><td>override_iv_ptr</td><td>Optional IV to use for this request</td></tr> > +<tr><td>hash_result_offset</td><td>Offset into the output packet where the hash result should be stored.</td></tr> > +<tr><td>cipher_range</td><td>The byte range (offset:length) of the data to be processed for ciphering.</td></tr> > +<tr><td>auth_range</td><td>The byte range (offset:length) of the data to be processed for authentication.</td></tr> > +</table> > + > +The crypto operation is initiated with a single call that passes the parameters for the operation and an event (for asynchronous completion). > +@code > +int odp_crypto_operation( > + struct odp_crypto_op_params *params, > + odp_buffer_t completion_event); > +@endcode > + > +Parameter | Meaning > +----------|-------- > +params | The parameter structure describing the crypto operation to be performed. > +completion_event | The event delivered on completion. > +It provides information about the status of the operation, result and request context. > +In synchronous mode the event is available upon function call return. > +In asynchronous mode, the event is placed on the session / operation completion queue when the operation finished. > + > +Upon return the return code indicates whether the operation was synchronous or asynchronous, or if an error occurred that prevented the operation from being performed. > + > +Get session operation : > +@code > +odp_crypto_op_t odp_crypto_session_get_op(odp_crypto_session_t ses); > +@endcode > + > +Get session cipher information : > +@code > +odp_cipher_alg odp_cipher_session_get_cipher_alg(odp_crypto_session_t ses); > +@endcode > + > +Get session authentication information : > +@code > +odp_auth_alg odp_crypto_session_get_auth_alg(odp_crypto_session_t ses); > +@endcode > + > +Change session IV : > +@code > +int odp_crypto_session_iv_set(odp_crypto_session_t ses, uint8_t *iv); > +@emdcode > + > +Change cipher or/and hash keys: > +@code > +int odp_crypto_session_key_set(odp_crypto_session_t ses, odp_key_t *key); > +@endcode > + > +Destroy crypto session. > +All pending operations are cancelled. > +@code > +int odp_crypto_session_destroy(odp_crypto_session_t ses); > +@endcode > + > +Get completion event information - algorithm error, output and context. > +Note that implementations MAY define their own specific error codes that have meaning in that context. > +For application portability it is sufficient to know whether an operation completed successfully or experienced an error of some sort. > +@code > +enum crypto_alg_err { > + ODP_CRYPTO_ALG_ERR_NONE, > + ODP_CRYPTO_ALG_ERR_MODE, > + ODP_CRYPTO_ALG_ERR_DATA_SIZE, > + ODP_CRYPTO_ALG_ERR_KEY_SIZE, > + ODP_CRYPTO_ALG_ERR_ICV_CHECK, > + ODP_CRYPTO_ALG_ERR_AAD_SIZE, > +}; > + > +enum crypto_hw_err { > + ODP_CRYPTO_HW_ERR_NONE, > + ODP_CRYPTO_HW_ERR_DMA, > + ODP_CRYPTO_HW_ERR_BP_DEPLETED, > +}; > + > +struct odp_crypto_compl_status { > + odp_crypto_alg_t alg; > + enum crypto_alg_err alg_err; > + enum crypto_hw_err hw_err; > +}; > + > +void > +odp_crypto_get_compl_status(odp_buffer_t completion_event, > + struct odp_crypto_compl_status *auth, > + struct odp_crypto_compl_status *cipher); > +@endcode > + > +Returns the output packet handle associated with the completion event : > +@code > +odp_packet_t odp_crypto_get_out_pkt(odp_buffer_t completion_event); > +@endcode > + > +Sets a context handle to be returned with the completion event : > +@code > +void odp_crypto_set_compl_ctx(odp_buffer_t completion_event, odp_compl_ctx_t *ctx); > +@endcode > + > +Returns the context associated with the completion event : > +@code > +odp_compl_ctx_t odp_crypto_get_compl_ctx(odp_buffer_t completion_event); > +@endcode > + > +This section describes the API/Interface being defined at a functional level in technical detail. > +Sub-sections include header file names, where implementation files are expected to reside in the ODP git tree, as well as the name, parameters, abstract data types, functionality, return codes, and exception conditions of each function call defined by the API/Interface. > +Appropriate diagrams, tables, etc. should be used to allow the programmer tasked with implementing the API/Interface to understand the function to be implemented as well as error conditions, corner cases, performance requirements, etc. needed to implement the described API/Interface in a functionally correct and efficient manner. > + > +@subsubsection random_number_functions Random Number Functions > +As noted earlier, random number support consists of two functions: > +@code > +int odp_hw_random_get (uint8_t *buf, uint32_t *len, bool use_entropy); > + > +int odp_drgb_random_get (uint8_t *buf, uint32_t *len); > +@endcode > + > +The difference is that the first provides access to hardware random number functions that return true random data. > +This is typically used for seed values. > +The second provides a deterministic random bit generator conforming to NIST standards and is used by various crypto protocols and algorithms. > +The use_entropy parameter on odp_hw_random_get is used to disable any hardware pre-processing normally provided by the function and is mainly intended to be used for testing/validation purposes. > + > +@subsubsection buffer_pool_extensions Buffer Pool Extensions > +To support zeroization a buffer may be allocated with an ODP_CLEAR_ON_FREE attribute that specifies that this buffer should be zeroized upon free. > +Alternately, a new type (ODP_CLEAR_ON_FREE) is added to odp_buffer_pool_create() that specifies that all buffers allocated from this pool must be zeroized upon free. > +Essentially, the buffer security attribute is set by default from the attributes of the buffer pool that it is allocated from. > + > +@subsubsection capability_inquiry Capability Inquiry > +To enable applications to determine crypto capabilities. > +@code > +int odp_crypto_inquire (enum odp_cipher_alg, enum odp_auth_alg); > +@endcode > + > +Inquires whether the specified crypto and auth algorithms are supported. > +Responses include: > +- ODP_HW_SYNC_SUPPORT > +- ODP_HW_ASYNC_SUPPORT > +- ODP_SW_SYNC_SUPPORT > +- ODP_SW_ASYNC_SUPPORT > +- ODP_NO_SUPPORT > + > +HW support means the combination is supported in hardware, SW support means the combination is supported in software by the implementation. > +No support means the combination is not supported by the implementation. > +The SYNC and ASYNC return options can help the application decide how to invoke these functions, or it can just check whether or not the response is ODP_NO_SUPPORT. > + > +@section implementation_considerations Implementation Considerations > +One of the main purposes for the ODP crypto APIs is to provide portable access across different SoCs whose hardware crypto capabilities largely overlap but vary in terms of their implementation details. > +As a result, implementations need not provide software fill-ins for specific cryptographic features that are not available as hardware features on that platform. > +Presumably applications needing specific features will select platforms on which these features are present. > +Therefore, while all APIs specified here MUST exist in each conforming ODP implementation, it is acceptable for these APIs to return ODP_RC_FEATURE_NOT_PRESENT in response to calls requesting crypto features not present on that platform. > + > +For example, the linux-generic ODP implementation may only implement the null cipher suite (ODP_CIPHER_ALG_NULL) and return a feature not present error code for any other cipher. > +This indication will also be returned on that platform in response to odp_crypto_inquire calls for non-null cipher algorithms. > + > +@section verification Verification/Testing > +This section describes the verification/test cases needed to ensure that the defined functionality is implemented correctly and performs adequately. > +This should be at a level of detail such that the programmer tasked with writing test scripts/programs to verify the implementation(s) of the defined functions can be written to ensure that all relevant functional variants and error/exception cases are properly tested. > + > +This section needs to be completed before API testing begins. > + > +*/ > \ No newline at end of file > diff --git a/images/syncmodels.png b/images/syncmodels.png > new file mode 100644 > index 0000000000000000000000000000000000000000..44e4c551bd803b7dd4320875699828d7f20d2044 > GIT binary patch > literal 17179 > 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 > Z7*dM{yQhj}4sy3din1y)<x=lM{ueeblRN+b > > literal 0 > HcmV?d00001 > > -- > 1.8.3.2 > > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > http://lists.linaro.org/mailman/listinfo/lng-odp
1. @subsubfunction should have been @subsubsection. Good catch. 2. Alex is already one of the authors, git format-patch added the signed off stuff. Not sure if it's ethical for me to impersonate someone else. 3. I did and it formats fine for me. 4. If you already have further tidy edits, feel free to apply/merge them into the final results. If you have scripts for doing this I'd be happy to run them. I just had Google save the doc as text and then edited by hand to get the doxygen. Bill On Wed, Jul 9, 2014 at 12:41 PM, Anders Roxell <anders.roxell@linaro.org> wrote: > On 2014-07-09 09:20, Bill Fischofer wrote: > > Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> > > --- > > crypto_design.dox | 545 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > > images/syncmodels.png | Bin 0 -> 17179 bytes > > 2 files changed, 545 insertions(+) > > create mode 100644 crypto_design.dox > > create mode 100644 images/syncmodels.png > > > > Hi Bill, > > Thank you for reworking the patch. > > I have a couple of comments. > 1. @subsubfunction is not a doxygen variable I think you mean: > "@subsubsection fucntion Session Creation". Doxygen was warning about > that. > 2. Should we add Alex Signed-off-by as well to give him credit? > 3. Before you send a patch try to apply it your self, git complained see > [1] > 4. See reference [2] this is a diff of what I had to do to tidy up the > patch, > can you please do that and resend it. > > > A nit not a blocker: > > +typedef struct odp_key_t { > > +}odp_key_t; > > Nothing inside this struct, is that correct? > Should there be an explanation why it's empty? > > Cheers, > Anders > > [1] http://people.linaro.org/~anders.roxell/git_am_crypto_design_doc.txt > [2] > http://people.linaro.org/~anders.roxell/cleanup_crypto_design_doc.patch > > > diff --git a/crypto_design.dox b/crypto_design.dox > > new file mode 100644 > > index 0000000..a46a2db > > --- /dev/null > > +++ b/crypto_design.dox > > @@ -0,0 +1,545 @@ > > +/* Copyright (c) 2043, Linaro Limited > > + * All rights reserved > > + * > > + * SPDX-License-Identifier: BSD-3-Clause > > + */ > > + > > +/** > > +@page crypto_design ODP Design - Crypto API > > +For the implimentation of the ODP crypto API please see @ref > odp_crypto.h > > + > > +@tableofcontents > > + > > +@section revision_history Revision History > > +Revision | Issue Data | Description | Author > > +---------|------------|-------------|-------- > > +0.1 | 4/9/2014 | Introduction started, Basic Functions | Bill, > Alexandru > > +0.2 | 4/15/2014 | Completed intro, added TOC, started use cases, > miscellaneous formatting, API comments | Bill > > +0.3 | 4/22/2014 | Added Use Case section to include results of > design discussions held during ODP team calls | Bill > > +0.4 | 4/30/2014 | Design review from ODP crypto sprint--action to > resolve | Bill > > +0.5 | 5/5/2014 | Rewrite incorporating review comments--ready > for final review | Bill > > +1.0 | 5/30/2014 | Final version for LNG-SC approval | Bill > > + > > +@section introduction Introduction > > +This document describes the ODP Crypto API. Cryptography is an > important part of data plane processing as many communication protocols > make use of cryptographic functions. > > +Moreover, many SoCs incorporate cryptographic hardware that can > significantly accelerate these operations compared to their software > equivalents as well as provide validated hardware functional correctness > and security boundaries necessary for system-level security certifications > such as FIPS-140 Level 2 and above. > > +@section requirements Requirements > > +@subsection use_of_terms Use of Terms > > +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", > "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this > document are to be interpreted as described in [RFC 2119]( > https://tools.ietf.org/html/rfc2119). > > +@subsection uses_of_cryptography Uses of Cryptography > > +Crypto functions cover a range of uses and capabilities designed to > support data security, integrity, authentication, and non-repudiation. > > +@subsubsection data_security Data Security > > +Cryptography supports data security by making use of complex > mathematical transformations that are not feasibly reversible without > possession of the secret key used to encrypt message data. > > +@subsubsection data_integrity Data Integrity > > +Cryptography supports data integrity through the use of cryptographic > checksums (also known as secure hashes) that ensure the recipient that > message data has not been altered either accidentally or maliciously while > in transit. > > +@subsubsection data_authentication Data Authentication > > +Cryptography supports data authentication through the uses of Message > Authentication Codes (MACs) that enable the recipient to verify that a > message was sent from an authorized counterparty, and hence was not forged. > > +@subsubsection data_non_repudiation Data Non-Repudiation > > +Cryptography supports data non-repudiation through the use of digital > signatures that enable a recipient or third party to verify the identity of > the sending party and prevents the sending party from later denying that > they originated a signed message. > > +@subsection scope Scope > > +ODP crypto support is designed to provide a portable framework for > accessing SoC-specific cryptographic functions of most use to the data > plane. This is predominantly symmetric crypto operations used to support > the encryption and decryption of data at line rate using hardware > acceleration and offload. Specifically excluded in this support are public > key operations and other crypto functions mainly used in the control plane. > > +@subsection cryptographic_operations_in_the_data_plane Cryptographic > Operations in the Data Plane > > +ODP crypto APIs cover the following areas: > > +@subsubsection ciphering Ciphering > > +Ciphering refers to mathematical transformations that use a secret key > to encipher data, transforming the original data (referred to as plaintext) > into ciphertext, thereby making it unintelligible to anyone not in > possession of the key. Similarly, ciphering is also used to decipher data, > allowing someone in possession of the correct key to transform received > ciphertext back into plaintext. Approved block ciphers are listed [here]( > http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html) and SHOULD be > supported by each ODP implementation. > > +@subsubsection hasing Hashing > > +A hash is a cryptographic digest of a message that can be used to > represent it for comparison or integrity checking. Hash functions are > designed so that any alteration of a message will alter the hash and that > it is computationally infeasible to craft a message that generates the same > hash value as another message. Secure hash functions approved for > cryptographic use are listed by NIST [here]( > http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html) and SHOULD be > supported by each ODP implementation. > > +@subsubsection zeroization Zeroization > > +To preserve the security of data, certain transient data held in data > buffers MUST be cleared to zeros upon buffer free. > > +Such capability is referred to as zeroization. > > +ODP supports zeroization as a buffer pool attribute. > > +@subsubsection random_number_generation Random Number Generation > > +Because cryptography relies heavily on “unguessable” keys of various > sorts, random number generation (RNG) is an integral part of cryptographic > processing. > > +Random numbers are used in key generation, initialization vectors > (IVs), various types of padding bytes, and various other uses collectively > referred to as nonces, that serve to “harden” cryptographic processing. > > + > > +There are two types of random number support of interest. > > +Hardware random data, also known as entropy, that is the result of > inherently random physical processes, and deterministic random bit > generation (DRBG) that is used in certain certified cryptographic > operations. > > +Approved DRBG algorithms are listed in [NIST SP 800-90A]( > http://en.wikipedia.org/wiki/NIST_SP_800-90A) and ODP does not specify > which algorithms are available on a given implementation. > > +As such ODP implementations MAY use any approved DRGB algorithm but > SHOULD support at least one of them. > > +Additionally, ODP implementations MUST NOT represent non-approved > algorithms as DRBG implementations. > > +Validated algorithms are listed in the [NIST DRBG Validation List]( > http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgval.html). > > + > > +@subsubsection capability_inquiry Capability Inquiry > > +To enable applications to adapt to the implementation models offered > across different SoC platforms, ODP provides APIs to allow applications to > inquire about underlying crypto capabilities. > > +A given ODP implementation may offer crypto as hardware features, > software features, or not available on a given platform. > > +@subsection cryptographic_algorithms Cryptographic Algorithms and > Protocols > > +A cryptographic algorithm is a mathematical transform that provides one > of the cryptographic operations described above. > > +They in turn are used as building blocks in creating cryptographic > protocols. > > +These are complete sets of rules for how to exchange data securely > using cryptography. > > +Both cryptographic algorithm and protocol design are highly specialized > disciplines that involve high levels of public scrutiny and validation. > > +As a result, applications simply make use of approved cryptographic > algorithms and protocols. > > +@subsection cryptographic_operations Cryptographic Operations > > +Cryptographic operations may be initiated by software or directly by > hardware as part of the RX or TX packet path processing. > > +For ODP software-initiated cryptographic operations are the primary use > case. > > +ODP provides APIs for performing data ciphering, hashing, random number > generation, and capability inquiry. > > +@subsection performance_expectations Performance Expectations > > +In the data plane, the total processing budget for a packet may only be > a few hundred cycles, so function invocation overhead MUST be kept to a > minimum. > > +This has several implications. > > + > > +-# When work is dispatched to a thread, all information needed by the > thread to process the work request SHOULD be immediately at hand. > > +Ideally any context or variables needed for the operation have been > pre-warmed in the cache to avoid the latency hits associated with cache > misses. > > +SoCs having hardware schedulers generally do this pre-staging of data > to minimize such latencies, and ODP implementations are expected to exploit > such platform capabilities whenever possible.\n\n > > + > > +-# Calls to ODP functions SHOULD NOT involve excessive amounts of > parameter passing and (depending on the implementation) SHOULD be inlined > as much as possible to avoid call overhead. > > +One technique that has proven useful is to allow for parameters to be > passed as an explicit thread-local static structure. > > +Such use of “templating” means that a single function can support a > rich set of options but the caller can configure a template matched to > specific use and only vary the one or two parameters that differ from call > to call.\n\n > > + > > +-# Kernel traps or interrupts SHOULD NOT be part of any non-exception > path function processing. > > +Kernel calls and such are acceptable only during one-time > initialization logic or certain types of unusual error recovery operations. > > +Often the best way to handle the latter is to pass the work to a > dedicated recovery thread (or back to the control plane) rather than > attempting to handle the condition inline. > > +For example, a link-down condition will trigger various recovery > actions that might best be handled in this manner. > > + > > +@subsection use_by_existing_code Use by Existing Code > > +Most applications wishing to make use of ODP represent substantial > existing investment that must be preserved. > > +Insofar as possible, ODP functions need to be orthogonal to existing > application environments and structures to permit easy intermixing with > pre-existing code. > > +@subsection data_references Data References > > +Packet data is inherently of variable length however it is often more > efficient to organize memory into fixed-sized buffers that can be chained > together on demand to contain packets. > > +The application SHOULD normally not need to be aware of such > lower-level segmentation and should be able to treat a packet as a single > object. > > +Alternately, especially when dealing with existing code, data > segmentation MUST be explicitly specifiable via scatter/gather lists. > > +For example, data encryption or decryption may be invoked on a list of > data segments as part of a single function call. > > +@subsection chained_operations Chained Operations > > +Crypto operations such as hashing and encryption, or decryption and > verification, are very commonly used in combination. > > +For ODP, it is sufficient to support one cipher and one > hash/authentication operation in a single call and this combination MUST be > supported to avoid the call and dispatch overhead of separate invocations. > > + > > +@subsection key_management Key Management and Session Data > > +Keying is an area of particular sensitivity in crypto processing since > keys are highly confidential and may be subject to legal requirements for > safeguarding within special hardware enclosures. > > + > > +A session is the security context used to represent an active set of > crypto operations that need to be applied to a flow on a packet-by-packet > basis. Generally a session is established upon detection of a flow > requiring crypto processing and retained for the life of that flow. It has > been noted that this can involve cooperative processing between the control > and data planes so several requirements stem from this: > > + > > +-# Session creation MAY need to be handled in an asynchronous manner. > This is to allow these to be created in batches by thread(s) that > specialize in this activity.\n\n > > + > > +-# Sessions MAY need to reference keying material indirectly via key > handling modules.\n\n > > + > > +-# Session creation MAY be performed by non-ODP code and communicated > to data plane routines that make use of ODP crypto functions that need to > reference the session information. > > + > > +ODP session APIs and data structures SHOULD be represented by abstract > data types that encapsulate implementation details for both platform > efficiency and to accommodate these needs. > > +Use Cases > > +For ODP the major use cases of interest involve cryptographic algorithm > acceleration. Cryptographic protocol acceleration is reserved for future > ODP releases. > > +Buffers and Data Blocks > > +Cryptographic operations may be performed directly on data contained in > ODP packet buffers, or it may be performed on “raw” data blocks operating > entirely under application control. > > +Note that when using raw data blocks not managed by ODP, the > application must perform any needed zeroization using either its own or > ODP-supplied buffer zeroization functions. > > +ODP automatic support for zeroization is limited to ODP-managed buffers. > > +ODP buffers allocated from buffer pools designated for crypto use will > also have whatever alignment and/or addressability attributes needed by the > implementation to support crypto API calls. > > + > > +Note: Some implementations may have difficulty dealing with application > buffer addresses, as these may be virtual addresses that are mapped > discontiguously into physical memory. > > +For such implementations, memory SHOULD be allocated contiguously and > MAY need to be “registered” to have proper addressability for crypto > operations. > > +This area of the design will be updated based on experience in dealing > with different crypto implementations that have such requirements. > > +Synchronization > > +ODP operations fall into one of three categories: > > + > > +-# Inline (Synchronous): Upon return from a call the operation is > complete. > > +Operation is thus completely synchronous to the caller. > > +Inline is the appropriate model when the invoked function takes > relatively few cycles or when the caller cannot feasibly progress without > the results of the invoked function.\n\n > > + > > +-# Parallel: Upon return from a call the operation has been initiated, > but is expected to complete shortly. > > +The caller continues to execute until it needs the result at which > point it waits to complete the parallel operation. > > +The effect is as if the operation were inline except that the caller > was able to execute in parallel with the operation for some > application-determined period of time. > > +Parallel is the appropriate model when the operation being performed is > relatively short (a few dozen up to perhaps 100 or 200 cycles) and the > caller can usefully accomplish other processing on the same unit of work > while the parallel operation is in progress, but not enough to justify the > overhead of a formal queued work dispatch.\n\n > > + > > +-# Offloaded (Asynchronous): Upon return from the call the operation > has been queued for execution. > > +A completion event will be queued back to the scheduler when the event > is completed. > > +Offload is the appropriate model when the invoked function will take a > substantial amount of cycles (thousands to tens of thousands) allowing the > invoking thread/core to service other work until the operation completes. > > +For offloaded work, completion is indicated by a completion event being > posted back to an application-designated completion queue. > > +Upon receipt the unit of work that initiated the offloaded operation > continues processing with the results of the call. > > + > > +The synchronization models of interest are summarized in Figure 1: > > + > > +![Figure 1: Synchronization Models](./images/syncmodels.png) > > + > > +Note: Because few implementations are expected to offer the Parallel > mode of operation as described above, this mode is reserved for potential > future use. > > +For ODP only synchronous and asynchronous crypto operations are defined. > > +@section functional_definition Functional Definition > > +@subsection abstract_data_types Abstract data types > > +The following enumerations define various algorithms used for ciphering > and hashing. > > +These are the basic operations applied to input data. > > + > > +A particular ODP implementation should map these values to the actual > information to be passed to the crypto engine. > > +As such, the actual values of these enums is implementation-defined. > > + > > +Cipher algorithm encoding specifies the algorithm and cipher mode > employed (as per security relevant RFCs - [4305]( > http://tools.ietf.org/html/rfc4305), [4868]( > http://tools.ietf.org/html/rfc4868), [4494]( > http://tools.ietf.org/html/rfc4494)). > > + > > +@code > > +enum odp_cipher_alg { > > + ODP_CIPHER_ALG_NULL, > > + ODP_CIPHER_ALG_DES, > > + ODP_CIPHER_ALG_3DES_CBC, > > + ODP_CIPHER_ALG_AES_CBC, > > + ODP_CIPHER_ALG_AES_GCM, > > + ODP_CIPHER_ALG_AES_CTR, > > + ODP_CIPHER_ALG_KASUMI, > > + ODP_CIPHER_ALG_SNOW, > > + ... > > +}; > > +@endcode > > + > > +Authorization algorithm encoding specifies the algorithm and the length > of the authorization used (as per security relevant RFCs - [4305]( > http://tools.ietf.org/html/rfc4305), [4868]( > http://tools.ietf.org/html/rfc4868), [4494]( > http://tools.ietf.org/html/rfc4494)): > > + > > +@code > > +enum odp_auth_alg { > > + ODP_AUTH_ALG_NULL, > > + ODP_AUTH_MD5_96, > > + ODP_AUTH_ALG_SHA1_96, > > + ODP_AUTH_ALG_SHA1_160 > > + ODP_AUTH_ALG_SHA2_256_128, > > + ODP_AUTH_ALG_SHA2_384_192, > > + ODP_AUTH_ALG_SHA2_512_256, > > + ODP_AUTH_ALG_AES_CMAC_96, > > + ODP_AUTH_ALG_AES_XCBC_MAC_96, > > + ODP_AUTH_ALG_SNOW, > > + ODP_AUTH_ALG_KASUMI, > > + ... > > +}; > > + > > +typedef union odp_crypto_alg_t { > > + enum odp_cipher_alg cipher; > > + enum odp_auth_alg auth; > > +}odp_crypto_alg_t; > > +@endcode > > +@subsection parameter_structures Parameter Structures > > +@subsubsection crypto_sessions Crypto Sessions > > +The following structure describes a crypto session. > > +All packets / raw data buffers processed in a session share the data > that defines the session. > > +A crypto session is defined by: > > + > > +- Operation type : encode or decode\n\n > > + > > +- Algorithms specifications, keys and , if required, initialization > vectors. > > +When initialization vectors are not provided and they should be > provided automatically by the crypto engine.\n\n > > + > > +- The operation mode: synchronous or asynchronous. > > +Synchronous operation blocks the caller until an operation status and > result are available. > > +In synchronous mode there is at most only one outstanding crypto > operation in the calling thread. > > +In asynchronous mode, the caller starts the crypto operation and later > it may receive the status and the result together with a request context. > > +The operation status and result may also be received by a different > thread.\n\n > > + > > +- Operation mode parameters: For asynchronous operation a completion > event containing the status, the result and the request context is enqueued > to a completion queue. > > +In case the queue is under the scheduler control, the scheduler > determines who will receive the completion event and when. > > +When the completion queue is not scheduled, the thread which is > supposed to get the operation output has to explicitly poll the completion > queue. > > + > > +Note that this is an abstract data type and its structure is > implementation-specific. > > +The layout shown here is for illustrative purposes and the actual > layout will vary from one implementation to the next to most closely align > with the structures needed by the underlying SoC platform. > > +Applications set and reference fields in the session structure via > accessor functions that hide the actual layout. > > + > > +@code > > +typedef enum odp_crypto_op_t { > > + ODP_CRYPTO_OP_ENCODE, > > + ODP_CRYPTO_OP_DECODE > > +}odp_crypto_op_t; > > + > > +typedef struct odp_key_t { > > +}odp_key_t; > > + > > +typedef struct odp_crypto_session_t { > > + odp_crypto_op_t op; > > + struct { > > + enum odp_cipher_alg cipher_alg; > > + odp_key_t *key; > > + uint8_t *iv; > > + size_t iv_len; > > + } cipher; > > + > > + struct { > > + enum odp_auth_alg auth_alg; > > + enum odp_auth_len auth_len; > > + odp_key_t *key; > > + } auth; > > + > > + enum odp_crypto_op_mode { > > + ODP_CRYPTO_SYNC, > > + ODP_CRYPTO_ASYNC, > > + } op_mode; > > + > > + struct { > > + uint32_t timeout; > > + struct { > > + odp_queue_t completion_queue; > > + } async; > > + } op_mode_params; > > + > > + odp_session_proc_info_t session_proc_info; > > +} odp_crxsypto_session_t; > > +@endcode > > + > > +The completion queue contained in the session structure is an in/out > parameter. > > +If provided, then the queue specified is associated with the session > and is used to ensure order preservation on that session. > > +If not provided, one is created and returned to the caller. > > +Note that this completion queue is used to order operations performed > on this crypto session. > > +It should not be confused with the completion queue specified on the > odp_crypto_session_create() call (see below) that is used to control > whether that call is itself processed in a synchronous vs. asynchronous > manner. > > + > > +The following structure comprises processing information. > > +This is logically divided in two parts: > > + > > +- Processing input info - When crypto engine provides support for > protocol processing, this information is provided in a higher level common > protocol terminology form and a particular implementation should be able to > derive everything it needs from this definition. > > +In addition, for crypto engines able to automate tasks like memory > allocation for the output a buffer pool id may be specified.\n\n > > + > > +- Processing output information - statistics about processed > bytes/packets. > > +These are useful when a session expiration is based on traffic volume. > > +These statistics may be updated by the software or by the hardware > crypto engine. > > + > > +Again, this is an abstract type whose specific layout will vary based > on implementation considerations. > > +Access to fields contained in the structure is only via accessor > functions. > > + > > +@code > > +typedef struct { > > + uint64_t pkts_processed; > > + uint64_t bytes_processed; > > + uint64_t pkts_errored; > > + uint64_t bytes_errored; > > + > > + odp_buffer_pool_t out_pool; > > + > > +} odp_session_proc_info_t; > > +@endcode > > + > > +This enumeration defines which operations are applied and the order. > > + > > +@code > > +enum odp_crypto_combination { > > + ODP_CRYPTO_CIPHER_ONLY, > > + ODP_CRYPTO_AUTH_ONLY, > > + ODP_CRYPTO_AUTH_CIPHERTEXT > > +}; > > +@endcode > > + > > +This structure defines a contiguous segment in the input data which > starts at offset offset and is len bytes long. > > + > > +@code > > +struct odp_data_range { > > + unsigned offset:16; > > + unsigned len:16; > > +}; > > +@endcode > > + > > +@subsection api_functions API Functions > > + > > +@subsubfunction Session Creation > > + > > +This function is used to create a crypto session. > > +The required parameters are: > > + > > +- Operation : encode/decode > > +- Processing info : cipher/auth/both > > +- Preferred mode : sync or async. > > +- Algorithms suites, keys and optional IV > > + > > +Session creation can be synchronous or asynchronous. > > +Completion event argument is used to return the status and the session > handle. > > +When completion queue is not provided (synchronous call), the > completion event is available upon function call return. > > +When completion queue is provided (asynchronous call), the completion > event is placed on the completion queue. > > + > > +@code > > +typedef uint64_t odp_crypto_session_t; > > + > > +struct odp_session_params { > > + enum odp_crypto_operation op; > > + odp_session_proc_info_t proc_info; > > + enum odp_crypto_op_mode pref_mode; > > + enum odp_cipher_alg cipher_alg; > > + odp_key_t *cipher_key; > > + uint8_t *iv; > > + size_t iv_len; > > + enum odp_auth_alg auth_alg; > > + odp_key_t *auth_key; > > +}; > > + > > +enum odp_crypto_ses_create_err { > > + ODP_CRYPTO_SES_CREATE_NONE, > > + ODP_CRYPTO_SES_CREATE_ENOMEM, > > + /* Session creation error codes */ > > +}; > > + > > +void > > +odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, > enum odp_crypto_ses_create_err *status); > > + > > +void > > +odp_crypto_get_ses_create_compl_handle(odp_buffer_t completion_event, > odp_crypto_session_t *handle); > > + > > +int odp_crypto_session_create( > > + struct odp_session_params *params, > > + odp_buffer_t completion_event, > > + odp_queue_t completion_queue); > > +@endcode > > +@subsection crypto_operation Crypto Operation > > + > > +Crypto operations are described by a parameter structure: > > +@code > > +struct odp_crypto_op_params { > > + odp_crypto_session_t session; > > + odp_packet_t pkt; > > + odp_packet_t out_pkt; > > + uint8_t *override_iv_ptr; > > + unsigned hash_result_offset; > > + struct odp_data_range cipher_range; > > + struct odp_data_range auth_range; > > +}; > > +@endcode > > + > > +<table> > > +<tr><th>Parameter</th><th>Meaning</th></tr> > > +<tr><td>session</td><td>Session to perform the operation</td></tr> > > +<tr><td>pkt</td><td>Packet / buffer to be processed</td></tr> > > +<tr><td>out_pkt</td><td>Handle of an output packet / buffer to be > returned as the result of the operation. > > +There are three different ways this parameter is used, depending on the > mode of operation requested by the caller and the capabilities of the > underlying implementation:\n\n > > + > > +-# If out_pkt is the same as pkt this indicates that the operation > should be performed in place.\n\n > > +-# If out_pkt is different from pkt this indicates that output should > be placed in the buffer supplied by the caller.\n\n > > +-# If out_pkt is omitted (a null/invalid value supplied on input) this > indicates that an output buffer should be allocated by the operation and > returned as part of the completion event associated with the operation.\n\n > > + > > +Note that not every implementation will support all of these modes and > MAY require that one mode be used in preference to others. > > +Any such implementation restrictions are communicated as output from > session creation.</td></tr> > > +<tr><td>override_iv_ptr</td><td>Optional IV to use for this > request</td></tr> > > +<tr><td>hash_result_offset</td><td>Offset into the output packet where > the hash result should be stored.</td></tr> > > +<tr><td>cipher_range</td><td>The byte range (offset:length) of the data > to be processed for ciphering.</td></tr> > > +<tr><td>auth_range</td><td>The byte range (offset:length) of the data > to be processed for authentication.</td></tr> > > +</table> > > + > > +The crypto operation is initiated with a single call that passes the > parameters for the operation and an event (for asynchronous completion). > > +@code > > +int odp_crypto_operation( > > + struct odp_crypto_op_params *params, > > + odp_buffer_t completion_event); > > +@endcode > > + > > +Parameter | Meaning > > +----------|-------- > > +params | The parameter structure describing the crypto operation to > be performed. > > +completion_event | The event delivered on completion. > > +It provides information about the status of the operation, result and > request context. > > +In synchronous mode the event is available upon function call return. > > +In asynchronous mode, the event is placed on the session / operation > completion queue when the operation finished. > > + > > +Upon return the return code indicates whether the operation was > synchronous or asynchronous, or if an error occurred that prevented the > operation from being performed. > > + > > +Get session operation : > > +@code > > +odp_crypto_op_t odp_crypto_session_get_op(odp_crypto_session_t ses); > > +@endcode > > + > > +Get session cipher information : > > +@code > > +odp_cipher_alg odp_cipher_session_get_cipher_alg(odp_crypto_session_t > ses); > > +@endcode > > + > > +Get session authentication information : > > +@code > > +odp_auth_alg odp_crypto_session_get_auth_alg(odp_crypto_session_t ses); > > +@endcode > > + > > +Change session IV : > > +@code > > +int odp_crypto_session_iv_set(odp_crypto_session_t ses, uint8_t *iv); > > +@emdcode > > + > > +Change cipher or/and hash keys: > > +@code > > +int odp_crypto_session_key_set(odp_crypto_session_t ses, odp_key_t > *key); > > +@endcode > > + > > +Destroy crypto session. > > +All pending operations are cancelled. > > +@code > > +int odp_crypto_session_destroy(odp_crypto_session_t ses); > > +@endcode > > + > > +Get completion event information - algorithm error, output and context. > > +Note that implementations MAY define their own specific error codes > that have meaning in that context. > > +For application portability it is sufficient to know whether an > operation completed successfully or experienced an error of some sort. > > +@code > > +enum crypto_alg_err { > > + ODP_CRYPTO_ALG_ERR_NONE, > > + ODP_CRYPTO_ALG_ERR_MODE, > > + ODP_CRYPTO_ALG_ERR_DATA_SIZE, > > + ODP_CRYPTO_ALG_ERR_KEY_SIZE, > > + ODP_CRYPTO_ALG_ERR_ICV_CHECK, > > + ODP_CRYPTO_ALG_ERR_AAD_SIZE, > > +}; > > + > > +enum crypto_hw_err { > > + ODP_CRYPTO_HW_ERR_NONE, > > + ODP_CRYPTO_HW_ERR_DMA, > > + ODP_CRYPTO_HW_ERR_BP_DEPLETED, > > +}; > > + > > +struct odp_crypto_compl_status { > > + odp_crypto_alg_t alg; > > + enum crypto_alg_err alg_err; > > + enum crypto_hw_err hw_err; > > +}; > > + > > +void > > +odp_crypto_get_compl_status(odp_buffer_t completion_event, > > + struct odp_crypto_compl_status *auth, > > + struct odp_crypto_compl_status *cipher); > > +@endcode > > + > > +Returns the output packet handle associated with the completion event : > > +@code > > +odp_packet_t odp_crypto_get_out_pkt(odp_buffer_t completion_event); > > +@endcode > > + > > +Sets a context handle to be returned with the completion event : > > +@code > > +void odp_crypto_set_compl_ctx(odp_buffer_t completion_event, > odp_compl_ctx_t *ctx); > > +@endcode > > + > > +Returns the context associated with the completion event : > > +@code > > +odp_compl_ctx_t odp_crypto_get_compl_ctx(odp_buffer_t completion_event); > > +@endcode > > + > > +This section describes the API/Interface being defined at a functional > level in technical detail. > > +Sub-sections include header file names, where implementation files are > expected to reside in the ODP git tree, as well as the name, parameters, > abstract data types, functionality, return codes, and exception conditions > of each function call defined by the API/Interface. > > +Appropriate diagrams, tables, etc. should be used to allow the > programmer tasked with implementing the API/Interface to understand the > function to be implemented as well as error conditions, corner cases, > performance requirements, etc. needed to implement the described > API/Interface in a functionally correct and efficient manner. > > + > > +@subsubsection random_number_functions Random Number Functions > > +As noted earlier, random number support consists of two functions: > > +@code > > +int odp_hw_random_get (uint8_t *buf, uint32_t *len, bool use_entropy); > > + > > +int odp_drgb_random_get (uint8_t *buf, uint32_t *len); > > +@endcode > > + > > +The difference is that the first provides access to hardware random > number functions that return true random data. > > +This is typically used for seed values. > > +The second provides a deterministic random bit generator conforming to > NIST standards and is used by various crypto protocols and algorithms. > > +The use_entropy parameter on odp_hw_random_get is used to disable any > hardware pre-processing normally provided by the function and is mainly > intended to be used for testing/validation purposes. > > + > > +@subsubsection buffer_pool_extensions Buffer Pool Extensions > > +To support zeroization a buffer may be allocated with an > ODP_CLEAR_ON_FREE attribute that specifies that this buffer should be > zeroized upon free. > > +Alternately, a new type (ODP_CLEAR_ON_FREE) is added to > odp_buffer_pool_create() that specifies that all buffers allocated from > this pool must be zeroized upon free. > > +Essentially, the buffer security attribute is set by default from the > attributes of the buffer pool that it is allocated from. > > + > > +@subsubsection capability_inquiry Capability Inquiry > > +To enable applications to determine crypto capabilities. > > +@code > > +int odp_crypto_inquire (enum odp_cipher_alg, enum odp_auth_alg); > > +@endcode > > + > > +Inquires whether the specified crypto and auth algorithms are supported. > > +Responses include: > > +- ODP_HW_SYNC_SUPPORT > > +- ODP_HW_ASYNC_SUPPORT > > +- ODP_SW_SYNC_SUPPORT > > +- ODP_SW_ASYNC_SUPPORT > > +- ODP_NO_SUPPORT > > + > > +HW support means the combination is supported in hardware, SW support > means the combination is supported in software by the implementation. > > +No support means the combination is not supported by the implementation. > > +The SYNC and ASYNC return options can help the application decide how > to invoke these functions, or it can just check whether or not the response > is ODP_NO_SUPPORT. > > + > > +@section implementation_considerations Implementation Considerations > > +One of the main purposes for the ODP crypto APIs is to provide portable > access across different SoCs whose hardware crypto capabilities largely > overlap but vary in terms of their implementation details. > > +As a result, implementations need not provide software fill-ins for > specific cryptographic features that are not available as hardware features > on that platform. > > +Presumably applications needing specific features will select platforms > on which these features are present. > > +Therefore, while all APIs specified here MUST exist in each conforming > ODP implementation, it is acceptable for these APIs to return > ODP_RC_FEATURE_NOT_PRESENT in response to calls requesting crypto features > not present on that platform. > > + > > +For example, the linux-generic ODP implementation may only implement > the null cipher suite (ODP_CIPHER_ALG_NULL) and return a feature not > present error code for any other cipher. > > +This indication will also be returned on that platform in response to > odp_crypto_inquire calls for non-null cipher algorithms. > > + > > +@section verification Verification/Testing > > +This section describes the verification/test cases needed to ensure > that the defined functionality is implemented correctly and performs > adequately. > > +This should be at a level of detail such that the programmer tasked > with writing test scripts/programs to verify the implementation(s) of the > defined functions can be written to ensure that all relevant functional > variants and error/exception cases are properly tested. > > + > > +This section needs to be completed before API testing begins. > > + > > +*/ > > \ No newline at end of file > > diff --git a/images/syncmodels.png b/images/syncmodels.png > > new file mode 100644 > > index > 0000000000000000000000000000000000000000..44e4c551bd803b7dd4320875699828d7f20d2044 > > GIT binary patch > > literal 17179 > > zcmch;XH?Tcv@Z$>iXhSqNDxrER8c~aDjh?WUL(Et-Vx~th$xXJz4smxnsljBLkDS* > > z-U&T7c+PqEth3g=pWb`(A^(+`Ju`dSo?U(urKTcJLIfnj!NDO>RFHXxgM;UcgM-UP > > zco&=V+&Rz%2S;jIQRa=N_smYZm=g1R%A)G;H}~-I@#)CiCI2J+roi>GZf!`WZf2C^ > > z)RvpX$JcFtiQ5qoYL6FkUycg*4Vd+@&4{rjkG>nkclWe8rfD1Kcc1XHC~lIRaY%yb > > z&#AzVI)|_y#V9pZhT`)S%d?B?+??Iw*B&jKn(0AesGPJrSZ@CB2`0NB4)JL96L+p} > > z2EA*#7UJYgNNv7slHc$~o1KpsjkR7Barezu`JrcdID~L;+5)WX%*UJQ&Yi``U%4(X > > zh-E}#FgHFdGdD9&|LPB(lF}u>&RE{s?M=6MF^#D=F|5EA<NV{oCcMa<zn~Mk<T(Ze > > z&0HR0nL<AyH)RZQ<XDn1{1sHSG^Y=gE!Bz}JL8mgNokN{HQQR8?0sLmM}k+*VtSKU > > z0(G5xjIBkg*mgar8dl?2>(#mwgCLf6u_Q?2KQ*N}ioKasK+MwbOk$c3&Z~KIZ=mPa > > zLC?i`823#_G-G7OIGO%Zt?-*4ASFD1bOllAd=>Z=)0y0vs(aX((aGyG^fp5mz!EEf > > zF>d?iB8)~$oLa4x=o~?8D}fg;$+MVIVN%ak%xZb5y40sy{T31f2D7)Al2jElI=#fN > > zx)0-4Uf!(2BHt@6HeOe~;Bhg-@+!)V3ysYAsLS76mS&4ywdoKN<Xkcj8vRSH?CpA^ > > zZ9jN`nyu1e6#Y_3nzMKf^V7svbi+ln5P6Btmp3WERhY<Khny?~P8Zpg?wVm3cV*HP > > zF7irVsHEod?fy`fjUhz9{Io}Ph2yS$vZyi)rbl*X|6+P8NG4lr_T`IRUN`;zBs<+} > > zT&;Tegh9lXEM8H#WzrQ4k0`6-rOIZab@5GnK@r4wCG}xiH?WAEvh^2e8oA|8_7(DV > > z5#{zDv#r_|AZFJ|X*X!oF;&=4Fo&EnWes7Xf5LE1ZL%z@!1el5uR?cCfVh?NTYPzB > > zBcJE;-j0G%Ppbn+w^1fHs*r*cspp$f(G$WC(1olV7+1;iP|5mP^(0==$z0aQYE_N1 > > zFJ;$W95c_yL552$#QpDU9PXBRRb|F>CNv1JuK7MGSR~?}M)kid{}5SM^TJ#tde-1^ > > zqHAH7)P6A@4^IsHUVRggU`~aL0v88o>F0e|d~9In=Gaqy9!h71JGknx1kk5a>{LRn > > zJ7WiSU7d^tmr_kniLBtPMh%Gv_z#>Ks~I~B1j#>TDETJt+oLT^>%d$VrsQ^(^G805 > > zKs`qV`Q@O}XIF0R3S5rE1tG5KaRey<eev{=NU2n>D%~0XZj&qBhgXJ-OXdPjX%P#o > > z=imy!?b@^Bdbyh91U3fS1-8WVR+)p~rF@V<{4{`?m9{iM{V>%%rk<_FJQmO&;nng$ > > zrTh`()rUt!GGJ4Hs6_n$G;B|fguqa@K59S3=7BW#S1Y_73S6kJOv%g%BFORd1>Wru > > z!u2w4OV|4}Q}I>YDXg!02-Nv(Wm^-*Y!s7WMx3ro>HuA`z}u}pb7Wlla_sN$xCfeh > > z-W5g#<HDupfx1pwl$br>rF8z`UH#Tx?|Sq_6f-@-8m^0-NE}>f=?0ZSkg?(OfT*s& > > zb{*dZs*0x%Ty1n#a>?cGHq3Fy=zNod!EhM~!B6L4R*B;U-8PoMFD@Qd*}L}J^ON5Q > > z3}1fu1ADd?Xm4aDO1ti>l2Ox^PN%VDw89)IJsE-(Op<Ns5)e4989DV%{7NE$`Jm+0 > > z(K4#==OJ^AIAuaz@=bhu!^+GR4DM`H(~oaRaYLLQS(zSQ!MLA~$1{y#A$MTpS)qZ& > > z*0}KkoEc%u(+GK>9QVU9&yPO_e*?h!qR&iJt;nIH)t~yf8;2sQj@A-&iD=n^v7>7X > > zc;w7TG_d4bWf^7^5ZGMr?sur<9VshcD!Ne3bXi7tV9IfIr74>H=iHEynQ_Er1O;1W > > zk>I$rnyotFAW|IyP#dhiq{>i+Ye7KUVEDs=;cp-67Si*Csi1BoR2<J!o$-Q|gS5|L > > z4+g%AHrzW;vt^H{v=5sKp*aU1il;Y*r$;Ia^Y}#fbHM2rGIS}|nrc>1Ne1U9ee<(e > > z{&18JjB@`B48?@mEPm@A`T+R6^(hEDWx-U@F$ouS;wIldeGtiCDpz<px&I1cf~^od > > zN%W~-ywM^`V#T5x`m;+xXUl^t?Y1c#oPFl|)POywWv3Ue1Rf=pkRD22iI#s?!(zJg > > zALmv^$p~`W5H3@mm}crh;p#o{<J!5r$k%+Po@tx-*!o`2m(0u5XnMFxfV~6WdcQKs > > z2!&cJ<gb+rKfCzGl@h)vL4`g#`Ci)o8TsPEJtNcvs`179wMRyppjGD=u9aiOl~V{M > > z1?O`1{aMD1Zx%(YC&-OGQ@OP2irm@5yet7qtA^*i<cO_=*_S2{{+@r-<imD)W{g)( > > z(I^dg!5C6}u}FmN5KJ(h+IyatbISifm}l$LOkVzs))VbdpHqIr*fe_s_)-392h0bK > > z#q7l;k(AFoiVxgvb^SK2^sWs$7pVbI7Uhnl=+@%!=@OIUzb+6J<47Lc*8x6?Gup>j > > zfdKa#|H%{VV1xHqm!f}G#o(t=TSQ#U=4JOAti>7GRvj)oi$!`#5kRe^uSsCFF}1s+ > > zJO;GkMoocZc}bvxWu8aQ29|!{E@UXVi7X)9f{Brr!dd(}=7S_1aVRHtJd)rk(t1@V > > z_N8K;I_(qqxGySwr|%Ibvg84-6||UwIHlq5w^uTndMghI=He7JUg7GHT&bqI`+i_= > > ztxz_uU|I?dAsW3?e0v4f0-c^yxG<XaH`Rel6-;HfoS|M>4}l*v)G!R1y-@_VPa|sz > > zd)68tM(n|97s8&g+Lg$ZdS#~UhlVpA!Z{m#C2DhxGHrvl-+h$*8loFiH0};{B3IsR > > zWdodZ^gZc(9iidRH=J@(u!2C6lbpPcsxgI#ol`*OfkRPcvZng7?3Y)UO(3N-jH71- > > zQHldV@tK9#seT88b5Y(PlZhTUoe=gMVBsb=MPj4-5$>dNbTpF=S<eNJ?Nr?$LGwl_ > > zP;RJ-)L(7#hWzES#oUo1T?6DX)v>>#Mi|Gf{-k=J+&17tFy}ii>>nI7^tUSt%8z@- > > z+R0@A&uhTt>pE=^DwFjfJ$F;C=1~{aBE?cUaxj~R#~ufOThGm7I-oRst+i^U3XrR~ > > zoAQOFs|mk%yPn;YSh}`v<itr_FRbtRUSM8|$lmqp8=#i3(7$WxS;THPc1;O4vZjdO > > z!eRfY2z63FTji(wvXH%-So=!}$Y*f5xAH6VU29)mZo^_O;_=zmi2r@M3rtx5j}K#c > > zF0&`TcR`K_)q%B_)*f8F^6JAG&ZRX+h3woDZo})g*I)5*_LV}k8JD@X5O$2?4>kQG > > zEgbtJ3*baF<V>?13RfJ+KUU)K6GL)IHtt8xfhpb*(}HE~TMDw1h52p@D?H|eLY&## > > zwR@C<v&4gAAJz}Tc1gQt6X+r8f7sf0VxwUWO!%b7t&w%Zz=m8i$k_9m2xARy25Jee > > z>p3Ii!e(CH?Hd^ztnl+@B^lnk5pAlxr2g97Au9vchAyYrrSbR|XZP|rvM+DsfOQHM > > zyimv<J<kon1<#jpi<)icJmY%GNUOv+F{ZxPC#^;g4wwl`l7o*vf;oZtq!^9QKlGp~ > > z(tM+hyL2fSOBOpxD^mnh&2NdfO5uIt;sy5!gmL>yjSUhMntY}K6W(>=TA9MA`@ > > z3mUA+4I9pd?s=^yKf2!-gq^UX@ydJNsxb38gCvD&hO!d|7zyHf8zoz9Ii6N{R#Z}` > > z=adl4nY<HHRqVrNldic1Vc(R(6&#mo)8n+54;7=zwNjVW{l1s>ynyL?zQ4DpR1p<w > > zmYy!(v;VG{ta;<c=WK1aR+N41k75yyVNI2O;Wcj72;6G4CTu3->Qxkl&-Ya=d!^zt > > zpc*b;86HysqgiW|_ZK(6;~*U}&tIUxoHAu@pGAGW>h3nWdmFt)S|z0i^eJvlAij!a > > z8?A<h6hc@wxHSsJZL7yPHC(?lTFDyQW-zkCFhPOL!GQJGJ;Z*v4JZX@_If84{-LQR > > zRm6YNMuI<gb;;WiQ)lru`(&8e8x|?4r$b(qKPwENt9I(hqr7AJNsYo>y<Pc)I*@oM > > zUZSQHAGH{o{2*b>Vf2p#(`bQIaWP|G#;dX$a|139C&QVr4TPUGI4g374q!V*W0L|} > > zV>7MHT+>F1HV~LP&4YNDUS?f-DFK(NTCN$Fa2%Z%$8T)B1JUu=&5HAM35Wi70Mp04 > > z<Tv+ma0rEh?|CjNP(RJXiUmR;oLyS%X#z6-`({4FTWa~!f-U&ZjQ{##3;s6&w)h|6 > > zKeF>${R7~eKD4{v3FhlfAKUa<IgcSVCiXAl{iM-;nLYj!9Gp2TTsD%aKcJ6>nj>s! > > zkJTIGY&t**PW-Bnj@BmYuLh4AIz^&_@8ASSurGx(qG#+IWXm5ls>~-16Q0PHLokAr > > z&h7W!(v~X@=1ng0lm*>chn4v)cQZEFY+89e-96l_(1`!l;^|R6Z+GQobA=rgj<++O > > z<FxKGBA%*lZo3ZF*^&eUmnaX1OA1^z)Un#KGl_T##>3+sMC2I#ZL-G!V4_u)<3@8* > > zQOwK0I1|UzutGtcF+L$y)<JQjnRrHywF&p%<EK5L9mkBa3v3N>eDAKto*5GMHZ9@% > > z_;a6cc#G9IQ!oT&kO@|l0j}5TyO@JeqBjM+k41i-6Wq>$s5x$fV`y@ZfkY<}ng;h? > > z1J_dY1!QyNUYXrOoso3g#Nf?+u|<m~iAN&;di#x^M)+zmjKc`L@NT4tWSwok9>cpS > > zwUgKR2k39lxb#}H&4*Kefe=CB7U%wrsy2{*0jr2D?B6aPOaoWPWrO*y4Sv^5{oWVH > > zd;x&><&5=iiNuB_-2}$(jaga_wwZ03k<)IFeuuGjddUVKYSbkqP;@<)sF~X%02mJN > > z$>E^`{<dl7xO+m4dk<@{$+gX!(<E@2uRkTBH-tX-YPOKk|5a<3_B;4?>FzNt;a9o4 > > z2bl4j-Z#0+VMv{<2ltkD;kEmZ<@k)%b74-{dpVpi_!4_J{MXky66fE4?Dw`9=Rd#L > > z;{O}@k~kBC=3czvFBS&#Ai_C)vp3TCZ2@<1oEH<EXz67f#auag&ebj(B4H0nQ1!x% > > z-{h=K&}gjm`dG*}lWBW<B5-y&OUe&crhKmHq75OdmP~?VjoAmUiWyZ;p^Sp4QPP@W > > znOz}QN??*Mx*HVtfz{?QaXXp1aGr}7ZO}DPMfK@YA2c-RMDDMJ!@=~`t^|~NK~)We > > zQ~mruuL<lf3`VT<60(8CTxSzfHTh2U(J>0XIU&2_ER*%>*Sy(|ugRPb)gW<m?^jQ? > > z?Db@F%eD?=0si+mE;te{GhI$>VT@dYvB9aMN3!;lEn1ziTobeX#B~@}l1Ey1GKFui > > z12Iv^tWUk#rOs_{d&5z7wdH!as4|GdCU1dhQ8sFu2E$nV7T#KZdC0LX%DB*8u1IdN > > zV~K!t9F`Wcr)gBJ^V1o(MNOru|Ag%V%c2BLy-m=(xqR(^oT(9q{b-Sd$jjHFt(TB~ > > zVuZwj5CP6v;P}f@Q{y&06CJHTo~3wwM4$rgMzuB%Sa<o*n-glH-ll0D0!Alwf|+dn > > zJ3BtcIB^?3d90?7aP$YTB75JyMVle8QN&2U81<YS%W{8V^wW)y?RQ`u`S4&$7v}lo > > z7EZ0W02f85WdTv~!}*{>Z4kMy{3csPyS->6CRTsykmL93Pg<4I9h)QWljA_45*zYK > > z%_U)Fc{b>yCC`Lsch|yZ$l6J8mK@26=aOFYR$6LF>WRa1W5$SuHl)5Ol8Ka$M5Fsy > > zR!}oqj~olnQu-nhOJB-W@0%&1No@7&Pg<>1I%vj@g#qp*970HtICfX!sAYNB*T<As > > z5#O4GIJ-2Xu{LG)rbcE(B)9+ne@ou{_OZ2y1|}`^ZiCUm>0Z#bms3Us<owD@A}QxZ > > z(sKnYC*CPd0piqAMTwnSaXCB6Xawrct*lY^hvY22W9<E*+BvI3<;)c0;)|6OI6v}( > > zX^Z4`Ur=cnFy)M3%6hMTOBf&Co_C!6LA>(7dL!PoabUw_<=(v0rRmQTK?wjJ-y}Wa > > z0<vy4(r_)^GtGCviRx{n==LC(JGJ(*OuLo7SeuXr7fP7h-0M&{1^g5j^cJBj9~c`5 > > z;g2ptrB(q{Wxj_(w-@7Xf<~?n{T>lFmk`2k{Zr9qY;iiHjHp>Yr~juJHcH|J?Z7CR > > zQTHZp?Ygprh4CN@7Aoyn(@neMOOE<#AL6t~(W<`trf*_o(}-I8@za#7y+vHfh#Q%e > > z0}fo0w{OK04h~kF!uo7pa=M!{U0gpQe$Cq=CF8DF1&Ar?bCIUDp^DOSI<Up#sfQ^G > > z<ZF}$ebc)Y+BlM?A4H;L)wct=1S9#XLZUo&N-z0$SxN8>e-ore*8cPk8oj>IDszVt > > z!#efRTC!`3Iey|{|2pgi-my|Fb-i~G8Y1KWjR)Y2bv9APh*f3#fPb7dMhAmg)gyyx > > z5l@x>bEHPjSJI-pJNAgf<#)I!g5-wPu0)D#=kkRxUvGgZynjpLY=n#U2W{N_Mi9hl > > zH-d?W62W9L0~9R_v@KU?3P)LdEpT;cqS@Z{rnvv&LQcSlk*fKUZP;~gOO)$wG8#8} > > zuFbze6l)bOp7FN3P}X#asYY{Aj6uT7crI37FREww*S3085AVaYPbCKKLDyzho5)a_ > > z0<dLAHzcaCJJ3QYJ$8)80uMVe|2^#&7R|YyRja`sVE+0suYn#licVlf{F2L4DcKeW > > z|3{4<dzBZTellJ49XLhpectV7<)FK31Lt|iS}k<81RCaC9NRKPZrz%w@xdp(=T7%g > > zc({xiEu7zX(ui8>-(zG}sRlg}H|r;94{L@AFtg+F1(`Rz6fupGZENm924uUkHm4ix > > zhU)vZ7KE8iyZwUXN#{$texK`yi2Gib__y!d2a3Gvo9H$<8oR;Y@_7aed>41Ee5JB^ > > z@T_dMofuuq{k{1@3cE|tp~K2RR&q~~gxOIDIeA|1&X#zUb5xxQ)xpBp&V*zq*JjmV > > zZ-8?Vs6RSNc1)q~B2J4WNI;rP@re_^n0TDyJY-_=Et$OHSY??_24C!PT>ehZMGeVW > > z5k0M%I-=rycC0oMlae%c4?sBD8#Ge;0N;mmBQT?$P7KmH9=)!2*h;nPH<YJ6qLcrL > > z4RrO8#7TN=-D+D$Su`MD)Ux(L2JjD9Ze%=5Esbl_qY71uA97v}E3vcM+6zUrSO9Tw > > z^p&)A%rl~ihx4Pqe<8xl0?WS9Ua=-fgZ%YV=u&xwi>zSG*MqZuf<6Dfk_xPM`WpWd > > zKTXw5-g(X-JMLv)TmHe+82}dqJo^@4MzhhP&=#B0^yItSL!%smYNTNdoF09?J0WBl > > z+bgD(rA{KFXmsremy1DZP&+%wUHKh|d~=Cg)R_#3;TXMcUaF8zI?=u2E@?w+?~2b0 > > zK5i2A24}RgB^lWQg0grGWAYv2N-}<Z+L|eG8Q#F8g(FONlheXEO^)$>PX08cUd-lr > > z*ns1GBslX$vD-;xpJnBz1i5ZV6Im5wr;&Oai1I~NFeUoUwPx&8jm`JINV7$dXY6&# > > zv!!Ah)UOsKM@uo35LUrzq~)NCs3kv&#dLxQ3`e#l?zfX7gyQ+dt6CyistjcFh9dwt > > zen3xHYq^xmVbtW2C7#OWO>OkmJ7<y|;mPGK2vHMkTIYl2Lu3D@$k*eqU*(~6PF{cW > > zzyyYWmzcZ|F2r1pr`ulba6CqW;y_S+D~BHvoBdMI=vvup$QZ0^m{VCNNRIB|UQWnO > > z`FBw#>+dY|1vog1@hRjqDzs6!Ohah`+IO(LuGta7QpB&)qrcoI2||6j>pjSytw#lO > > z9D8icx^xN}vRuiOA~qBf->D;)F8L7LPYdp@uKHnqAC^sSHt3z#?jY4MJszOaflkU1 > > zV0v4PZ&=Yi5fg0pSIR+Kz8XKRRlZ4$7KHu`Q+?Cq_A@4edS2S{Qj*|zEx0WIPmJVb > > zpdAg5`8bo4L(L83?@e*OgX9WBUvE&&W$yygI5TN}tacj@XO6~*!?MZG0+<XJP_fI; > > zG8iUvHdgZqVo+N7#<Ij(%QvkK?u13T$;%oEQI#swMstg`I046)>hPWb-*_em`{hVk > > zkEJ&(hcT99yPO?+*nLFxtm=_p=?~MrjNPmU_n^Z}{K(gPsvIm0nSOQXh!tpHF8LJb > > zQUWtb7eR<0&z4@-{S<RWn~5UP=9>M;<kx=AcW|L&uDg>vF5H)2;FYv4>arT_OWSqH > > zt{dJXLl4M7vodYz-?yelWZJ@#4xS}yGw8%84cg7$c$46wy7ujmLikvj)<U^M<Mew6 > > zY5jM0?!<DVPViuHm*)q|wEd*@0no*d?=ShtYtLW8!bl;z@rbcWX42E9IL`c{720wL > > zE^%*|dtormIFyQ<DNqXB8oj^ENeHt6aLSU@6t)+EEBx4(?i$&e(0bTV+dgM<sFSoG > > zEXFWF^_5kX4YzpcNE?=cWe$3Hjz&jmNa~D`^Bu1uf-8kFHto7$8azi8$m?j|z=9iz > > zT&ypr&0&T6?!rtDV?%rfee)!v4C|eQ=IwVSd(q^cf!c0U0Ar6Li?ZD1!p&;x??2pa > > zpm`YzzX4~{_eYuW91VwSc&P&+>av(>Fk5LTUdtkghuHkOqR@GJthOSV|0MMVq_C9- > > zsy|P(88q{C1MVjpV|;sm8b(8qmE2^``!XA9fB@Q+C)HG)S5#McF|ud}BSNo1jtQ(I > > zyFAMMjSBu{K6_F@)OWeO;dxc3JtvnlQ;u)R0%e=7l^TDo9G_}h?J71Nb>rj2hmXD! > > zL)({6sw(36Gu+jzJ#TRq39d)x*$Jo5=kQedpX<FhHKNskvivq*Oo)bQ2PnM;pPA=L > > zpT^qKHxZ~^EX8|doYC^%_!+L~gRgng8`l=S!&7p9LBCxmnNFuOAk=;bG`|tQ^2VhS > > z$W_1NU3pb`?1sj=1{lJrZ2@mTTG7n$l<-`djWhnf()3Cm-7R3g1bnkHd@bfH)iE_h > > zD3AXYA_mve2$#mS8soDV<;%NdHG;cdC_P<D3CNb`3U|^Zi-x^cdsDwV6jW{XyK_&% > > zfN}Dt4y)s$*!7z+mYyK>R#$t~u0Kf#e@|M`Ho3AUHNT(?VBKN+u4>28UWt%l|9t<< > > zaK}+yg?fO*nX=}vH=byVm7Y)0DN~*cT66xq#T^AimQ@koOvHXG%AIBLD4_Xc-*}w( > > zgsmK8HmSnD04M6Xc}mClW!p4Nz(E!XTe5zI>$Ul=WVJN9>We-(X~=QYeJ;1154~Ss > > zK(-n^cb>L-4yAOfzx(OMoyD0QEVpuVtLI}L3)&tbB%pgR^_Yd+qYh#OLi8qc;sNgj > > z@i3KbQ1m9UHGWG^6TNq3VNrBi;d8fcUrzwjgN~A1ysj}cv%Q`-X%%}M&CFYWDEC?S > > z=d0qRock+Wt~XZDI2{qsvU4u5^#@LiT&9BTe&TUe<RfQ+I2~J`BNOPyv#xhG1=7@a > > z5_AMm6_%?Vsw1a=poK~C73wjer;8-5bLlOlu`~PqSaU+*?|O)K%j4BP;<{(Eg^R?v > > z4QiKnbPDqD0){2}*%J_XVD2|95Ciy~d*j9YHe3pN4BwI<2q`a^bslD^%t|s$yM(~7 > > z!0t*$VdU)S)q9D1%Y6pOdad^!e{Z;O*^E+XKS<V;e)oTve1tH%h)Qv(GrTwmXB-XW > > zqY~%cuBO7^1M9T&*%-uvG2rvH%hq_AxraK0j&(m<N%3~qE-{z(MW?)tz_OsEpJFf` > > z4s)5bvZAHug^?vC-bc%Szu9fyJuzF$eWp7=CLs2+g&VyC{?_zsN@s+B%KcNS=yXIR > > zW;K3Q5$<(uWwCDf+Qx*5a4`rj*Jr~oG`T)HeCYjbU8krV(aq;p!(rN$fq9^4++e3K > > z&Qi=AJHxHd6mA;x{%g2*oAAdke-emcf1q_A|D4ZDxPoq@X#%!~R1RZH4Y>4W!7CO7 > > zI5_kgIo;oa3p9~FdRXlctLl2tVQuem>+xW?iV;@%2ZDg0%pdAVT%2Gzl3+OYX!G0h > > z+e#W0lw)N<EHD<RhAi5`s>eBZCI5qb6ldIH^ED36@4}HnT#xkssDaJHN)BvG<r@E5 > > zij^ZN+`7%nRKJsX+tTm<P5a+k|Hllr-~Xb`QNOeK`ac-NDa7`Q<>g<?nd<+o<d$_T > > zoBx}m|IzLLvD#Ak=JY?yw0siNwt3;b>T2ot()E1F`zFNgvYhP3WHsOEbN$a=z(D<1 > > z2c1<oli>SPv`o2qeauhK-r{fq9CX^Q!9$4((ofDJ1*BA}u$`Cn3<RxuQ*>P16SMTr > > zIdVpgucZ_0?9_E@61KcE@pfAu@^0_Sort5c-NliMyrXX21bO%xsq!?Q-kigcovJ&u > > zKYmU~MsmwJN_FXo?Ke2pL$xA}L54W6f;6nA%@Xi5boTHm#vCZ<^Y;qa=y_Br3X@-} > > zohc5MOWNES{VtZec<tleQh$v@TZbs*EFdi`*EKHD$_0$y`QT^gQM-1sZLt#sMJ-|w > > zd)f)vejNUMa1*19cP6WvPbQRwV<Zibn4AQ^oRd1_8MTW5Wh1ZefPOb?t+A7BdeTL6 > > z_N*IE-4(apYh$bucAsJJnsIrjcaFDuKKXzVGI0U7X+J?{#)1#k)LXw`Lda{yug&<& > > za28eD)=t(l_yt=;GxL>m)cH^(z#yZ|3fEY<>5V(Xt%E~0`f`IE4#FLMjJshz)?ZI> > > zZD@ZPC+@x(`%A6l>!;k(bAmf<LN7zPIl~Xha7VCEeLlR}ZH)oeVRVeWC0u%v5+a^1 > > zIlj~JtxGsW@>y-VLyet+%C1lL9sp}MGCw@&E3^Zg=)5?wpBb-sR%S*pFPM9RToe&@ > > z*k%Q#XH9Whd*6|3TT^Ogc!6GFqm(o5x9Xn1v$eV}wX@fPj_D%>OL+CiynE!eM!V?? > > ztuk&NITRn=(eb5g3bq@&ct?t_9YIu_ZCBe}Z#Q+vw^^W$J~{(bhEjoOufHtMq1KMs > > z+>~o`ur}hfg+pw_5`{=#9s1;Y6hdSz6o<toA&m^;)&Xg17%_dpfJR4KVFhE`I7i*v > > zIF|9&pir^kdf~!%>HI&UzbfxOI{EM-*9pQ&6I;C(&Q2hB73xz`x^>5r+glgDL~^9r > > z@plrI1lpAzQ=qrIXn0AVFK&#{ZZ0Doj22gN+w^+d@%JIVVU~wBY(`=}?8E`PQ`{yC > > zH}=FRoOQ}LS9A(F@A(=}=qhjO^X4DxGZbe61xYmHchTD6A>j?SoBHaq$dp~$ad>rs > > z4Fl<J;unGC8sJbkJwzt~lyzW$3q`_3vrztgyezMPdkNjNL@@Ph$jD{=4iB&WxrGA{ > > z{mcF4`Ti8$#?~ZiTfYuo%o&5z_p24jvu(TdDZ#bPu+wZGl^Ls{Ux3o$f}g|+gSunY > > zg(=VnnCcaRIoM>fV%g$?zV0t?Ichw0)YvtnH{Z<fqn)D~>mOB+lt@J!m<4V_Hi`L9 > > z-G{b64IoLusS`(UeTQ7+a{R3ww~KAQ63^hQ4R-8LHIc8s1X_qpp~pp=1dg-nvPtPN > > zr~cS*gtfo;C$RwM@~w`F9K{6#^KVnvF$nANK4Jtz_T8Nzaf8C^XB3~${aBYA^>qy8 > > zjFS12;z;usP9NJ%=L`1;diUo)oQ4ZL=Kq>_fv3i=jaX?rd`~bJPHrhK22#$LN2TOC > > z4R=nIo3yytcxma%izp{kWz2k3?uN>tr!q1IkvFm9M^4^)K4rtgLDxwh2r9xITy9h< > > z5lnSG8Cl`6mF;%x2>yM!96JdPYHjjF^)vuNQ1zr<FUkCzj_F|vZGhN*5u7s~JRa02 > > zjk@#)S#!P><=+zCR9gFI<;7W_<Qjc{o_-LJoRoTLOP^H!>rS7<3)WAZ#j@s%D}TPQ > > zEJb&>n;?|jW`Zvr!wkrsy(TNU$8Suqk(OgIN+)CyCue@SX1SWq;rhk&-5QF}JqX$4 > > z%hG$T=Hnm+x%npDV_RQ=SNMjYm6np?46Ybi?>JIB&907IeM+{Mn}195P1^J3->crO > > zvX|$5F3nxMa;S7^-`ALHYS$gPLD_ujCKowt71!{WikHkemE+;Ho7Xliep<sLeG~05 > > zEAONUjO5lB%x+uiThmvM)}RlztV;s?*Yhc-Dk(a_drV8)Z3aP<7ka^gcPH-6?~dHl > > zRd?ET2w-1*Nv{S4_4Qx8fBceU_#V{rjS=(G>8G~M@ne<E)NIlcN3Kt99KY-NOPj=h > > zzmDx1O6vL={)hWTW6!>}4>XarMZL|aq1@hX<#ocdLjQDOb>h%H#;uY4g}*2Cns#!7 > > z<8>jEIrJxER$MMS%J^ola2qN-CcTgmRJEktGpEAdioa~6B}{fz8G@9zTo8>;e=Ju| > > zrbkSSJyC`$&e6DKZqoVUNy?4rje~t)JffCXU~g2B@>JHlSP|a$(}TOQn?CUkG>-D5 > > zCsmo}@3^RPu>?kGd*pZ^<?0mX-Yb>*%gGqx-+Uq>KY<G~5*Uy+)u1g8S?Dy_yckTi > > zR;K+ddnB1UdDouP`~6vJz<P*-#AJs`WMSj>FT9m}@{_<t>n1HTF~2erR2sQ6!AV2e > > zpR<U#z2d3yqqH9lMHXWwrxWu#yokfEHWo&D<6Dhpo3&(~vCs+C!SVUDixNAdVY`p@ > > zSsuN}81*tX1AXj;;mH!oI{=>0mCe@-rGp)roo^4w^D@Gft_}Inp=g6qXJ$IRj$0Sx > > zE(oi((o=}iN!jfL$dsD3_|?pV%7w8Wq<!-QIhQ0;?=O)S4oe?$-IR@z`)}jQ|1<rN > > z5Z1xuxJjr}VCz_)8K5}S@91>>p|84RNVtRqdG0!h8Lg22&szUq|NntEE8z|+OQ1p5 > > zzudZ6FOXVqDNA^_D(3{E!@~5)y7;`aG8(>7@6N}s`9bo(#4k!zi1u9^o}Syfm-)i5 > > zz(X8IFj+J0w6l}^!*MMplM%m`H*xWFEP<TT@I7|d2&>E0xdx__S-@Rr=QF88hc)U3 > > zv6=K|9P8O;BI-BMXz5k|h(kCS7kzrpDu~4!NN&+i7b!^k#}Z5-P?S|`n>z~JuB`&P > > z;WrmOLsN@bXR^fXKfkg#=jrapU`o5p$iC0FUfCH83zZk+Dw%Ub%s6q8ylEa*fecOp > > zRd&HX1PE4tf3_`<W0qlb&3n|nhrHYW%^ezknR1`vK8mpfY0)F=@AJ&LF?e=(U<`p; > > z8S!DrS>YVni`aJm>RP4S{G2+S)8w)oReJbE)G@Xe@=k6i*`=?M`k94SLPqW-;=231 > > z9$9dppC<Q5#kB^zTWX_WA}*`_$qF@*dCHy1?lG+Gs1g?l;|Kl#M@SMZ8u7}E@2uqF > > z@=1KM2&I;3SIIVh58Iur^VecLfo7PKd@06ycFRveG2Ai3IukF)t(BEJyX{TWV`L(P > > z6jMW)TntQD*S_VtX>upFc4K58vHF}niZS4vTNYKAIyi{8GCRv{T8Q12?U_`f(OhvG > > zb(g>7G;>K4;C`p#qCZ^zrtHnrzWT2xhy(|*n=Rpfv$WQ}s{1RMBiR@JVxF;U-tJT? > > zhE%QrD@_4$!%oKtfPoiwOqmvVj<4#qK{cn$MkQla>|b15tGQbjmJ=hR-LdyqjI73^ > > zh)?pA>J(mMzz-}^-8~6}>1(<VyzSIS%Pzs&5>;y4CBJ*AoQ=Js&xp8{qJD3RQ9ffV > > z28NpZ8)xK~2-Xwkn>ut8_Kno=`}UigPSZx0sYSiNcucsa>N3L|@6uR=^R{oxj%#Vv > > zaHBr1D{rIaG+XUdQ4gHbRQdHV;YFT*-t3gI>hm0#tHEv)whe`TIo8MC>TD+6fu=53 > > z2TJ2?8zpzMw^s++X<~YHKeJ9EoTcPUcSM&hu`0fGa&Qdo88MvE3>QVax#g9`n$1Y= > > zoyDRgqe8U-gJ&NgT#UU16unIEU;36KUQ|5}6k;oG%Ht$|1sP_w;*b7Z7tZHls^x3o > > zGp5Ev62kdo;9$c2JTNj$$&*IsRjGCaiBX#i{D&&R`E=aaNF^_o2ezJ5CsOe3WimVU > > z0Xy>e9G3Lc);^%0BZ#*Wi;_Ed+}CF_R=#2$e)wDv8~c_liIkP3Bu?9lKAuk&BzIm& > > zc@$lgD{?SJ_@nBTI_rkbBWE^Lca0JM-64asA>zCa-2nwy6s;(7B1JbQFt(%qvRO-2 > > z#@N*7s!NwFpz&);5|}ZCm50pv#I5}`*3iAOT%*WmdBCOwP7)H|Lz&`2zxKp=inR(i > > z*eke-1+M*@BtX>rU-WlS1aW(=O;N!jHG~8oXIEUbIG!ZxRc5S&8<$G7luQx{Z3r}1 > > z2agHu=vKbk(to6#bLncSXh-(OG&ve!z^1H6*R!F}eJ4K&Q9=Z>ymRivvovII($qB; > > zzk^U}v(P(u$2mWNZ<y0NAKgD5Ep)(kbG!Lu&wgILlq=36hq^$jShinuz}-A>y#&Nd > > zUs4f<CcZi#*Z<Hob!fuM$OI6Ive@4b;Tc~z0;lpPd!)GUU4Ic4(Fjck@cbHOW_!(! > > z(UNO4WL|nWqz4~06MW=c)pfY<AIONicI1Wy8Fo_!+V-~Y-JGnf%Gmca$H*m|vA88U > > zx!%}(tmCVy-*x+Uz`u0P9D}I1UaD|aeSgwLQe{Ml&hL+8o`rmw{_NtV&;4-LptmWK > > zECH(95C<ek(;ugJwlCE+tEhnsRiZdsvrp6c5+08#^$vl|s+5{7Lu8WNFIhLP#$W6X > > zT#{H-7|XVu>ot9e5aJ=vdtGycg&<aWUjvC7r+jH34ZI{aElO=H#Pk{6H_S$XO)2Rf > > zn~0xzKbThtCAuwEIskmM#OCCI2e5VsZD&oSgoxg4&_X{nGItgHz~lPu&%?%(zGa%| > > zgsIB;tY5)s+l~tp#)sRV2EEsd_^;r{5riMYS%hVryGVk>RHW_S#Nda<%CoXY{w1d- > > zE@f{Ph;z&4H|8-H13a(Rlz+hq0z8hX@>aBbU!JC1*}HkDL?z@{yQ;X*v0u~Ig?gqp > > zgS}LBb&aC{b^_nSQqlvH`L+n&+tWNqQn}xuh<|w@jGMwW_D;1=$gFf>dU=SEDo4nS > > zuiT}JN@If}erqVTdriX>yvrMZs$qg1#_zXpimCV!Niz*!+^++h1R>7egv^tO;bb!| > > z>^{K(c4^z63p;G|Y>$=CF%tO8wjYFGvvH`2%NI}64Mvw!I~6P<Ri%s&1KlkfM}{~J > > zs=PMX^5DzJPr~1#m|yD2QT?X(Yqv;19`4UYusD{dgnQol2ljgteo4MOupGB<^=@BN > > zk2XB{KqQoWF81ad_OAE7>dj64#@b_^e;x<sa;u(%1UWZBx>UGb55){5Lf>nlWA;Cr > > z5FMU329QWog`aK_mH%ylU(_5plziX*9Y7J05!+lISp3HK^@->KXGR9+<_-6W-}|A2 > > z`$~2|OiQ$O6nIiabmB#mw{ITGamz=12PD>-d%0k}ApH|mcC)3ga-E-M3oK~x^-O)K > > zM}nWm<-u=Jo~nw7+%rD$DqXvEjmAGF=MQ{2T<TcyIE&x1Qy;eEs)$x>$Z?+!cxh4& > > z%yQ3O9*Fr&L*gWluG=^O0sK@5Ceor4L6lYz(V3+*s}3nt1ug@RaaWP0qMBKPmYs&F > > z7dBqgR6>}tbvkAA`_-%V*&SfM#>h8|W<&mLTgfo!aEwNl9_ca}TnU)3rQn;O^U4PE > > ze)%UJ)^)RwPv)}9ZAAc}Tv&EneaD%!4-O9|?ov@lfBPgf{VFj0_$-v@A=ro@3zM$# > > zp}MF&f0*!FfLCCtu`$7Ncz2`q=-Tve{xH*ma+{&PL;!*X0B7@6nU5^;RWs(1)?HKj > > z{^dpx=qSb{9<Pfpky6PPau!d9#mC^N#zaSF8HQU|O=gCW6KS_O08LzrTeaKjQm@-< > > ziAbtSr_05KTO4HcBXx7)u<^Y79v*g{`Iv>bplO*lEiJ;qLdoMNcDg#`&MT}x)Pe;l > > zofm-YMqQ(HcHB|IOiSjFg6EVO;cuY&A`ynRxU~a~wJ`u}xAelC9Pe{yHM(PbVx~V6 > > z5jh<cn-jt`0F)r8XR|&oTa&g+y{U|jF{X9YOq%1JzkkJ@DrS{Zt$E;LHBpxTXL?0c > > z>5Vb-5>W~Y0LUtlWB&m=S{b%)nE_qtq{MY$-S}qExI9{<d(iJ%$H%yWS%KQe`cwQ0 > > zLUwZd=Vt->_fF>Yiuti2*0D_KE=8xr>#$F5Z#it?ACF$+nXp8z**u-fKn8SuI)e|k > > zh$F3&xB3YC>9@Q#V4_*C2qmaH7Zb_loD$sv(u89RhC_9nr_GN1k(L?Yp1S)EDaiUv > > z{{VW|H$c~)n7~9GRVT9B$h>5J@W&Vvdu+H5XO6a$Xk3oZFgl%%7#qKQuqb;gk(?dO > > zAA}Cb0Gq=a#P2(0cm3%LHWp#Ifv*U5??wTh+Wiw-!Qcd0W(%q>N?EPeVJA-H1{p?n > > zJ#PGz;(;$}09JungDN%LH9zkj2QB2qm=O`IR1AV1`air!6ww>J@<X!ep*f+F#FFrU > > ze7s!?GoGm0Tky$TO{2cVITj40{S0p{vH#|K6(Omf+eRJv)0Ykq?e`Fks%NPFugAq; > > z9cj`8kF3sRErbOw8>4cmOAUvDg`EBf%h+{S1?EX?E=Cg_k65=8`XyYge-Xa!(H&X` > > zeYU({?Q<@x664!Kxa`36smBPO)^;y3UdMO0_##5S^VUBjfwj#|ytA|$d2KERM;S1# > > z-Ywdk!+VYohg&PUcP$*$=W3vcS8HKt%BT{O>lkR=sMEUbomRb>=h3u!#SIbXv_BTF > > z&&AhBahCXAEsfTNay4_jgipj1#x{YGtP~>}FBl8w^A=faA1R%=8e0()r0qxzmi&EQ > > z;+!%_=IxoFf;b(O#T%-KWi}nGu;p>=2gMm}X^&WwKRazt3n~sl20FROt!(^0JovMR > > z*sjY;VI)E6F?~X0>{{%g6kY_xmQMuwn4k+p>QmNa)n*)chr&^wmok-6M~seG`}-@k > > zmpc6<zbftUx}C>)?5V>ylxKY6)z0o)Z&71h9LEFU1#F0`#0@#_TlaTV^)DgBeK9+n > > z(lb$|#Es|r#~%m1rK@bHxR^A@W3RdM;Z;Mew(~0mp$z4zm=A3njYlPE5yXk~@NU(I > > z)BeXBfwX}iHqX5u8y8bEnjBe?OENmj;LO|j8t<x*@-|^~jf=0RimzltoK@Rpn{aXF > > z#2MMe8;|Bc#C!-YDbeCFO#Pc!1q95WM-fGIzt#5IxR>T6-4+FM{%wyM&)9?4YBxGS > > zdEmlJqZ9r2QV4~3w`Y{6l0xXw8L*9aKjBZFpe;7aytaU<2zn<w3USfZhTJ?~75KBV > > z%0@S=>wlKvN5!?*#%WXR6*eZeqoIY%v@8#o?z&)|tY-oU=g4`7Wy{HoeTo*`XsJ!a > > z%@y(BmHvHF|8($6{>FO<w3`jjrYEnY4(yeyOC~rV{3XH+P$VqIb7PDcXM7&G<4u1a > > zl-biTf9~?p4Va&6q7c7l4ZD;xd^;WZTS!Mag%xy_LjHAMq0tW43o?p5bAoII?GDOa > > z->FSl<{KVw*Wi^Z59{ghnJ>0o8k$jOYnXJ{gCyIYEn!J<$ejOyK5iZF*z|Pi_V@pd > > zyiUr0&q;9pfklFYrEj4h*yjI<=Uc2NHsL?{Pm+j#D3yQckpD*V9~}J;lK*1*wmzZI > > zf05jFvae|!V<=DDz7cD<ku*9*-`Ln2yLFoDNX?{k-d))b9P*-8?Es&&-wK9*jh1(~ > > zubwhB&^00#A5UU&9UlYIxyf|fZLt76Bwb@m@5G4?{z^mi=S^;+;q_vdKi3iuu@GlN > > zEL`m0Ae`yMWqB$vN0vd*=oEo@M-4vKOX(Q(hTVP&XN`o}s5!|cNV}uu$=3Kvx}~3d > > zmnEMoCkNd3CBC7K+!P(Wf-SNDGUm#L=jh#X8g$bo<*?z`#U{m9d-`vP^sFGPRyi}+ > > zLY*+HdEk-RBeV2G-f@s+60UW^ne6~+kibH>$q6Ii5*4im2?mq<QtDbG`&1_lr7jG% > > zx&X1(au)+!!JKow@ybihCWqp)*_gS)3nS#U>+S{?OCL6mxoR$Ry2b5X+h?6d{0Y-% > > zQIsxg=f+O!{yv$@>08->&|MLiD3+4K5C<iKp?vy1wKr>;OMnxMW_WN79vFYFr+4ks > > z88N~k-q6-(OJig$?ESB_hVSGz@=$&99{!yl0%A@^n2Z#6`-QMz&eqbwu9c;h20y(^ > > zY&hT)MBx-feZN<<0oz|27A`(z1#pLGKJ|f4X!)21y3w?AfZG6CnLc;t&kyX_-lW7; > > zurCq)Y^)9fcUdZT8EU16BAl)k6sb3jo+h%&z;2@q4PH+dh<NIb>o+`yK>9&WQnU?w > > z&6zt1M#Px8Ew9)P@GfvecFNPnsa-?f_!#m0u6OitO2l5#O?2<(=(VuNAikkd*!N0o > > zQ2#<p;k;6%?hjS&tjFtpUaAJ%qfGtQ>|n}HJXD#Nt0Ak{r{tBJR#kb#I(q*(q0mM- > > zH}813qdIJ@ZlHwY`wpzf1u*F5doBCD)dg)v@s`Ir(`(>Vnv%I>_o^~<Pj-@cPMT`| > > z@KfT#{SB70CH+?#t$-(6HJn}_FIV{(hm)SAxOzw1Z`^qUm%8>Y#09(?{XB8}lSRtD > > zD@{ibZ%5&}%$%^g>0*8i6Zpx%s7sG$rOa!%)2ZtRLokHz;27a9y6|~jx_!ZU<B%Oh > > zvQ_u1BQ)R7pi53d>rZMzwW0QbMCOU@Q)%<q<Sl0gd_#88yZYbj_mqd}qI0$gVTtz` > > zv2b8aESTGvAV59YrRW4!c$t5kyl&O+SGAc@_R&}AD(U2$e+yV<LkB!n3b+1hHOI!i > > z^^nA`FAvNitUN~COm)3(F_oe7+x^VSPG{eq+vdATOS`YuZ_&8B2j~)$_bQOWJW*DV > > zn6|Y=n9;kSoHswH2gMe0OfH{E1avQ{ja+*1c_+|}1yKHsVZj2%<mr<lXq>ufFZ_yo > > z3bdwtw!#65^Bj0+!`Iq;6&Sls_<(ft?&y8)tYFR*Gh@wT+mBU6Qj3D7;$lupW;^`N > > z1;Fml0);<fGvCmTHtoRVI1f3YDpMQ3h3qzaqSIv)Gaf1<!!H8zV&6y5S0vxvt@|Np > > zW$aGmD`sr-IPm3X-W58rg56OMK>B?ry)jfzfv2sI2Y0Ff)6`Xrc09SW!)B`nMrV-N > > zAT=5dG0Zu+X(58)LRFSF$1nbJp8^IE6`Xf`jb`rf8SwKqX^F{i_TM|gNDia_kfuP5 > > zz!hLNqq>cA<F8MERYJukY1Y0MgFZXuKJncN#v&P{8Rag}(_A5@dhueM)ZbTUaR1!P > > z*PwC><@gMRBpnIBiD0gWJ9ujpzKiBPZkEFjQX3I4Sw6x@*ck$jzP!k?`8yU6AX<)# > > zHJbE6IaNhgy1!C9J}@LVShns$79#5v1B5QS>omIh)Wd^Ik}Cyj57;+4S~G2ColJ#a > > z|57kW1+y)=H@dsV)`?F{Kr#gURnX0&{<TG9`(~K>x~%62_YgJpBMY|4rcpVkzR2FD > > zb*I_f;T|1+pB?vDGgU#*o-j0ymqa#(T1zCQKBQ{0v;@=<k&Fy)0r$Vx8>R&zM`Akl > > zp!!1$(FBglN9R)LZznUVg_pUP4O%i@=Ho@CiI<tSeKYzIr^;sxuS%WSy5FHk&gys{ > > z23{G@>vr2G3nCa)m5hL6m+S*20B2guSygKT{<Sqtp&9CQW$qrqH{PinyKIJV&94<! > > z7SPklC-~YToJ-;<`=`fO!Ws-)`8-%PQT(Z3NWh(LDVIb=_6f-+yRZ^fsq?P9MD5L# > > zmM{JEJw5<jRM^sI0m4KYyrJ*|yQhWzKK4L~mQ*`FrY6e78#;%|Xj=;(2bra~@M-9? > > zrRqa?`I_)&6Fw5!bJ;;Vm9QKLg>^e9j=RpnnSy`71ImM}SsN`siWm=@*&U_XHPc^b > > zS!v1)%*t*=0rAQoMSgylxL;GQt}Y8ZnaxMqcSORsh=lya7Qa{C!@}gs?p(^X`Mmi? > > zEHjZg`Elga#R~G`_~1P1z7bCyzeqFvt96TkZZC@Q=4@lASgcoqJP1dU$*9~#u3E!x > > zU>iVSXt19zUQD|4EMR{<cJU$96Db63e(=dC6R!8s%?MZU?<mi&(+3CD_N68TG<fBL > > zm2=$1FH%8ktHPdx_Xgu>`cp~K9RTdJGJ!zPfp_c=UAuh+iefiypYm68v9~-pHJq{7 > > zLg?^PM5B$`gzGw^$o{&=YL5pp4K+)iYEL+nu~k$&Tk@ahx%)?u6T!r^aH*V3Y7Hb+ > > zrdI*^x6-4E9g(SoFdnhiOw_UEoN56uC_@-Y#NoupY4_Mz*E8jCXQX!6R`2`|-h9ek > > z3BT))3kJ>WYk6oQyxnhA+u!C-*n+Un9DH-%6xv9m^%-t<bRIbm>82U~ZM^vzSQz5i > > ze>OjIrhSq{M+B1vc#4<r63Yw*S8+{Ww<ILLB)z8e3gr4cJXQqmnc}v@K1^&b&Hk%E > > zTg>B-W^8@odvaDEE>f_Op(fG4IV|YQYd9l|eYbkFvbpISJM*&hXHxeb_mf1p(_Efe > > z>fxrBHf;}|#-#D8`$pg*i;!9Q*pKxRG(8dp&<OG~oVngAQ<&wcOXESfb7f~Vwl0sZ > > ziTfkbx!?$VrN^8aT_BYo2Y*ySjl-qA#hV}_fsjBASyZVH`S<b5{QkU^C4VnV7AE^t > > zouF%JT+~XH_R`z;Wt?z1aCJ}2TrrqUWWdJwD&Th>FVSpDQq$yY%KiRstFgVKmeRlo > > z&G)=Vg?Dj;;u#D@A2n@wrgm2@0j&nk<+ut^v50OLj%yBlqHd?uU0P=wL1@4Ad)7}D > > z?cHm5TiuyptKO4)f!m*8B+zRI2(K|mxl6v0)BF1acHU-hQeuE|5HfTqx!8`c<8)+b > > z*3(jYXdJk|Z!3Y^fs+RBC-1Ttx#7oWg9ZiDi&;q97b|ejWQ-V%NA`OzmHij@Ar!lu > > z_w>=x9Q*4q_gh<D03dWuj6WxBJ#aNJCFT`~J5I^-$}qt+5t@AYeMqlaqUVWGA(k+% > > z$*yG?0l8Rt_LQosg;lCHqW^*FlPcpF3m<qFS~>!3b^P!d^Q|7L&sJ^z{X>RL%X~X^ > > z%@;5<Ga>77#dAk&Nw8B-g#-;_2iw)^Gemc~?#7kQD|}4A9>6OwMC}&{!}Cvbog+(D > > zOgqWDE3u**ip(c>foSgk`c0Hv$^6P8k66GiT?XsB#cQA=e1j8Qa?miOb@NE<y)#UH > > z`}AgePC~vFQ?y{-_ywzTS$N+B0FaCg`#nLAjlD6qk2lu$M;-U>`19`~jyz<$i>E;x > > z*P|REM!DW9VabrROJ?b|bJc=#RigSaAa*3VmS3fq7j7O!HDJ^v7QYcRwEe@6WSycr > > zc<nG%wVFYN{T=q^y4_N^D2aRPcnJciQG)6&09FeHRi1t;6vhr&vE=*ZY+*u~)o^u~ > > z!BYzR#zQFw_KSeO77IDqN^s$>(fWL;fuQx0p1eiEhXiSu7S{^+&j;A{5?TNBOHJ!8 > > zVcWpb59X5MPU26FTx#8aD%BsfSz>>sat{?9)H-A;l%zuS^K`ysZ1)eB$gNM{|CrFx > > Z7*dM{yQhj}4sy3din1y)<x=lM{ueeblRN+b > > > > literal 0 > > HcmV?d00001 > > > > -- > > 1.8.3.2 > > > > > > _______________________________________________ > > lng-odp mailing list > > lng-odp@lists.linaro.org > > http://lists.linaro.org/mailman/listinfo/lng-odp > > -- > Anders Roxell > anders.roxell@linaro.org > M: +46 709 71 42 85 | IRC: roxell >
On 2014-07-09 13:28, Bill Fischofer wrote: > 1. @subsubfunction should have been @subsubsection. Good catch. > 2. Alex is already one of the authors, git format-patch added the signed > off stuff. Not sure if it's ethical for me to impersonate someone else. > 3. I did and it formats fine for me. With reference [1], what I really wanted to say was run these commands: $ git checkout -B test-am-my-patch origin/master $ git am 0001-name-of-your-patch.patch Cheers, Anders > 4. If you already have further tidy edits, feel free to apply/merge them > into the final results. If you have scripts for doing this I'd be happy to > run them. I just had Google save the doc as text and then edited by hand > to get the doxygen. > > Bill > > > On Wed, Jul 9, 2014 at 12:41 PM, Anders Roxell <anders.roxell@linaro.org> > wrote: > > > On 2014-07-09 09:20, Bill Fischofer wrote: > > > Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> > > > --- > > > crypto_design.dox | 545 > > ++++++++++++++++++++++++++++++++++++++++++++++++++ > > > images/syncmodels.png | Bin 0 -> 17179 bytes > > > 2 files changed, 545 insertions(+) > > > create mode 100644 crypto_design.dox > > > create mode 100644 images/syncmodels.png > > > > > > > Hi Bill, > > > > Thank you for reworking the patch. > > > > I have a couple of comments. > > 1. @subsubfunction is not a doxygen variable I think you mean: > > "@subsubsection fucntion Session Creation". Doxygen was warning about > > that. > > 2. Should we add Alex Signed-off-by as well to give him credit? > > 3. Before you send a patch try to apply it your self, git complained see > > [1] > > 4. See reference [2] this is a diff of what I had to do to tidy up the > > patch, > > can you please do that and resend it. > > > > > > A nit not a blocker: > > > +typedef struct odp_key_t { > > > +}odp_key_t; > > > > Nothing inside this struct, is that correct? > > Should there be an explanation why it's empty? > > > > Cheers, > > Anders > > > > [1] http://people.linaro.org/~anders.roxell/git_am_crypto_design_doc.txt > > [2] > > http://people.linaro.org/~anders.roxell/cleanup_crypto_design_doc.patch > > > > > diff --git a/crypto_design.dox b/crypto_design.dox > > > new file mode 100644 > > > index 0000000..a46a2db > > > --- /dev/null > > > +++ b/crypto_design.dox > > > @@ -0,0 +1,545 @@ > > > +/* Copyright (c) 2043, Linaro Limited > > > + * All rights reserved > > > + * > > > + * SPDX-License-Identifier: BSD-3-Clause > > > + */ > > > + > > > +/** > > > +@page crypto_design ODP Design - Crypto API > > > +For the implimentation of the ODP crypto API please see @ref > > odp_crypto.h > > > + > > > +@tableofcontents > > > + > > > +@section revision_history Revision History > > > +Revision | Issue Data | Description | Author > > > +---------|------------|-------------|-------- > > > +0.1 | 4/9/2014 | Introduction started, Basic Functions | Bill, > > Alexandru > > > +0.2 | 4/15/2014 | Completed intro, added TOC, started use cases, > > miscellaneous formatting, API comments | Bill > > > +0.3 | 4/22/2014 | Added Use Case section to include results of > > design discussions held during ODP team calls | Bill > > > +0.4 | 4/30/2014 | Design review from ODP crypto sprint--action to > > resolve | Bill > > > +0.5 | 5/5/2014 | Rewrite incorporating review comments--ready > > for final review | Bill > > > +1.0 | 5/30/2014 | Final version for LNG-SC approval | Bill > > > + > > > +@section introduction Introduction > > > +This document describes the ODP Crypto API. Cryptography is an > > important part of data plane processing as many communication protocols > > make use of cryptographic functions. > > > +Moreover, many SoCs incorporate cryptographic hardware that can > > significantly accelerate these operations compared to their software > > equivalents as well as provide validated hardware functional correctness > > and security boundaries necessary for system-level security certifications > > such as FIPS-140 Level 2 and above. > > > +@section requirements Requirements > > > +@subsection use_of_terms Use of Terms > > > +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", > > "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this > > document are to be interpreted as described in [RFC 2119]( > > https://tools.ietf.org/html/rfc2119). > > > +@subsection uses_of_cryptography Uses of Cryptography > > > +Crypto functions cover a range of uses and capabilities designed to > > support data security, integrity, authentication, and non-repudiation. > > > +@subsubsection data_security Data Security > > > +Cryptography supports data security by making use of complex > > mathematical transformations that are not feasibly reversible without > > possession of the secret key used to encrypt message data. > > > +@subsubsection data_integrity Data Integrity > > > +Cryptography supports data integrity through the use of cryptographic > > checksums (also known as secure hashes) that ensure the recipient that > > message data has not been altered either accidentally or maliciously while > > in transit. > > > +@subsubsection data_authentication Data Authentication > > > +Cryptography supports data authentication through the uses of Message > > Authentication Codes (MACs) that enable the recipient to verify that a > > message was sent from an authorized counterparty, and hence was not forged. > > > +@subsubsection data_non_repudiation Data Non-Repudiation > > > +Cryptography supports data non-repudiation through the use of digital > > signatures that enable a recipient or third party to verify the identity of > > the sending party and prevents the sending party from later denying that > > they originated a signed message. > > > +@subsection scope Scope > > > +ODP crypto support is designed to provide a portable framework for > > accessing SoC-specific cryptographic functions of most use to the data > > plane. This is predominantly symmetric crypto operations used to support > > the encryption and decryption of data at line rate using hardware > > acceleration and offload. Specifically excluded in this support are public > > key operations and other crypto functions mainly used in the control plane. > > > +@subsection cryptographic_operations_in_the_data_plane Cryptographic > > Operations in the Data Plane > > > +ODP crypto APIs cover the following areas: > > > +@subsubsection ciphering Ciphering > > > +Ciphering refers to mathematical transformations that use a secret key > > to encipher data, transforming the original data (referred to as plaintext) > > into ciphertext, thereby making it unintelligible to anyone not in > > possession of the key. Similarly, ciphering is also used to decipher data, > > allowing someone in possession of the correct key to transform received > > ciphertext back into plaintext. Approved block ciphers are listed [here]( > > http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html) and SHOULD be > > supported by each ODP implementation. > > > +@subsubsection hasing Hashing > > > +A hash is a cryptographic digest of a message that can be used to > > represent it for comparison or integrity checking. Hash functions are > > designed so that any alteration of a message will alter the hash and that > > it is computationally infeasible to craft a message that generates the same > > hash value as another message. Secure hash functions approved for > > cryptographic use are listed by NIST [here]( > > http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html) and SHOULD be > > supported by each ODP implementation. > > > +@subsubsection zeroization Zeroization > > > +To preserve the security of data, certain transient data held in data > > buffers MUST be cleared to zeros upon buffer free. > > > +Such capability is referred to as zeroization. > > > +ODP supports zeroization as a buffer pool attribute. > > > +@subsubsection random_number_generation Random Number Generation > > > +Because cryptography relies heavily on “unguessable” keys of various > > sorts, random number generation (RNG) is an integral part of cryptographic > > processing. > > > +Random numbers are used in key generation, initialization vectors > > (IVs), various types of padding bytes, and various other uses collectively > > referred to as nonces, that serve to “harden” cryptographic processing. > > > + > > > +There are two types of random number support of interest. > > > +Hardware random data, also known as entropy, that is the result of > > inherently random physical processes, and deterministic random bit > > generation (DRBG) that is used in certain certified cryptographic > > operations. > > > +Approved DRBG algorithms are listed in [NIST SP 800-90A]( > > http://en.wikipedia.org/wiki/NIST_SP_800-90A) and ODP does not specify > > which algorithms are available on a given implementation. > > > +As such ODP implementations MAY use any approved DRGB algorithm but > > SHOULD support at least one of them. > > > +Additionally, ODP implementations MUST NOT represent non-approved > > algorithms as DRBG implementations. > > > +Validated algorithms are listed in the [NIST DRBG Validation List]( > > http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgval.html). > > > + > > > +@subsubsection capability_inquiry Capability Inquiry > > > +To enable applications to adapt to the implementation models offered > > across different SoC platforms, ODP provides APIs to allow applications to > > inquire about underlying crypto capabilities. > > > +A given ODP implementation may offer crypto as hardware features, > > software features, or not available on a given platform. > > > +@subsection cryptographic_algorithms Cryptographic Algorithms and > > Protocols > > > +A cryptographic algorithm is a mathematical transform that provides one > > of the cryptographic operations described above. > > > +They in turn are used as building blocks in creating cryptographic > > protocols. > > > +These are complete sets of rules for how to exchange data securely > > using cryptography. > > > +Both cryptographic algorithm and protocol design are highly specialized > > disciplines that involve high levels of public scrutiny and validation. > > > +As a result, applications simply make use of approved cryptographic > > algorithms and protocols. > > > +@subsection cryptographic_operations Cryptographic Operations > > > +Cryptographic operations may be initiated by software or directly by > > hardware as part of the RX or TX packet path processing. > > > +For ODP software-initiated cryptographic operations are the primary use > > case. > > > +ODP provides APIs for performing data ciphering, hashing, random number > > generation, and capability inquiry. > > > +@subsection performance_expectations Performance Expectations > > > +In the data plane, the total processing budget for a packet may only be > > a few hundred cycles, so function invocation overhead MUST be kept to a > > minimum. > > > +This has several implications. > > > + > > > +-# When work is dispatched to a thread, all information needed by the > > thread to process the work request SHOULD be immediately at hand. > > > +Ideally any context or variables needed for the operation have been > > pre-warmed in the cache to avoid the latency hits associated with cache > > misses. > > > +SoCs having hardware schedulers generally do this pre-staging of data > > to minimize such latencies, and ODP implementations are expected to exploit > > such platform capabilities whenever possible.\n\n > > > + > > > +-# Calls to ODP functions SHOULD NOT involve excessive amounts of > > parameter passing and (depending on the implementation) SHOULD be inlined > > as much as possible to avoid call overhead. > > > +One technique that has proven useful is to allow for parameters to be > > passed as an explicit thread-local static structure. > > > +Such use of “templating” means that a single function can support a > > rich set of options but the caller can configure a template matched to > > specific use and only vary the one or two parameters that differ from call > > to call.\n\n > > > + > > > +-# Kernel traps or interrupts SHOULD NOT be part of any non-exception > > path function processing. > > > +Kernel calls and such are acceptable only during one-time > > initialization logic or certain types of unusual error recovery operations. > > > +Often the best way to handle the latter is to pass the work to a > > dedicated recovery thread (or back to the control plane) rather than > > attempting to handle the condition inline. > > > +For example, a link-down condition will trigger various recovery > > actions that might best be handled in this manner. > > > + > > > +@subsection use_by_existing_code Use by Existing Code > > > +Most applications wishing to make use of ODP represent substantial > > existing investment that must be preserved. > > > +Insofar as possible, ODP functions need to be orthogonal to existing > > application environments and structures to permit easy intermixing with > > pre-existing code. > > > +@subsection data_references Data References > > > +Packet data is inherently of variable length however it is often more > > efficient to organize memory into fixed-sized buffers that can be chained > > together on demand to contain packets. > > > +The application SHOULD normally not need to be aware of such > > lower-level segmentation and should be able to treat a packet as a single > > object. > > > +Alternately, especially when dealing with existing code, data > > segmentation MUST be explicitly specifiable via scatter/gather lists. > > > +For example, data encryption or decryption may be invoked on a list of > > data segments as part of a single function call. > > > +@subsection chained_operations Chained Operations > > > +Crypto operations such as hashing and encryption, or decryption and > > verification, are very commonly used in combination. > > > +For ODP, it is sufficient to support one cipher and one > > hash/authentication operation in a single call and this combination MUST be > > supported to avoid the call and dispatch overhead of separate invocations. > > > + > > > +@subsection key_management Key Management and Session Data > > > +Keying is an area of particular sensitivity in crypto processing since > > keys are highly confidential and may be subject to legal requirements for > > safeguarding within special hardware enclosures. > > > + > > > +A session is the security context used to represent an active set of > > crypto operations that need to be applied to a flow on a packet-by-packet > > basis. Generally a session is established upon detection of a flow > > requiring crypto processing and retained for the life of that flow. It has > > been noted that this can involve cooperative processing between the control > > and data planes so several requirements stem from this: > > > + > > > +-# Session creation MAY need to be handled in an asynchronous manner. > > This is to allow these to be created in batches by thread(s) that > > specialize in this activity.\n\n > > > + > > > +-# Sessions MAY need to reference keying material indirectly via key > > handling modules.\n\n > > > + > > > +-# Session creation MAY be performed by non-ODP code and communicated > > to data plane routines that make use of ODP crypto functions that need to > > reference the session information. > > > + > > > +ODP session APIs and data structures SHOULD be represented by abstract > > data types that encapsulate implementation details for both platform > > efficiency and to accommodate these needs. > > > +Use Cases > > > +For ODP the major use cases of interest involve cryptographic algorithm > > acceleration. Cryptographic protocol acceleration is reserved for future > > ODP releases. > > > +Buffers and Data Blocks > > > +Cryptographic operations may be performed directly on data contained in > > ODP packet buffers, or it may be performed on “raw” data blocks operating > > entirely under application control. > > > +Note that when using raw data blocks not managed by ODP, the > > application must perform any needed zeroization using either its own or > > ODP-supplied buffer zeroization functions. > > > +ODP automatic support for zeroization is limited to ODP-managed buffers. > > > +ODP buffers allocated from buffer pools designated for crypto use will > > also have whatever alignment and/or addressability attributes needed by the > > implementation to support crypto API calls. > > > + > > > +Note: Some implementations may have difficulty dealing with application > > buffer addresses, as these may be virtual addresses that are mapped > > discontiguously into physical memory. > > > +For such implementations, memory SHOULD be allocated contiguously and > > MAY need to be “registered” to have proper addressability for crypto > > operations. > > > +This area of the design will be updated based on experience in dealing > > with different crypto implementations that have such requirements. > > > +Synchronization > > > +ODP operations fall into one of three categories: > > > + > > > +-# Inline (Synchronous): Upon return from a call the operation is > > complete. > > > +Operation is thus completely synchronous to the caller. > > > +Inline is the appropriate model when the invoked function takes > > relatively few cycles or when the caller cannot feasibly progress without > > the results of the invoked function.\n\n > > > + > > > +-# Parallel: Upon return from a call the operation has been initiated, > > but is expected to complete shortly. > > > +The caller continues to execute until it needs the result at which > > point it waits to complete the parallel operation. > > > +The effect is as if the operation were inline except that the caller > > was able to execute in parallel with the operation for some > > application-determined period of time. > > > +Parallel is the appropriate model when the operation being performed is > > relatively short (a few dozen up to perhaps 100 or 200 cycles) and the > > caller can usefully accomplish other processing on the same unit of work > > while the parallel operation is in progress, but not enough to justify the > > overhead of a formal queued work dispatch.\n\n > > > + > > > +-# Offloaded (Asynchronous): Upon return from the call the operation > > has been queued for execution. > > > +A completion event will be queued back to the scheduler when the event > > is completed. > > > +Offload is the appropriate model when the invoked function will take a > > substantial amount of cycles (thousands to tens of thousands) allowing the > > invoking thread/core to service other work until the operation completes. > > > +For offloaded work, completion is indicated by a completion event being > > posted back to an application-designated completion queue. > > > +Upon receipt the unit of work that initiated the offloaded operation > > continues processing with the results of the call. > > > + > > > +The synchronization models of interest are summarized in Figure 1: > > > + > > > +![Figure 1: Synchronization Models](./images/syncmodels.png) > > > + > > > +Note: Because few implementations are expected to offer the Parallel > > mode of operation as described above, this mode is reserved for potential > > future use. > > > +For ODP only synchronous and asynchronous crypto operations are defined. > > > +@section functional_definition Functional Definition > > > +@subsection abstract_data_types Abstract data types > > > +The following enumerations define various algorithms used for ciphering > > and hashing. > > > +These are the basic operations applied to input data. > > > + > > > +A particular ODP implementation should map these values to the actual > > information to be passed to the crypto engine. > > > +As such, the actual values of these enums is implementation-defined. > > > + > > > +Cipher algorithm encoding specifies the algorithm and cipher mode > > employed (as per security relevant RFCs - [4305]( > > http://tools.ietf.org/html/rfc4305), [4868]( > > http://tools.ietf.org/html/rfc4868), [4494]( > > http://tools.ietf.org/html/rfc4494)). > > > + > > > +@code > > > +enum odp_cipher_alg { > > > + ODP_CIPHER_ALG_NULL, > > > + ODP_CIPHER_ALG_DES, > > > + ODP_CIPHER_ALG_3DES_CBC, > > > + ODP_CIPHER_ALG_AES_CBC, > > > + ODP_CIPHER_ALG_AES_GCM, > > > + ODP_CIPHER_ALG_AES_CTR, > > > + ODP_CIPHER_ALG_KASUMI, > > > + ODP_CIPHER_ALG_SNOW, > > > + ... > > > +}; > > > +@endcode > > > + > > > +Authorization algorithm encoding specifies the algorithm and the length > > of the authorization used (as per security relevant RFCs - [4305]( > > http://tools.ietf.org/html/rfc4305), [4868]( > > http://tools.ietf.org/html/rfc4868), [4494]( > > http://tools.ietf.org/html/rfc4494)): > > > + > > > +@code > > > +enum odp_auth_alg { > > > + ODP_AUTH_ALG_NULL, > > > + ODP_AUTH_MD5_96, > > > + ODP_AUTH_ALG_SHA1_96, > > > + ODP_AUTH_ALG_SHA1_160 > > > + ODP_AUTH_ALG_SHA2_256_128, > > > + ODP_AUTH_ALG_SHA2_384_192, > > > + ODP_AUTH_ALG_SHA2_512_256, > > > + ODP_AUTH_ALG_AES_CMAC_96, > > > + ODP_AUTH_ALG_AES_XCBC_MAC_96, > > > + ODP_AUTH_ALG_SNOW, > > > + ODP_AUTH_ALG_KASUMI, > > > + ... > > > +}; > > > + > > > +typedef union odp_crypto_alg_t { > > > + enum odp_cipher_alg cipher; > > > + enum odp_auth_alg auth; > > > +}odp_crypto_alg_t; > > > +@endcode > > > +@subsection parameter_structures Parameter Structures > > > +@subsubsection crypto_sessions Crypto Sessions > > > +The following structure describes a crypto session. > > > +All packets / raw data buffers processed in a session share the data > > that defines the session. > > > +A crypto session is defined by: > > > + > > > +- Operation type : encode or decode\n\n > > > + > > > +- Algorithms specifications, keys and , if required, initialization > > vectors. > > > +When initialization vectors are not provided and they should be > > provided automatically by the crypto engine.\n\n > > > + > > > +- The operation mode: synchronous or asynchronous. > > > +Synchronous operation blocks the caller until an operation status and > > result are available. > > > +In synchronous mode there is at most only one outstanding crypto > > operation in the calling thread. > > > +In asynchronous mode, the caller starts the crypto operation and later > > it may receive the status and the result together with a request context. > > > +The operation status and result may also be received by a different > > thread.\n\n > > > + > > > +- Operation mode parameters: For asynchronous operation a completion > > event containing the status, the result and the request context is enqueued > > to a completion queue. > > > +In case the queue is under the scheduler control, the scheduler > > determines who will receive the completion event and when. > > > +When the completion queue is not scheduled, the thread which is > > supposed to get the operation output has to explicitly poll the completion > > queue. > > > + > > > +Note that this is an abstract data type and its structure is > > implementation-specific. > > > +The layout shown here is for illustrative purposes and the actual > > layout will vary from one implementation to the next to most closely align > > with the structures needed by the underlying SoC platform. > > > +Applications set and reference fields in the session structure via > > accessor functions that hide the actual layout. > > > + > > > +@code > > > +typedef enum odp_crypto_op_t { > > > + ODP_CRYPTO_OP_ENCODE, > > > + ODP_CRYPTO_OP_DECODE > > > +}odp_crypto_op_t; > > > + > > > +typedef struct odp_key_t { > > > +}odp_key_t; > > > + > > > +typedef struct odp_crypto_session_t { > > > + odp_crypto_op_t op; > > > + struct { > > > + enum odp_cipher_alg cipher_alg; > > > + odp_key_t *key; > > > + uint8_t *iv; > > > + size_t iv_len; > > > + } cipher; > > > + > > > + struct { > > > + enum odp_auth_alg auth_alg; > > > + enum odp_auth_len auth_len; > > > + odp_key_t *key; > > > + } auth; > > > + > > > + enum odp_crypto_op_mode { > > > + ODP_CRYPTO_SYNC, > > > + ODP_CRYPTO_ASYNC, > > > + } op_mode; > > > + > > > + struct { > > > + uint32_t timeout; > > > + struct { > > > + odp_queue_t completion_queue; > > > + } async; > > > + } op_mode_params; > > > + > > > + odp_session_proc_info_t session_proc_info; > > > +} odp_crxsypto_session_t; > > > +@endcode > > > + > > > +The completion queue contained in the session structure is an in/out > > parameter. > > > +If provided, then the queue specified is associated with the session > > and is used to ensure order preservation on that session. > > > +If not provided, one is created and returned to the caller. > > > +Note that this completion queue is used to order operations performed > > on this crypto session. > > > +It should not be confused with the completion queue specified on the > > odp_crypto_session_create() call (see below) that is used to control > > whether that call is itself processed in a synchronous vs. asynchronous > > manner. > > > + > > > +The following structure comprises processing information. > > > +This is logically divided in two parts: > > > + > > > +- Processing input info - When crypto engine provides support for > > protocol processing, this information is provided in a higher level common > > protocol terminology form and a particular implementation should be able to > > derive everything it needs from this definition. > > > +In addition, for crypto engines able to automate tasks like memory > > allocation for the output a buffer pool id may be specified.\n\n > > > + > > > +- Processing output information - statistics about processed > > bytes/packets. > > > +These are useful when a session expiration is based on traffic volume. > > > +These statistics may be updated by the software or by the hardware > > crypto engine. > > > + > > > +Again, this is an abstract type whose specific layout will vary based > > on implementation considerations. > > > +Access to fields contained in the structure is only via accessor > > functions. > > > + > > > +@code > > > +typedef struct { > > > + uint64_t pkts_processed; > > > + uint64_t bytes_processed; > > > + uint64_t pkts_errored; > > > + uint64_t bytes_errored; > > > + > > > + odp_buffer_pool_t out_pool; > > > + > > > +} odp_session_proc_info_t; > > > +@endcode > > > + > > > +This enumeration defines which operations are applied and the order. > > > + > > > +@code > > > +enum odp_crypto_combination { > > > + ODP_CRYPTO_CIPHER_ONLY, > > > + ODP_CRYPTO_AUTH_ONLY, > > > + ODP_CRYPTO_AUTH_CIPHERTEXT > > > +}; > > > +@endcode > > > + > > > +This structure defines a contiguous segment in the input data which > > starts at offset offset and is len bytes long. > > > + > > > +@code > > > +struct odp_data_range { > > > + unsigned offset:16; > > > + unsigned len:16; > > > +}; > > > +@endcode > > > + > > > +@subsection api_functions API Functions > > > + > > > +@subsubfunction Session Creation > > > + > > > +This function is used to create a crypto session. > > > +The required parameters are: > > > + > > > +- Operation : encode/decode > > > +- Processing info : cipher/auth/both > > > +- Preferred mode : sync or async. > > > +- Algorithms suites, keys and optional IV > > > + > > > +Session creation can be synchronous or asynchronous. > > > +Completion event argument is used to return the status and the session > > handle. > > > +When completion queue is not provided (synchronous call), the > > completion event is available upon function call return. > > > +When completion queue is provided (asynchronous call), the completion > > event is placed on the completion queue. > > > + > > > +@code > > > +typedef uint64_t odp_crypto_session_t; > > > + > > > +struct odp_session_params { > > > + enum odp_crypto_operation op; > > > + odp_session_proc_info_t proc_info; > > > + enum odp_crypto_op_mode pref_mode; > > > + enum odp_cipher_alg cipher_alg; > > > + odp_key_t *cipher_key; > > > + uint8_t *iv; > > > + size_t iv_len; > > > + enum odp_auth_alg auth_alg; > > > + odp_key_t *auth_key; > > > +}; > > > + > > > +enum odp_crypto_ses_create_err { > > > + ODP_CRYPTO_SES_CREATE_NONE, > > > + ODP_CRYPTO_SES_CREATE_ENOMEM, > > > + /* Session creation error codes */ > > > +}; > > > + > > > +void > > > +odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, > > enum odp_crypto_ses_create_err *status); > > > + > > > +void > > > +odp_crypto_get_ses_create_compl_handle(odp_buffer_t completion_event, > > odp_crypto_session_t *handle); > > > + > > > +int odp_crypto_session_create( > > > + struct odp_session_params *params, > > > + odp_buffer_t completion_event, > > > + odp_queue_t completion_queue); > > > +@endcode > > > +@subsection crypto_operation Crypto Operation > > > + > > > +Crypto operations are described by a parameter structure: > > > +@code > > > +struct odp_crypto_op_params { > > > + odp_crypto_session_t session; > > > + odp_packet_t pkt; > > > + odp_packet_t out_pkt; > > > + uint8_t *override_iv_ptr; > > > + unsigned hash_result_offset; > > > + struct odp_data_range cipher_range; > > > + struct odp_data_range auth_range; > > > +}; > > > +@endcode > > > + > > > +<table> > > > +<tr><th>Parameter</th><th>Meaning</th></tr> > > > +<tr><td>session</td><td>Session to perform the operation</td></tr> > > > +<tr><td>pkt</td><td>Packet / buffer to be processed</td></tr> > > > +<tr><td>out_pkt</td><td>Handle of an output packet / buffer to be > > returned as the result of the operation. > > > +There are three different ways this parameter is used, depending on the > > mode of operation requested by the caller and the capabilities of the > > underlying implementation:\n\n > > > + > > > +-# If out_pkt is the same as pkt this indicates that the operation > > should be performed in place.\n\n > > > +-# If out_pkt is different from pkt this indicates that output should > > be placed in the buffer supplied by the caller.\n\n > > > +-# If out_pkt is omitted (a null/invalid value supplied on input) this > > indicates that an output buffer should be allocated by the operation and > > returned as part of the completion event associated with the operation.\n\n > > > + > > > +Note that not every implementation will support all of these modes and > > MAY require that one mode be used in preference to others. > > > +Any such implementation restrictions are communicated as output from > > session creation.</td></tr> > > > +<tr><td>override_iv_ptr</td><td>Optional IV to use for this > > request</td></tr> > > > +<tr><td>hash_result_offset</td><td>Offset into the output packet where > > the hash result should be stored.</td></tr> > > > +<tr><td>cipher_range</td><td>The byte range (offset:length) of the data > > to be processed for ciphering.</td></tr> > > > +<tr><td>auth_range</td><td>The byte range (offset:length) of the data > > to be processed for authentication.</td></tr> > > > +</table> > > > + > > > +The crypto operation is initiated with a single call that passes the > > parameters for the operation and an event (for asynchronous completion). > > > +@code > > > +int odp_crypto_operation( > > > + struct odp_crypto_op_params *params, > > > + odp_buffer_t completion_event); > > > +@endcode > > > + > > > +Parameter | Meaning > > > +----------|-------- > > > +params | The parameter structure describing the crypto operation to > > be performed. > > > +completion_event | The event delivered on completion. > > > +It provides information about the status of the operation, result and > > request context. > > > +In synchronous mode the event is available upon function call return. > > > +In asynchronous mode, the event is placed on the session / operation > > completion queue when the operation finished. > > > + > > > +Upon return the return code indicates whether the operation was > > synchronous or asynchronous, or if an error occurred that prevented the > > operation from being performed. > > > + > > > +Get session operation : > > > +@code > > > +odp_crypto_op_t odp_crypto_session_get_op(odp_crypto_session_t ses); > > > +@endcode > > > + > > > +Get session cipher information : > > > +@code > > > +odp_cipher_alg odp_cipher_session_get_cipher_alg(odp_crypto_session_t > > ses); > > > +@endcode > > > + > > > +Get session authentication information : > > > +@code > > > +odp_auth_alg odp_crypto_session_get_auth_alg(odp_crypto_session_t ses); > > > +@endcode > > > + > > > +Change session IV : > > > +@code > > > +int odp_crypto_session_iv_set(odp_crypto_session_t ses, uint8_t *iv); > > > +@emdcode > > > + > > > +Change cipher or/and hash keys: > > > +@code > > > +int odp_crypto_session_key_set(odp_crypto_session_t ses, odp_key_t > > *key); > > > +@endcode > > > + > > > +Destroy crypto session. > > > +All pending operations are cancelled. > > > +@code > > > +int odp_crypto_session_destroy(odp_crypto_session_t ses); > > > +@endcode > > > + > > > +Get completion event information - algorithm error, output and context. > > > +Note that implementations MAY define their own specific error codes > > that have meaning in that context. > > > +For application portability it is sufficient to know whether an > > operation completed successfully or experienced an error of some sort. > > > +@code > > > +enum crypto_alg_err { > > > + ODP_CRYPTO_ALG_ERR_NONE, > > > + ODP_CRYPTO_ALG_ERR_MODE, > > > + ODP_CRYPTO_ALG_ERR_DATA_SIZE, > > > + ODP_CRYPTO_ALG_ERR_KEY_SIZE, > > > + ODP_CRYPTO_ALG_ERR_ICV_CHECK, > > > + ODP_CRYPTO_ALG_ERR_AAD_SIZE, > > > +}; > > > + > > > +enum crypto_hw_err { > > > + ODP_CRYPTO_HW_ERR_NONE, > > > + ODP_CRYPTO_HW_ERR_DMA, > > > + ODP_CRYPTO_HW_ERR_BP_DEPLETED, > > > +}; > > > + > > > +struct odp_crypto_compl_status { > > > + odp_crypto_alg_t alg; > > > + enum crypto_alg_err alg_err; > > > + enum crypto_hw_err hw_err; > > > +}; > > > + > > > +void > > > +odp_crypto_get_compl_status(odp_buffer_t completion_event, > > > + struct odp_crypto_compl_status *auth, > > > + struct odp_crypto_compl_status *cipher); > > > +@endcode > > > + > > > +Returns the output packet handle associated with the completion event : > > > +@code > > > +odp_packet_t odp_crypto_get_out_pkt(odp_buffer_t completion_event); > > > +@endcode > > > + > > > +Sets a context handle to be returned with the completion event : > > > +@code > > > +void odp_crypto_set_compl_ctx(odp_buffer_t completion_event, > > odp_compl_ctx_t *ctx); > > > +@endcode > > > + > > > +Returns the context associated with the completion event : > > > +@code > > > +odp_compl_ctx_t odp_crypto_get_compl_ctx(odp_buffer_t completion_event); > > > +@endcode > > > + > > > +This section describes the API/Interface being defined at a functional > > level in technical detail. > > > +Sub-sections include header file names, where implementation files are > > expected to reside in the ODP git tree, as well as the name, parameters, > > abstract data types, functionality, return codes, and exception conditions > > of each function call defined by the API/Interface. > > > +Appropriate diagrams, tables, etc. should be used to allow the > > programmer tasked with implementing the API/Interface to understand the > > function to be implemented as well as error conditions, corner cases, > > performance requirements, etc. needed to implement the described > > API/Interface in a functionally correct and efficient manner. > > > + > > > +@subsubsection random_number_functions Random Number Functions > > > +As noted earlier, random number support consists of two functions: > > > +@code > > > +int odp_hw_random_get (uint8_t *buf, uint32_t *len, bool use_entropy); > > > + > > > +int odp_drgb_random_get (uint8_t *buf, uint32_t *len); > > > +@endcode > > > + > > > +The difference is that the first provides access to hardware random > > number functions that return true random data. > > > +This is typically used for seed values. > > > +The second provides a deterministic random bit generator conforming to > > NIST standards and is used by various crypto protocols and algorithms. > > > +The use_entropy parameter on odp_hw_random_get is used to disable any > > hardware pre-processing normally provided by the function and is mainly > > intended to be used for testing/validation purposes. > > > + > > > +@subsubsection buffer_pool_extensions Buffer Pool Extensions > > > +To support zeroization a buffer may be allocated with an > > ODP_CLEAR_ON_FREE attribute that specifies that this buffer should be > > zeroized upon free. > > > +Alternately, a new type (ODP_CLEAR_ON_FREE) is added to > > odp_buffer_pool_create() that specifies that all buffers allocated from > > this pool must be zeroized upon free. > > > +Essentially, the buffer security attribute is set by default from the > > attributes of the buffer pool that it is allocated from. > > > + > > > +@subsubsection capability_inquiry Capability Inquiry > > > +To enable applications to determine crypto capabilities. > > > +@code > > > +int odp_crypto_inquire (enum odp_cipher_alg, enum odp_auth_alg); > > > +@endcode > > > + > > > +Inquires whether the specified crypto and auth algorithms are supported. > > > +Responses include: > > > +- ODP_HW_SYNC_SUPPORT > > > +- ODP_HW_ASYNC_SUPPORT > > > +- ODP_SW_SYNC_SUPPORT > > > +- ODP_SW_ASYNC_SUPPORT > > > +- ODP_NO_SUPPORT > > > + > > > +HW support means the combination is supported in hardware, SW support > > means the combination is supported in software by the implementation. > > > +No support means the combination is not supported by the implementation. > > > +The SYNC and ASYNC return options can help the application decide how > > to invoke these functions, or it can just check whether or not the response > > is ODP_NO_SUPPORT. > > > + > > > +@section implementation_considerations Implementation Considerations > > > +One of the main purposes for the ODP crypto APIs is to provide portable > > access across different SoCs whose hardware crypto capabilities largely > > overlap but vary in terms of their implementation details. > > > +As a result, implementations need not provide software fill-ins for > > specific cryptographic features that are not available as hardware features > > on that platform. > > > +Presumably applications needing specific features will select platforms > > on which these features are present. > > > +Therefore, while all APIs specified here MUST exist in each conforming > > ODP implementation, it is acceptable for these APIs to return > > ODP_RC_FEATURE_NOT_PRESENT in response to calls requesting crypto features > > not present on that platform. > > > + > > > +For example, the linux-generic ODP implementation may only implement > > the null cipher suite (ODP_CIPHER_ALG_NULL) and return a feature not > > present error code for any other cipher. > > > +This indication will also be returned on that platform in response to > > odp_crypto_inquire calls for non-null cipher algorithms. > > > + > > > +@section verification Verification/Testing > > > +This section describes the verification/test cases needed to ensure > > that the defined functionality is implemented correctly and performs > > adequately. > > > +This should be at a level of detail such that the programmer tasked > > with writing test scripts/programs to verify the implementation(s) of the > > defined functions can be written to ensure that all relevant functional > > variants and error/exception cases are properly tested. > > > + > > > +This section needs to be completed before API testing begins. > > > + > > > +*/ > > > \ No newline at end of file > > > diff --git a/images/syncmodels.png b/images/syncmodels.png > > > new file mode 100644 > > > index > > 0000000000000000000000000000000000000000..44e4c551bd803b7dd4320875699828d7f20d2044 > > > GIT binary patch > > > literal 17179 > > > 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 > > > Z7*dM{yQhj}4sy3din1y)<x=lM{ueeblRN+b > > > > > > literal 0 > > > HcmV?d00001 > > > > > > -- > > > 1.8.3.2 > > > > > > > > > _______________________________________________ > > > lng-odp mailing list > > > lng-odp@lists.linaro.org > > > http://lists.linaro.org/mailman/listinfo/lng-odp > > > > -- > > Anders Roxell > > anders.roxell@linaro.org > > M: +46 709 71 42 85 | IRC: roxell > >
The V4 patch should be clean. Please ignore the previous ones. Thanks. Bill On Wed, Jul 9, 2014 at 2:47 PM, Anders Roxell <anders.roxell@linaro.org> wrote: > On 2014-07-09 13:28, Bill Fischofer wrote: > > 1. @subsubfunction should have been @subsubsection. Good catch. > > 2. Alex is already one of the authors, git format-patch added the > signed > > off stuff. Not sure if it's ethical for me to impersonate someone > else. > > 3. I did and it formats fine for me. > > With reference [1], what I really wanted to say was run these commands: > $ git checkout -B test-am-my-patch origin/master > $ git am 0001-name-of-your-patch.patch > > Cheers, > Anders > > > 4. If you already have further tidy edits, feel free to apply/merge > them > > into the final results. If you have scripts for doing this I'd be > happy to > > run them. I just had Google save the doc as text and then edited by > hand > > to get the doxygen. > > > > Bill > > > > > > On Wed, Jul 9, 2014 at 12:41 PM, Anders Roxell <anders.roxell@linaro.org > > > > wrote: > > > > > On 2014-07-09 09:20, Bill Fischofer wrote: > > > > Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> > > > > --- > > > > crypto_design.dox | 545 > > > ++++++++++++++++++++++++++++++++++++++++++++++++++ > > > > images/syncmodels.png | Bin 0 -> 17179 bytes > > > > 2 files changed, 545 insertions(+) > > > > create mode 100644 crypto_design.dox > > > > create mode 100644 images/syncmodels.png > > > > > > > > > > Hi Bill, > > > > > > Thank you for reworking the patch. > > > > > > I have a couple of comments. > > > 1. @subsubfunction is not a doxygen variable I think you mean: > > > "@subsubsection fucntion Session Creation". Doxygen was warning > about > > > that. > > > 2. Should we add Alex Signed-off-by as well to give him credit? > > > 3. Before you send a patch try to apply it your self, git complained > see > > > [1] > > > 4. See reference [2] this is a diff of what I had to do to tidy up the > > > patch, > > > can you please do that and resend it. > > > > > > > > > A nit not a blocker: > > > > +typedef struct odp_key_t { > > > > +}odp_key_t; > > > > > > Nothing inside this struct, is that correct? > > > Should there be an explanation why it's empty? > > > > > > Cheers, > > > Anders > > > > > > [1] > http://people.linaro.org/~anders.roxell/git_am_crypto_design_doc.txt > > > [2] > > > > http://people.linaro.org/~anders.roxell/cleanup_crypto_design_doc.patch > > > > > > > diff --git a/crypto_design.dox b/crypto_design.dox > > > > new file mode 100644 > > > > index 0000000..a46a2db > > > > --- /dev/null > > > > +++ b/crypto_design.dox > > > > @@ -0,0 +1,545 @@ > > > > +/* Copyright (c) 2043, Linaro Limited > > > > + * All rights reserved > > > > + * > > > > + * SPDX-License-Identifier: BSD-3-Clause > > > > + */ > > > > + > > > > +/** > > > > +@page crypto_design ODP Design - Crypto API > > > > +For the implimentation of the ODP crypto API please see @ref > > > odp_crypto.h > > > > + > > > > +@tableofcontents > > > > + > > > > +@section revision_history Revision History > > > > +Revision | Issue Data | Description | Author > > > > +---------|------------|-------------|-------- > > > > +0.1 | 4/9/2014 | Introduction started, Basic Functions | > Bill, > > > Alexandru > > > > +0.2 | 4/15/2014 | Completed intro, added TOC, started use > cases, > > > miscellaneous formatting, API comments | Bill > > > > +0.3 | 4/22/2014 | Added Use Case section to include results of > > > design discussions held during ODP team calls | Bill > > > > +0.4 | 4/30/2014 | Design review from ODP crypto > sprint--action to > > > resolve | Bill > > > > +0.5 | 5/5/2014 | Rewrite incorporating review comments--ready > > > for final review | Bill > > > > +1.0 | 5/30/2014 | Final version for LNG-SC approval | Bill > > > > + > > > > +@section introduction Introduction > > > > +This document describes the ODP Crypto API. Cryptography is an > > > important part of data plane processing as many communication protocols > > > make use of cryptographic functions. > > > > +Moreover, many SoCs incorporate cryptographic hardware that can > > > significantly accelerate these operations compared to their software > > > equivalents as well as provide validated hardware functional > correctness > > > and security boundaries necessary for system-level security > certifications > > > such as FIPS-140 Level 2 and above. > > > > +@section requirements Requirements > > > > +@subsection use_of_terms Use of Terms > > > > +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", > > > "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this > > > document are to be interpreted as described in [RFC 2119]( > > > https://tools.ietf.org/html/rfc2119). > > > > +@subsection uses_of_cryptography Uses of Cryptography > > > > +Crypto functions cover a range of uses and capabilities designed to > > > support data security, integrity, authentication, and non-repudiation. > > > > +@subsubsection data_security Data Security > > > > +Cryptography supports data security by making use of complex > > > mathematical transformations that are not feasibly reversible without > > > possession of the secret key used to encrypt message data. > > > > +@subsubsection data_integrity Data Integrity > > > > +Cryptography supports data integrity through the use of > cryptographic > > > checksums (also known as secure hashes) that ensure the recipient that > > > message data has not been altered either accidentally or maliciously > while > > > in transit. > > > > +@subsubsection data_authentication Data Authentication > > > > +Cryptography supports data authentication through the uses of > Message > > > Authentication Codes (MACs) that enable the recipient to verify that a > > > message was sent from an authorized counterparty, and hence was not > forged. > > > > +@subsubsection data_non_repudiation Data Non-Repudiation > > > > +Cryptography supports data non-repudiation through the use of > digital > > > signatures that enable a recipient or third party to verify the > identity of > > > the sending party and prevents the sending party from later denying > that > > > they originated a signed message. > > > > +@subsection scope Scope > > > > +ODP crypto support is designed to provide a portable framework for > > > accessing SoC-specific cryptographic functions of most use to the data > > > plane. This is predominantly symmetric crypto operations used to > support > > > the encryption and decryption of data at line rate using hardware > > > acceleration and offload. Specifically excluded in this support are > public > > > key operations and other crypto functions mainly used in the control > plane. > > > > +@subsection cryptographic_operations_in_the_data_plane Cryptographic > > > Operations in the Data Plane > > > > +ODP crypto APIs cover the following areas: > > > > +@subsubsection ciphering Ciphering > > > > +Ciphering refers to mathematical transformations that use a secret > key > > > to encipher data, transforming the original data (referred to as > plaintext) > > > into ciphertext, thereby making it unintelligible to anyone not in > > > possession of the key. Similarly, ciphering is also used to decipher > data, > > > allowing someone in possession of the correct key to transform received > > > ciphertext back into plaintext. Approved block ciphers are listed > [here]( > > > http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html) and SHOULD > be > > > supported by each ODP implementation. > > > > +@subsubsection hasing Hashing > > > > +A hash is a cryptographic digest of a message that can be used to > > > represent it for comparison or integrity checking. Hash functions are > > > designed so that any alteration of a message will alter the hash and > that > > > it is computationally infeasible to craft a message that generates the > same > > > hash value as another message. Secure hash functions approved for > > > cryptographic use are listed by NIST [here]( > > > http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html) and > SHOULD be > > > supported by each ODP implementation. > > > > +@subsubsection zeroization Zeroization > > > > +To preserve the security of data, certain transient data held in > data > > > buffers MUST be cleared to zeros upon buffer free. > > > > +Such capability is referred to as zeroization. > > > > +ODP supports zeroization as a buffer pool attribute. > > > > +@subsubsection random_number_generation Random Number Generation > > > > +Because cryptography relies heavily on “unguessable” keys of various > > > sorts, random number generation (RNG) is an integral part of > cryptographic > > > processing. > > > > +Random numbers are used in key generation, initialization vectors > > > (IVs), various types of padding bytes, and various other uses > collectively > > > referred to as nonces, that serve to “harden” cryptographic processing. > > > > + > > > > +There are two types of random number support of interest. > > > > +Hardware random data, also known as entropy, that is the result of > > > inherently random physical processes, and deterministic random bit > > > generation (DRBG) that is used in certain certified cryptographic > > > operations. > > > > +Approved DRBG algorithms are listed in [NIST SP 800-90A]( > > > http://en.wikipedia.org/wiki/NIST_SP_800-90A) and ODP does not specify > > > which algorithms are available on a given implementation. > > > > +As such ODP implementations MAY use any approved DRGB algorithm but > > > SHOULD support at least one of them. > > > > +Additionally, ODP implementations MUST NOT represent non-approved > > > algorithms as DRBG implementations. > > > > +Validated algorithms are listed in the [NIST DRBG Validation List]( > > > http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgval.html). > > > > + > > > > +@subsubsection capability_inquiry Capability Inquiry > > > > +To enable applications to adapt to the implementation models offered > > > across different SoC platforms, ODP provides APIs to allow > applications to > > > inquire about underlying crypto capabilities. > > > > +A given ODP implementation may offer crypto as hardware features, > > > software features, or not available on a given platform. > > > > +@subsection cryptographic_algorithms Cryptographic Algorithms and > > > Protocols > > > > +A cryptographic algorithm is a mathematical transform that provides > one > > > of the cryptographic operations described above. > > > > +They in turn are used as building blocks in creating cryptographic > > > protocols. > > > > +These are complete sets of rules for how to exchange data securely > > > using cryptography. > > > > +Both cryptographic algorithm and protocol design are highly > specialized > > > disciplines that involve high levels of public scrutiny and validation. > > > > +As a result, applications simply make use of approved cryptographic > > > algorithms and protocols. > > > > +@subsection cryptographic_operations Cryptographic Operations > > > > +Cryptographic operations may be initiated by software or directly by > > > hardware as part of the RX or TX packet path processing. > > > > +For ODP software-initiated cryptographic operations are the primary > use > > > case. > > > > +ODP provides APIs for performing data ciphering, hashing, random > number > > > generation, and capability inquiry. > > > > +@subsection performance_expectations Performance Expectations > > > > +In the data plane, the total processing budget for a packet may > only be > > > a few hundred cycles, so function invocation overhead MUST be kept to a > > > minimum. > > > > +This has several implications. > > > > + > > > > +-# When work is dispatched to a thread, all information needed by > the > > > thread to process the work request SHOULD be immediately at hand. > > > > +Ideally any context or variables needed for the operation have been > > > pre-warmed in the cache to avoid the latency hits associated with cache > > > misses. > > > > +SoCs having hardware schedulers generally do this pre-staging of > data > > > to minimize such latencies, and ODP implementations are expected to > exploit > > > such platform capabilities whenever possible.\n\n > > > > + > > > > +-# Calls to ODP functions SHOULD NOT involve excessive amounts of > > > parameter passing and (depending on the implementation) SHOULD be > inlined > > > as much as possible to avoid call overhead. > > > > +One technique that has proven useful is to allow for parameters to > be > > > passed as an explicit thread-local static structure. > > > > +Such use of “templating” means that a single function can support a > > > rich set of options but the caller can configure a template matched to > > > specific use and only vary the one or two parameters that differ from > call > > > to call.\n\n > > > > + > > > > +-# Kernel traps or interrupts SHOULD NOT be part of any > non-exception > > > path function processing. > > > > +Kernel calls and such are acceptable only during one-time > > > initialization logic or certain types of unusual error recovery > operations. > > > > +Often the best way to handle the latter is to pass the work to a > > > dedicated recovery thread (or back to the control plane) rather than > > > attempting to handle the condition inline. > > > > +For example, a link-down condition will trigger various recovery > > > actions that might best be handled in this manner. > > > > + > > > > +@subsection use_by_existing_code Use by Existing Code > > > > +Most applications wishing to make use of ODP represent substantial > > > existing investment that must be preserved. > > > > +Insofar as possible, ODP functions need to be orthogonal to existing > > > application environments and structures to permit easy intermixing with > > > pre-existing code. > > > > +@subsection data_references Data References > > > > +Packet data is inherently of variable length however it is often > more > > > efficient to organize memory into fixed-sized buffers that can be > chained > > > together on demand to contain packets. > > > > +The application SHOULD normally not need to be aware of such > > > lower-level segmentation and should be able to treat a packet as a > single > > > object. > > > > +Alternately, especially when dealing with existing code, data > > > segmentation MUST be explicitly specifiable via scatter/gather lists. > > > > +For example, data encryption or decryption may be invoked on a list > of > > > data segments as part of a single function call. > > > > +@subsection chained_operations Chained Operations > > > > +Crypto operations such as hashing and encryption, or decryption and > > > verification, are very commonly used in combination. > > > > +For ODP, it is sufficient to support one cipher and one > > > hash/authentication operation in a single call and this combination > MUST be > > > supported to avoid the call and dispatch overhead of separate > invocations. > > > > + > > > > +@subsection key_management Key Management and Session Data > > > > +Keying is an area of particular sensitivity in crypto processing > since > > > keys are highly confidential and may be subject to legal requirements > for > > > safeguarding within special hardware enclosures. > > > > + > > > > +A session is the security context used to represent an active set of > > > crypto operations that need to be applied to a flow on a > packet-by-packet > > > basis. Generally a session is established upon detection of a flow > > > requiring crypto processing and retained for the life of that flow. It > has > > > been noted that this can involve cooperative processing between the > control > > > and data planes so several requirements stem from this: > > > > + > > > > +-# Session creation MAY need to be handled in an asynchronous > manner. > > > This is to allow these to be created in batches by thread(s) that > > > specialize in this activity.\n\n > > > > + > > > > +-# Sessions MAY need to reference keying material indirectly via key > > > handling modules.\n\n > > > > + > > > > +-# Session creation MAY be performed by non-ODP code and > communicated > > > to data plane routines that make use of ODP crypto functions that need > to > > > reference the session information. > > > > + > > > > +ODP session APIs and data structures SHOULD be represented by > abstract > > > data types that encapsulate implementation details for both platform > > > efficiency and to accommodate these needs. > > > > +Use Cases > > > > +For ODP the major use cases of interest involve cryptographic > algorithm > > > acceleration. Cryptographic protocol acceleration is reserved for > future > > > ODP releases. > > > > +Buffers and Data Blocks > > > > +Cryptographic operations may be performed directly on data > contained in > > > ODP packet buffers, or it may be performed on “raw” data blocks > operating > > > entirely under application control. > > > > +Note that when using raw data blocks not managed by ODP, the > > > application must perform any needed zeroization using either its own or > > > ODP-supplied buffer zeroization functions. > > > > +ODP automatic support for zeroization is limited to ODP-managed > buffers. > > > > +ODP buffers allocated from buffer pools designated for crypto use > will > > > also have whatever alignment and/or addressability attributes needed > by the > > > implementation to support crypto API calls. > > > > + > > > > +Note: Some implementations may have difficulty dealing with > application > > > buffer addresses, as these may be virtual addresses that are mapped > > > discontiguously into physical memory. > > > > +For such implementations, memory SHOULD be allocated contiguously > and > > > MAY need to be “registered” to have proper addressability for crypto > > > operations. > > > > +This area of the design will be updated based on experience in > dealing > > > with different crypto implementations that have such requirements. > > > > +Synchronization > > > > +ODP operations fall into one of three categories: > > > > + > > > > +-# Inline (Synchronous): Upon return from a call the operation is > > > complete. > > > > +Operation is thus completely synchronous to the caller. > > > > +Inline is the appropriate model when the invoked function takes > > > relatively few cycles or when the caller cannot feasibly progress > without > > > the results of the invoked function.\n\n > > > > + > > > > +-# Parallel: Upon return from a call the operation has been > initiated, > > > but is expected to complete shortly. > > > > +The caller continues to execute until it needs the result at which > > > point it waits to complete the parallel operation. > > > > +The effect is as if the operation were inline except that the caller > > > was able to execute in parallel with the operation for some > > > application-determined period of time. > > > > +Parallel is the appropriate model when the operation being > performed is > > > relatively short (a few dozen up to perhaps 100 or 200 cycles) and the > > > caller can usefully accomplish other processing on the same unit of > work > > > while the parallel operation is in progress, but not enough to justify > the > > > overhead of a formal queued work dispatch.\n\n > > > > + > > > > +-# Offloaded (Asynchronous): Upon return from the call the operation > > > has been queued for execution. > > > > +A completion event will be queued back to the scheduler when the > event > > > is completed. > > > > +Offload is the appropriate model when the invoked function will > take a > > > substantial amount of cycles (thousands to tens of thousands) allowing > the > > > invoking thread/core to service other work until the operation > completes. > > > > +For offloaded work, completion is indicated by a completion event > being > > > posted back to an application-designated completion queue. > > > > +Upon receipt the unit of work that initiated the offloaded operation > > > continues processing with the results of the call. > > > > + > > > > +The synchronization models of interest are summarized in Figure 1: > > > > + > > > > +![Figure 1: Synchronization Models](./images/syncmodels.png) > > > > + > > > > +Note: Because few implementations are expected to offer the Parallel > > > mode of operation as described above, this mode is reserved for > potential > > > future use. > > > > +For ODP only synchronous and asynchronous crypto operations are > defined. > > > > +@section functional_definition Functional Definition > > > > +@subsection abstract_data_types Abstract data types > > > > +The following enumerations define various algorithms used for > ciphering > > > and hashing. > > > > +These are the basic operations applied to input data. > > > > + > > > > +A particular ODP implementation should map these values to the > actual > > > information to be passed to the crypto engine. > > > > +As such, the actual values of these enums is implementation-defined. > > > > + > > > > +Cipher algorithm encoding specifies the algorithm and cipher mode > > > employed (as per security relevant RFCs - [4305]( > > > http://tools.ietf.org/html/rfc4305), [4868]( > > > http://tools.ietf.org/html/rfc4868), [4494]( > > > http://tools.ietf.org/html/rfc4494)). > > > > + > > > > +@code > > > > +enum odp_cipher_alg { > > > > + ODP_CIPHER_ALG_NULL, > > > > + ODP_CIPHER_ALG_DES, > > > > + ODP_CIPHER_ALG_3DES_CBC, > > > > + ODP_CIPHER_ALG_AES_CBC, > > > > + ODP_CIPHER_ALG_AES_GCM, > > > > + ODP_CIPHER_ALG_AES_CTR, > > > > + ODP_CIPHER_ALG_KASUMI, > > > > + ODP_CIPHER_ALG_SNOW, > > > > + ... > > > > +}; > > > > +@endcode > > > > + > > > > +Authorization algorithm encoding specifies the algorithm and the > length > > > of the authorization used (as per security relevant RFCs - [4305]( > > > http://tools.ietf.org/html/rfc4305), [4868]( > > > http://tools.ietf.org/html/rfc4868), [4494]( > > > http://tools.ietf.org/html/rfc4494)): > > > > + > > > > +@code > > > > +enum odp_auth_alg { > > > > + ODP_AUTH_ALG_NULL, > > > > + ODP_AUTH_MD5_96, > > > > + ODP_AUTH_ALG_SHA1_96, > > > > + ODP_AUTH_ALG_SHA1_160 > > > > + ODP_AUTH_ALG_SHA2_256_128, > > > > + ODP_AUTH_ALG_SHA2_384_192, > > > > + ODP_AUTH_ALG_SHA2_512_256, > > > > + ODP_AUTH_ALG_AES_CMAC_96, > > > > + ODP_AUTH_ALG_AES_XCBC_MAC_96, > > > > + ODP_AUTH_ALG_SNOW, > > > > + ODP_AUTH_ALG_KASUMI, > > > > + ... > > > > +}; > > > > + > > > > +typedef union odp_crypto_alg_t { > > > > + enum odp_cipher_alg cipher; > > > > + enum odp_auth_alg auth; > > > > +}odp_crypto_alg_t; > > > > +@endcode > > > > +@subsection parameter_structures Parameter Structures > > > > +@subsubsection crypto_sessions Crypto Sessions > > > > +The following structure describes a crypto session. > > > > +All packets / raw data buffers processed in a session share the data > > > that defines the session. > > > > +A crypto session is defined by: > > > > + > > > > +- Operation type : encode or decode\n\n > > > > + > > > > +- Algorithms specifications, keys and , if required, initialization > > > vectors. > > > > +When initialization vectors are not provided and they should be > > > provided automatically by the crypto engine.\n\n > > > > + > > > > +- The operation mode: synchronous or asynchronous. > > > > +Synchronous operation blocks the caller until an operation status > and > > > result are available. > > > > +In synchronous mode there is at most only one outstanding crypto > > > operation in the calling thread. > > > > +In asynchronous mode, the caller starts the crypto operation and > later > > > it may receive the status and the result together with a request > context. > > > > +The operation status and result may also be received by a different > > > thread.\n\n > > > > + > > > > +- Operation mode parameters: For asynchronous operation a completion > > > event containing the status, the result and the request context is > enqueued > > > to a completion queue. > > > > +In case the queue is under the scheduler control, the scheduler > > > determines who will receive the completion event and when. > > > > +When the completion queue is not scheduled, the thread which is > > > supposed to get the operation output has to explicitly poll the > completion > > > queue. > > > > + > > > > +Note that this is an abstract data type and its structure is > > > implementation-specific. > > > > +The layout shown here is for illustrative purposes and the actual > > > layout will vary from one implementation to the next to most closely > align > > > with the structures needed by the underlying SoC platform. > > > > +Applications set and reference fields in the session structure via > > > accessor functions that hide the actual layout. > > > > + > > > > +@code > > > > +typedef enum odp_crypto_op_t { > > > > + ODP_CRYPTO_OP_ENCODE, > > > > + ODP_CRYPTO_OP_DECODE > > > > +}odp_crypto_op_t; > > > > + > > > > +typedef struct odp_key_t { > > > > +}odp_key_t; > > > > + > > > > +typedef struct odp_crypto_session_t { > > > > + odp_crypto_op_t op; > > > > + struct { > > > > + enum odp_cipher_alg cipher_alg; > > > > + odp_key_t *key; > > > > + uint8_t *iv; > > > > + size_t iv_len; > > > > + } cipher; > > > > + > > > > + struct { > > > > + enum odp_auth_alg auth_alg; > > > > + enum odp_auth_len auth_len; > > > > + odp_key_t *key; > > > > + } auth; > > > > + > > > > + enum odp_crypto_op_mode { > > > > + ODP_CRYPTO_SYNC, > > > > + ODP_CRYPTO_ASYNC, > > > > + } op_mode; > > > > + > > > > + struct { > > > > + uint32_t timeout; > > > > + struct { > > > > + odp_queue_t completion_queue; > > > > + } async; > > > > + } op_mode_params; > > > > + > > > > + odp_session_proc_info_t session_proc_info; > > > > +} odp_crxsypto_session_t; > > > > +@endcode > > > > + > > > > +The completion queue contained in the session structure is an in/out > > > parameter. > > > > +If provided, then the queue specified is associated with the session > > > and is used to ensure order preservation on that session. > > > > +If not provided, one is created and returned to the caller. > > > > +Note that this completion queue is used to order operations > performed > > > on this crypto session. > > > > +It should not be confused with the completion queue specified on the > > > odp_crypto_session_create() call (see below) that is used to control > > > whether that call is itself processed in a synchronous vs. asynchronous > > > manner. > > > > + > > > > +The following structure comprises processing information. > > > > +This is logically divided in two parts: > > > > + > > > > +- Processing input info - When crypto engine provides support for > > > protocol processing, this information is provided in a higher level > common > > > protocol terminology form and a particular implementation should be > able to > > > derive everything it needs from this definition. > > > > +In addition, for crypto engines able to automate tasks like memory > > > allocation for the output a buffer pool id may be specified.\n\n > > > > + > > > > +- Processing output information - statistics about processed > > > bytes/packets. > > > > +These are useful when a session expiration is based on traffic > volume. > > > > +These statistics may be updated by the software or by the hardware > > > crypto engine. > > > > + > > > > +Again, this is an abstract type whose specific layout will vary > based > > > on implementation considerations. > > > > +Access to fields contained in the structure is only via accessor > > > functions. > > > > + > > > > +@code > > > > +typedef struct { > > > > + uint64_t pkts_processed; > > > > + uint64_t bytes_processed; > > > > + uint64_t pkts_errored; > > > > + uint64_t bytes_errored; > > > > + > > > > + odp_buffer_pool_t out_pool; > > > > + > > > > +} odp_session_proc_info_t; > > > > +@endcode > > > > + > > > > +This enumeration defines which operations are applied and the order. > > > > + > > > > +@code > > > > +enum odp_crypto_combination { > > > > + ODP_CRYPTO_CIPHER_ONLY, > > > > + ODP_CRYPTO_AUTH_ONLY, > > > > + ODP_CRYPTO_AUTH_CIPHERTEXT > > > > +}; > > > > +@endcode > > > > + > > > > +This structure defines a contiguous segment in the input data which > > > starts at offset offset and is len bytes long. > > > > + > > > > +@code > > > > +struct odp_data_range { > > > > + unsigned offset:16; > > > > + unsigned len:16; > > > > +}; > > > > +@endcode > > > > + > > > > +@subsection api_functions API Functions > > > > + > > > > +@subsubfunction Session Creation > > > > + > > > > +This function is used to create a crypto session. > > > > +The required parameters are: > > > > + > > > > +- Operation : encode/decode > > > > +- Processing info : cipher/auth/both > > > > +- Preferred mode : sync or async. > > > > +- Algorithms suites, keys and optional IV > > > > + > > > > +Session creation can be synchronous or asynchronous. > > > > +Completion event argument is used to return the status and the > session > > > handle. > > > > +When completion queue is not provided (synchronous call), the > > > completion event is available upon function call return. > > > > +When completion queue is provided (asynchronous call), the > completion > > > event is placed on the completion queue. > > > > + > > > > +@code > > > > +typedef uint64_t odp_crypto_session_t; > > > > + > > > > +struct odp_session_params { > > > > + enum odp_crypto_operation op; > > > > + odp_session_proc_info_t proc_info; > > > > + enum odp_crypto_op_mode pref_mode; > > > > + enum odp_cipher_alg cipher_alg; > > > > + odp_key_t *cipher_key; > > > > + uint8_t *iv; > > > > + size_t iv_len; > > > > + enum odp_auth_alg auth_alg; > > > > + odp_key_t *auth_key; > > > > +}; > > > > + > > > > +enum odp_crypto_ses_create_err { > > > > + ODP_CRYPTO_SES_CREATE_NONE, > > > > + ODP_CRYPTO_SES_CREATE_ENOMEM, > > > > + /* Session creation error codes */ > > > > +}; > > > > + > > > > +void > > > > +odp_crypto_get_ses_create_compl_status(odp_buffer_t > completion_event, > > > enum odp_crypto_ses_create_err *status); > > > > + > > > > +void > > > > +odp_crypto_get_ses_create_compl_handle(odp_buffer_t > completion_event, > > > odp_crypto_session_t *handle); > > > > + > > > > +int odp_crypto_session_create( > > > > + struct odp_session_params *params, > > > > + odp_buffer_t completion_event, > > > > + odp_queue_t completion_queue); > > > > +@endcode > > > > +@subsection crypto_operation Crypto Operation > > > > + > > > > +Crypto operations are described by a parameter structure: > > > > +@code > > > > +struct odp_crypto_op_params { > > > > + odp_crypto_session_t session; > > > > + odp_packet_t pkt; > > > > + odp_packet_t out_pkt; > > > > + uint8_t *override_iv_ptr; > > > > + unsigned hash_result_offset; > > > > + struct odp_data_range cipher_range; > > > > + struct odp_data_range auth_range; > > > > +}; > > > > +@endcode > > > > + > > > > +<table> > > > > +<tr><th>Parameter</th><th>Meaning</th></tr> > > > > +<tr><td>session</td><td>Session to perform the operation</td></tr> > > > > +<tr><td>pkt</td><td>Packet / buffer to be processed</td></tr> > > > > +<tr><td>out_pkt</td><td>Handle of an output packet / buffer to be > > > returned as the result of the operation. > > > > +There are three different ways this parameter is used, depending on > the > > > mode of operation requested by the caller and the capabilities of the > > > underlying implementation:\n\n > > > > + > > > > +-# If out_pkt is the same as pkt this indicates that the operation > > > should be performed in place.\n\n > > > > +-# If out_pkt is different from pkt this indicates that output > should > > > be placed in the buffer supplied by the caller.\n\n > > > > +-# If out_pkt is omitted (a null/invalid value supplied on input) > this > > > indicates that an output buffer should be allocated by the operation > and > > > returned as part of the completion event associated with the > operation.\n\n > > > > + > > > > +Note that not every implementation will support all of these modes > and > > > MAY require that one mode be used in preference to others. > > > > +Any such implementation restrictions are communicated as output from > > > session creation.</td></tr> > > > > +<tr><td>override_iv_ptr</td><td>Optional IV to use for this > > > request</td></tr> > > > > +<tr><td>hash_result_offset</td><td>Offset into the output packet > where > > > the hash result should be stored.</td></tr> > > > > +<tr><td>cipher_range</td><td>The byte range (offset:length) of the > data > > > to be processed for ciphering.</td></tr> > > > > +<tr><td>auth_range</td><td>The byte range (offset:length) of the > data > > > to be processed for authentication.</td></tr> > > > > +</table> > > > > + > > > > +The crypto operation is initiated with a single call that passes the > > > parameters for the operation and an event (for asynchronous > completion). > > > > +@code > > > > +int odp_crypto_operation( > > > > + struct odp_crypto_op_params *params, > > > > + odp_buffer_t completion_event); > > > > +@endcode > > > > + > > > > +Parameter | Meaning > > > > +----------|-------- > > > > +params | The parameter structure describing the crypto operation > to > > > be performed. > > > > +completion_event | The event delivered on completion. > > > > +It provides information about the status of the operation, result > and > > > request context. > > > > +In synchronous mode the event is available upon function call > return. > > > > +In asynchronous mode, the event is placed on the session / operation > > > completion queue when the operation finished. > > > > + > > > > +Upon return the return code indicates whether the operation was > > > synchronous or asynchronous, or if an error occurred that prevented the > > > operation from being performed. > > > > + > > > > +Get session operation : > > > > +@code > > > > +odp_crypto_op_t odp_crypto_session_get_op(odp_crypto_session_t ses); > > > > +@endcode > > > > + > > > > +Get session cipher information : > > > > +@code > > > > +odp_cipher_alg > odp_cipher_session_get_cipher_alg(odp_crypto_session_t > > > ses); > > > > +@endcode > > > > + > > > > +Get session authentication information : > > > > +@code > > > > +odp_auth_alg odp_crypto_session_get_auth_alg(odp_crypto_session_t > ses); > > > > +@endcode > > > > + > > > > +Change session IV : > > > > +@code > > > > +int odp_crypto_session_iv_set(odp_crypto_session_t ses, uint8_t > *iv); > > > > +@emdcode > > > > + > > > > +Change cipher or/and hash keys: > > > > +@code > > > > +int odp_crypto_session_key_set(odp_crypto_session_t ses, odp_key_t > > > *key); > > > > +@endcode > > > > + > > > > +Destroy crypto session. > > > > +All pending operations are cancelled. > > > > +@code > > > > +int odp_crypto_session_destroy(odp_crypto_session_t ses); > > > > +@endcode > > > > + > > > > +Get completion event information - algorithm error, output and > context. > > > > +Note that implementations MAY define their own specific error codes > > > that have meaning in that context. > > > > +For application portability it is sufficient to know whether an > > > operation completed successfully or experienced an error of some sort. > > > > +@code > > > > +enum crypto_alg_err { > > > > + ODP_CRYPTO_ALG_ERR_NONE, > > > > + ODP_CRYPTO_ALG_ERR_MODE, > > > > + ODP_CRYPTO_ALG_ERR_DATA_SIZE, > > > > + ODP_CRYPTO_ALG_ERR_KEY_SIZE, > > > > + ODP_CRYPTO_ALG_ERR_ICV_CHECK, > > > > + ODP_CRYPTO_ALG_ERR_AAD_SIZE, > > > > +}; > > > > + > > > > +enum crypto_hw_err { > > > > + ODP_CRYPTO_HW_ERR_NONE, > > > > + ODP_CRYPTO_HW_ERR_DMA, > > > > + ODP_CRYPTO_HW_ERR_BP_DEPLETED, > > > > +}; > > > > + > > > > +struct odp_crypto_compl_status { > > > > + odp_crypto_alg_t alg; > > > > + enum crypto_alg_err alg_err; > > > > + enum crypto_hw_err hw_err; > > > > +}; > > > > + > > > > +void > > > > +odp_crypto_get_compl_status(odp_buffer_t completion_event, > > > > + struct odp_crypto_compl_status *auth, > > > > + struct odp_crypto_compl_status *cipher); > > > > +@endcode > > > > + > > > > +Returns the output packet handle associated with the completion > event : > > > > +@code > > > > +odp_packet_t odp_crypto_get_out_pkt(odp_buffer_t completion_event); > > > > +@endcode > > > > + > > > > +Sets a context handle to be returned with the completion event : > > > > +@code > > > > +void odp_crypto_set_compl_ctx(odp_buffer_t completion_event, > > > odp_compl_ctx_t *ctx); > > > > +@endcode > > > > + > > > > +Returns the context associated with the completion event : > > > > +@code > > > > +odp_compl_ctx_t odp_crypto_get_compl_ctx(odp_buffer_t > completion_event); > > > > +@endcode > > > > + > > > > +This section describes the API/Interface being defined at a > functional > > > level in technical detail. > > > > +Sub-sections include header file names, where implementation files > are > > > expected to reside in the ODP git tree, as well as the name, > parameters, > > > abstract data types, functionality, return codes, and exception > conditions > > > of each function call defined by the API/Interface. > > > > +Appropriate diagrams, tables, etc. should be used to allow the > > > programmer tasked with implementing the API/Interface to understand the > > > function to be implemented as well as error conditions, corner cases, > > > performance requirements, etc. needed to implement the described > > > API/Interface in a functionally correct and efficient manner. > > > > + > > > > +@subsubsection random_number_functions Random Number Functions > > > > +As noted earlier, random number support consists of two functions: > > > > +@code > > > > +int odp_hw_random_get (uint8_t *buf, uint32_t *len, bool > use_entropy); > > > > + > > > > +int odp_drgb_random_get (uint8_t *buf, uint32_t *len); > > > > +@endcode > > > > + > > > > +The difference is that the first provides access to hardware random > > > number functions that return true random data. > > > > +This is typically used for seed values. > > > > +The second provides a deterministic random bit generator conforming > to > > > NIST standards and is used by various crypto protocols and algorithms. > > > > +The use_entropy parameter on odp_hw_random_get is used to disable > any > > > hardware pre-processing normally provided by the function and is mainly > > > intended to be used for testing/validation purposes. > > > > + > > > > +@subsubsection buffer_pool_extensions Buffer Pool Extensions > > > > +To support zeroization a buffer may be allocated with an > > > ODP_CLEAR_ON_FREE attribute that specifies that this buffer should be > > > zeroized upon free. > > > > +Alternately, a new type (ODP_CLEAR_ON_FREE) is added to > > > odp_buffer_pool_create() that specifies that all buffers allocated from > > > this pool must be zeroized upon free. > > > > +Essentially, the buffer security attribute is set by default from > the > > > attributes of the buffer pool that it is allocated from. > > > > + > > > > +@subsubsection capability_inquiry Capability Inquiry > > > > +To enable applications to determine crypto capabilities. > > > > +@code > > > > +int odp_crypto_inquire (enum odp_cipher_alg, enum odp_auth_alg); > > > > +@endcode > > > > + > > > > +Inquires whether the specified crypto and auth algorithms are > supported. > > > > +Responses include: > > > > +- ODP_HW_SYNC_SUPPORT > > > > +- ODP_HW_ASYNC_SUPPORT > > > > +- ODP_SW_SYNC_SUPPORT > > > > +- ODP_SW_ASYNC_SUPPORT > > > > +- ODP_NO_SUPPORT > > > > + > > > > +HW support means the combination is supported in hardware, SW > support > > > means the combination is supported in software by the implementation. > > > > +No support means the combination is not supported by the > implementation. > > > > +The SYNC and ASYNC return options can help the application decide > how > > > to invoke these functions, or it can just check whether or not the > response > > > is ODP_NO_SUPPORT. > > > > + > > > > +@section implementation_considerations Implementation Considerations > > > > +One of the main purposes for the ODP crypto APIs is to provide > portable > > > access across different SoCs whose hardware crypto capabilities largely > > > overlap but vary in terms of their implementation details. > > > > +As a result, implementations need not provide software fill-ins for > > > specific cryptographic features that are not available as hardware > features > > > on that platform. > > > > +Presumably applications needing specific features will select > platforms > > > on which these features are present. > > > > +Therefore, while all APIs specified here MUST exist in each > conforming > > > ODP implementation, it is acceptable for these APIs to return > > > ODP_RC_FEATURE_NOT_PRESENT in response to calls requesting crypto > features > > > not present on that platform. > > > > + > > > > +For example, the linux-generic ODP implementation may only implement > > > the null cipher suite (ODP_CIPHER_ALG_NULL) and return a feature not > > > present error code for any other cipher. > > > > +This indication will also be returned on that platform in response > to > > > odp_crypto_inquire calls for non-null cipher algorithms. > > > > + > > > > +@section verification Verification/Testing > > > > +This section describes the verification/test cases needed to ensure > > > that the defined functionality is implemented correctly and performs > > > adequately. > > > > +This should be at a level of detail such that the programmer tasked > > > with writing test scripts/programs to verify the implementation(s) of > the > > > defined functions can be written to ensure that all relevant functional > > > variants and error/exception cases are properly tested. > > > > + > > > > +This section needs to be completed before API testing begins. > > > > + > > > > +*/ > > > > \ No newline at end of file > > > > diff --git a/images/syncmodels.png b/images/syncmodels.png > > > > new file mode 100644 > > > > index > > > > 0000000000000000000000000000000000000000..44e4c551bd803b7dd4320875699828d7f20d2044 > > > > GIT binary patch > > > > literal 17179 > > > > zcmch;XH?Tcv@Z$>iXhSqNDxrER8c~aDjh?WUL(Et-Vx~th$xXJz4smxnsljBLkDS* > > > > z-U&T7c+PqEth3g=pWb`(A^(+`Ju`dSo?U(urKTcJLIfnj!NDO>RFHXxgM;UcgM-UP > > > > zco&=V+&Rz%2S;jIQRa=N_smYZm=g1R%A)G;H}~-I@#)CiCI2J+roi>GZf!`WZf2C^ > > > > z)RvpX$JcFtiQ5qoYL6FkUycg*4Vd+@&4{rjkG>nkclWe8rfD1Kcc1XHC~lIRaY%yb > > > > z&#AzVI)|_y#V9pZhT`)S%d?B?+??Iw*B&jKn(0AesGPJrSZ@CB2`0NB4)JL96L+p} > > > > z2EA*#7UJYgNNv7slHc$~o1KpsjkR7Barezu`JrcdID~L;+5)WX%*UJQ&Yi``U%4(X > > > > zh-E}#FgHFdGdD9&|LPB(lF}u>&RE{s?M=6MF^#D=F|5EA<NV{oCcMa<zn~Mk<T(Ze > > > > z&0HR0nL<AyH)RZQ<XDn1{1sHSG^Y=gE!Bz}JL8mgNokN{HQQR8?0sLmM}k+*VtSKU > > > > z0(G5xjIBkg*mgar8dl?2>(#mwgCLf6u_Q?2KQ*N}ioKasK+MwbOk$c3&Z~KIZ=mPa > > > > zLC?i`823#_G-G7OIGO%Zt?-*4ASFD1bOllAd=>Z=)0y0vs(aX((aGyG^fp5mz!EEf > > > > zF>d?iB8)~$oLa4x=o~?8D}fg;$+MVIVN%ak%xZb5y40sy{T31f2D7)Al2jElI=#fN > > > > zx)0-4Uf!(2BHt@6HeOe~;Bhg-@+!)V3ysYAsLS76mS&4ywdoKN<Xkcj8vRSH?CpA^ > > > > zZ9jN`nyu1e6#Y_3nzMKf^V7svbi+ln5P6Btmp3WERhY<Khny?~P8Zpg?wVm3cV*HP > > > > zF7irVsHEod?fy`fjUhz9{Io}Ph2yS$vZyi)rbl*X|6+P8NG4lr_T`IRUN`;zBs<+} > > > > zT&;Tegh9lXEM8H#WzrQ4k0`6-rOIZab@5GnK@r4wCG}xiH?WAEvh^2e8oA|8_7(DV > > > > z5#{zDv#r_|AZFJ|X*X!oF;&=4Fo&EnWes7Xf5LE1ZL%z@!1el5uR?cCfVh?NTYPzB > > > > zBcJE;-j0G%Ppbn+w^1fHs*r*cspp$f(G$WC(1olV7+1;iP|5mP^(0==$z0aQYE_N1 > > > > zFJ;$W95c_yL552$#QpDU9PXBRRb|F>CNv1JuK7MGSR~?}M)kid{}5SM^TJ#tde-1^ > > > > zqHAH7)P6A@4^IsHUVRggU`~aL0v88o>F0e|d~9In=Gaqy9!h71JGknx1kk5a>{LRn > > > > zJ7WiSU7d^tmr_kniLBtPMh%Gv_z#>Ks~I~B1j#>TDETJt+oLT^>%d$VrsQ^(^G805 > > > > zKs`qV`Q@O}XIF0R3S5rE1tG5KaRey<eev{=NU2n>D%~0XZj&qBhgXJ-OXdPjX%P#o > > > > z=imy!?b@^Bdbyh91U3fS1-8WVR+)p~rF@V<{4{`?m9{iM{V>%%rk<_FJQmO&;nng$ > > > > zrTh`()rUt!GGJ4Hs6_n$G;B|fguqa@K59S3=7BW#S1Y_73S6kJOv%g%BFORd1>Wru > > > > z!u2w4OV|4}Q}I>YDXg!02-Nv(Wm^-*Y!s7WMx3ro>HuA`z}u}pb7Wlla_sN$xCfeh > > > > z-W5g#<HDupfx1pwl$br>rF8z`UH#Tx?|Sq_6f-@-8m^0-NE}>f=?0ZSkg?(OfT*s& > > > > zb{*dZs*0x%Ty1n#a>?cGHq3Fy=zNod!EhM~!B6L4R*B;U-8PoMFD@Qd*}L}J^ON5Q > > > > z3}1fu1ADd?Xm4aDO1ti>l2Ox^PN%VDw89)IJsE-(Op<Ns5)e4989DV%{7NE$`Jm+0 > > > > z(K4#==OJ^AIAuaz@=bhu!^+GR4DM`H(~oaRaYLLQS(zSQ!MLA~$1{y#A$MTpS)qZ& > > > > z*0}KkoEc%u(+GK>9QVU9&yPO_e*?h!qR&iJt;nIH)t~yf8;2sQj@A-&iD=n^v7>7X > > > > zc;w7TG_d4bWf^7^5ZGMr?sur<9VshcD!Ne3bXi7tV9IfIr74>H=iHEynQ_Er1O;1W > > > > zk>I$rnyotFAW|IyP#dhiq{>i+Ye7KUVEDs=;cp-67Si*Csi1BoR2<J!o$-Q|gS5|L > > > > z4+g%AHrzW;vt^H{v=5sKp*aU1il;Y*r$;Ia^Y}#fbHM2rGIS}|nrc>1Ne1U9ee<(e > > > > z{&18JjB@`B48?@mEPm@A`T+R6^(hEDWx-U@F$ouS;wIldeGtiCDpz<px&I1cf~^od > > > > zN%W~-ywM^`V#T5x`m;+xXUl^t?Y1c#oPFl|)POywWv3Ue1Rf=pkRD22iI#s?!(zJg > > > > zALmv^$p~`W5H3@mm}crh;p#o{<J!5r$k%+Po@tx-*!o`2m(0u5XnMFxfV~6WdcQKs > > > > z2!&cJ<gb+rKfCzGl@h)vL4`g#`Ci)o8TsPEJtNcvs`179wMRyppjGD=u9aiOl~V{M > > > > z1?O`1{aMD1Zx%(YC&-OGQ@OP2irm@5yet7qtA^*i<cO_=*_S2{{+@r-<imD)W{g)( > > > > z(I^dg!5C6}u}FmN5KJ(h+IyatbISifm}l$LOkVzs))VbdpHqIr*fe_s_)-392h0bK > > > > z#q7l;k(AFoiVxgvb^SK2^sWs$7pVbI7Uhnl=+@%!=@OIUzb+6J<47Lc*8x6?Gup>j > > > > zfdKa#|H%{VV1xHqm!f}G#o(t=TSQ#U=4JOAti>7GRvj)oi$!`#5kRe^uSsCFF}1s+ > > > > zJO;GkMoocZc}bvxWu8aQ29|!{E@UXVi7X)9f{Brr!dd(}=7S_1aVRHtJd)rk(t1@V > > > > z_N8K;I_(qqxGySwr|%Ibvg84-6||UwIHlq5w^uTndMghI=He7JUg7GHT&bqI`+i_= > > > > ztxz_uU|I?dAsW3?e0v4f0-c^yxG<XaH`Rel6-;HfoS|M>4}l*v)G!R1y-@_VPa|sz > > > > zd)68tM(n|97s8&g+Lg$ZdS#~UhlVpA!Z{m#C2DhxGHrvl-+h$*8loFiH0};{B3IsR > > > > zWdodZ^gZc(9iidRH=J@(u!2C6lbpPcsxgI#ol`*OfkRPcvZng7?3Y)UO(3N-jH71- > > > > zQHldV@tK9#seT88b5Y(PlZhTUoe=gMVBsb=MPj4-5$>dNbTpF=S<eNJ?Nr?$LGwl_ > > > > zP;RJ-)L(7#hWzES#oUo1T?6DX)v>>#Mi|Gf{-k=J+&17tFy}ii>>nI7^tUSt%8z@- > > > > z+R0@A&uhTt>pE=^DwFjfJ$F;C=1~{aBE?cUaxj~R#~ufOThGm7I-oRst+i^U3XrR~ > > > > zoAQOFs|mk%yPn;YSh}`v<itr_FRbtRUSM8|$lmqp8=#i3(7$WxS;THPc1;O4vZjdO > > > > z!eRfY2z63FTji(wvXH%-So=!}$Y*f5xAH6VU29)mZo^_O;_=zmi2r@M3rtx5j}K#c > > > > zF0&`TcR`K_)q%B_)*f8F^6JAG&ZRX+h3woDZo})g*I)5*_LV}k8JD@X5O$2?4>kQG > > > > zEgbtJ3*baF<V>?13RfJ+KUU)K6GL)IHtt8xfhpb*(}HE~TMDw1h52p@D?H|eLY&## > > > > zwR@C<v&4gAAJz}Tc1gQt6X+r8f7sf0VxwUWO!%b7t&w%Zz=m8i$k_9m2xARy25Jee > > > > z>p3Ii!e(CH?Hd^ztnl+@B^lnk5pAlxr2g97Au9vchAyYrrSbR|XZP|rvM+DsfOQHM > > > > zyimv<J<kon1<#jpi<)icJmY%GNUOv+F{ZxPC#^;g4wwl`l7o*vf;oZtq!^9QKlGp~ > > > > z(tM+hyL2fSOBOpxD^mnh&2NdfO5uIt;sy5!gmL>yjSUhMntY}K6W(>=TA9MA`@ > > > > z3mUA+4I9pd?s=^yKf2!-gq^UX@ydJNsxb38gCvD&hO!d|7zyHf8zoz9Ii6N{R#Z}` > > > > z=adl4nY<HHRqVrNldic1Vc(R(6&#mo)8n+54;7=zwNjVW{l1s>ynyL?zQ4DpR1p<w > > > > zmYy!(v;VG{ta;<c=WK1aR+N41k75yyVNI2O;Wcj72;6G4CTu3->Qxkl&-Ya=d!^zt > > > > zpc*b;86HysqgiW|_ZK(6;~*U}&tIUxoHAu@pGAGW>h3nWdmFt)S|z0i^eJvlAij!a > > > > z8?A<h6hc@wxHSsJZL7yPHC(?lTFDyQW-zkCFhPOL!GQJGJ;Z*v4JZX@_If84{-LQR > > > > zRm6YNMuI<gb;;WiQ)lru`(&8e8x|?4r$b(qKPwENt9I(hqr7AJNsYo>y<Pc)I*@oM > > > > zUZSQHAGH{o{2*b>Vf2p#(`bQIaWP|G#;dX$a|139C&QVr4TPUGI4g374q!V*W0L|} > > > > zV>7MHT+>F1HV~LP&4YNDUS?f-DFK(NTCN$Fa2%Z%$8T)B1JUu=&5HAM35Wi70Mp04 > > > > z<Tv+ma0rEh?|CjNP(RJXiUmR;oLyS%X#z6-`({4FTWa~!f-U&ZjQ{##3;s6&w)h|6 > > > > zKeF>${R7~eKD4{v3FhlfAKUa<IgcSVCiXAl{iM-;nLYj!9Gp2TTsD%aKcJ6>nj>s! > > > > zkJTIGY&t**PW-Bnj@BmYuLh4AIz^&_@8ASSurGx(qG#+IWXm5ls>~-16Q0PHLokAr > > > > z&h7W!(v~X@=1ng0lm*>chn4v)cQZEFY+89e-96l_(1`!l;^|R6Z+GQobA=rgj<++O > > > > z<FxKGBA%*lZo3ZF*^&eUmnaX1OA1^z)Un#KGl_T##>3+sMC2I#ZL-G!V4_u)<3@8* > > > > zQOwK0I1|UzutGtcF+L$y)<JQjnRrHywF&p%<EK5L9mkBa3v3N>eDAKto*5GMHZ9@% > > > > z_;a6cc#G9IQ!oT&kO@|l0j}5TyO@JeqBjM+k41i-6Wq>$s5x$fV`y@ZfkY<}ng;h? > > > > z1J_dY1!QyNUYXrOoso3g#Nf?+u|<m~iAN&;di#x^M)+zmjKc`L@NT4tWSwok9>cpS > > > > zwUgKR2k39lxb#}H&4*Kefe=CB7U%wrsy2{*0jr2D?B6aPOaoWPWrO*y4Sv^5{oWVH > > > > zd;x&><&5=iiNuB_-2}$(jaga_wwZ03k<)IFeuuGjddUVKYSbkqP;@<)sF~X%02mJN > > > > z$>E^`{<dl7xO+m4dk<@{$+gX!(<E@2uRkTBH-tX-YPOKk|5a<3_B;4?>FzNt;a9o4 > > > > z2bl4j-Z#0+VMv{<2ltkD;kEmZ<@k)%b74-{dpVpi_!4_J{MXky66fE4?Dw`9=Rd#L > > > > z;{O}@k~kBC=3czvFBS&#Ai_C)vp3TCZ2@<1oEH<EXz67f#auag&ebj(B4H0nQ1!x% > > > > z-{h=K&}gjm`dG*}lWBW<B5-y&OUe&crhKmHq75OdmP~?VjoAmUiWyZ;p^Sp4QPP@W > > > > znOz}QN??*Mx*HVtfz{?QaXXp1aGr}7ZO}DPMfK@YA2c-RMDDMJ!@=~`t^|~NK~)We > > > > zQ~mruuL<lf3`VT<60(8CTxSzfHTh2U(J>0XIU&2_ER*%>*Sy(|ugRPb)gW<m?^jQ? > > > > z?Db@F%eD?=0si+mE;te{GhI$>VT@dYvB9aMN3!;lEn1ziTobeX#B~@}l1Ey1GKFui > > > > z12Iv^tWUk#rOs_{d&5z7wdH!as4|GdCU1dhQ8sFu2E$nV7T#KZdC0LX%DB*8u1IdN > > > > zV~K!t9F`Wcr)gBJ^V1o(MNOru|Ag%V%c2BLy-m=(xqR(^oT(9q{b-Sd$jjHFt(TB~ > > > > zVuZwj5CP6v;P}f@Q{y&06CJHTo~3wwM4$rgMzuB%Sa<o*n-glH-ll0D0!Alwf|+dn > > > > zJ3BtcIB^?3d90?7aP$YTB75JyMVle8QN&2U81<YS%W{8V^wW)y?RQ`u`S4&$7v}lo > > > > z7EZ0W02f85WdTv~!}*{>Z4kMy{3csPyS->6CRTsykmL93Pg<4I9h)QWljA_45*zYK > > > > z%_U)Fc{b>yCC`Lsch|yZ$l6J8mK@26=aOFYR$6LF>WRa1W5$SuHl)5Ol8Ka$M5Fsy > > > > zR!}oqj~olnQu-nhOJB-W@0%&1No@7&Pg<>1I%vj@g#qp*970HtICfX!sAYNB*T<As > > > > z5#O4GIJ-2Xu{LG)rbcE(B)9+ne@ou{_OZ2y1|}`^ZiCUm>0Z#bms3Us<owD@A}QxZ > > > > z(sKnYC*CPd0piqAMTwnSaXCB6Xawrct*lY^hvY22W9<E*+BvI3<;)c0;)|6OI6v}( > > > > zX^Z4`Ur=cnFy)M3%6hMTOBf&Co_C!6LA>(7dL!PoabUw_<=(v0rRmQTK?wjJ-y}Wa > > > > z0<vy4(r_)^GtGCviRx{n==LC(JGJ(*OuLo7SeuXr7fP7h-0M&{1^g5j^cJBj9~c`5 > > > > z;g2ptrB(q{Wxj_(w-@7Xf<~?n{T>lFmk`2k{Zr9qY;iiHjHp>Yr~juJHcH|J?Z7CR > > > > zQTHZp?Ygprh4CN@7Aoyn(@neMOOE<#AL6t~(W<`trf*_o(}-I8@za#7y+vHfh#Q%e > > > > z0}fo0w{OK04h~kF!uo7pa=M!{U0gpQe$Cq=CF8DF1&Ar?bCIUDp^DOSI<Up#sfQ^G > > > > z<ZF}$ebc)Y+BlM?A4H;L)wct=1S9#XLZUo&N-z0$SxN8>e-ore*8cPk8oj>IDszVt > > > > z!#efRTC!`3Iey|{|2pgi-my|Fb-i~G8Y1KWjR)Y2bv9APh*f3#fPb7dMhAmg)gyyx > > > > z5l@x>bEHPjSJI-pJNAgf<#)I!g5-wPu0)D#=kkRxUvGgZynjpLY=n#U2W{N_Mi9hl > > > > zH-d?W62W9L0~9R_v@KU?3P)LdEpT;cqS@Z{rnvv&LQcSlk*fKUZP;~gOO)$wG8#8} > > > > zuFbze6l)bOp7FN3P}X#asYY{Aj6uT7crI37FREww*S3085AVaYPbCKKLDyzho5)a_ > > > > z0<dLAHzcaCJJ3QYJ$8)80uMVe|2^#&7R|YyRja`sVE+0suYn#licVlf{F2L4DcKeW > > > > z|3{4<dzBZTellJ49XLhpectV7<)FK31Lt|iS}k<81RCaC9NRKPZrz%w@xdp(=T7%g > > > > zc({xiEu7zX(ui8>-(zG}sRlg}H|r;94{L@AFtg+F1(`Rz6fupGZENm924uUkHm4ix > > > > zhU)vZ7KE8iyZwUXN#{$texK`yi2Gib__y!d2a3Gvo9H$<8oR;Y@_7aed>41Ee5JB^ > > > > z@T_dMofuuq{k{1@3cE|tp~K2RR&q~~gxOIDIeA|1&X#zUb5xxQ)xpBp&V*zq*JjmV > > > > zZ-8?Vs6RSNc1)q~B2J4WNI;rP@re_^n0TDyJY-_=Et$OHSY??_24C!PT>ehZMGeVW > > > > z5k0M%I-=rycC0oMlae%c4?sBD8#Ge;0N;mmBQT?$P7KmH9=)!2*h;nPH<YJ6qLcrL > > > > z4RrO8#7TN=-D+D$Su`MD)Ux(L2JjD9Ze%=5Esbl_qY71uA97v}E3vcM+6zUrSO9Tw > > > > z^p&)A%rl~ihx4Pqe<8xl0?WS9Ua=-fgZ%YV=u&xwi>zSG*MqZuf<6Dfk_xPM`WpWd > > > > zKTXw5-g(X-JMLv)TmHe+82}dqJo^@4MzhhP&=#B0^yItSL!%smYNTNdoF09?J0WBl > > > > z+bgD(rA{KFXmsremy1DZP&+%wUHKh|d~=Cg)R_#3;TXMcUaF8zI?=u2E@?w+?~2b0 > > > > zK5i2A24}RgB^lWQg0grGWAYv2N-}<Z+L|eG8Q#F8g(FONlheXEO^)$>PX08cUd-lr > > > > z*ns1GBslX$vD-;xpJnBz1i5ZV6Im5wr;&Oai1I~NFeUoUwPx&8jm`JINV7$dXY6&# > > > > zv!!Ah)UOsKM@uo35LUrzq~)NCs3kv&#dLxQ3`e#l?zfX7gyQ+dt6CyistjcFh9dwt > > > > zen3xHYq^xmVbtW2C7#OWO>OkmJ7<y|;mPGK2vHMkTIYl2Lu3D@$k*eqU*(~6PF{cW > > > > zzyyYWmzcZ|F2r1pr`ulba6CqW;y_S+D~BHvoBdMI=vvup$QZ0^m{VCNNRIB|UQWnO > > > > z`FBw#>+dY|1vog1@hRjqDzs6!Ohah`+IO(LuGta7QpB&)qrcoI2||6j>pjSytw#lO > > > > z9D8icx^xN}vRuiOA~qBf->D;)F8L7LPYdp@uKHnqAC^sSHt3z#?jY4MJszOaflkU1 > > > > zV0v4PZ&=Yi5fg0pSIR+Kz8XKRRlZ4$7KHu`Q+?Cq_A@4edS2S{Qj*|zEx0WIPmJVb > > > > zpdAg5`8bo4L(L83?@e*OgX9WBUvE&&W$yygI5TN}tacj@XO6~*!?MZG0+<XJP_fI; > > > > zG8iUvHdgZqVo+N7#<Ij(%QvkK?u13T$;%oEQI#swMstg`I046)>hPWb-*_em`{hVk > > > > zkEJ&(hcT99yPO?+*nLFxtm=_p=?~MrjNPmU_n^Z}{K(gPsvIm0nSOQXh!tpHF8LJb > > > > zQUWtb7eR<0&z4@-{S<RWn~5UP=9>M;<kx=AcW|L&uDg>vF5H)2;FYv4>arT_OWSqH > > > > zt{dJXLl4M7vodYz-?yelWZJ@#4xS}yGw8%84cg7$c$46wy7ujmLikvj)<U^M<Mew6 > > > > zY5jM0?!<DVPViuHm*)q|wEd*@0no*d?=ShtYtLW8!bl;z@rbcWX42E9IL`c{720wL > > > > zE^%*|dtormIFyQ<DNqXB8oj^ENeHt6aLSU@6t)+EEBx4(?i$&e(0bTV+dgM<sFSoG > > > > zEXFWF^_5kX4YzpcNE?=cWe$3Hjz&jmNa~D`^Bu1uf-8kFHto7$8azi8$m?j|z=9iz > > > > zT&ypr&0&T6?!rtDV?%rfee)!v4C|eQ=IwVSd(q^cf!c0U0Ar6Li?ZD1!p&;x??2pa > > > > zpm`YzzX4~{_eYuW91VwSc&P&+>av(>Fk5LTUdtkghuHkOqR@GJthOSV|0MMVq_C9- > > > > zsy|P(88q{C1MVjpV|;sm8b(8qmE2^``!XA9fB@Q+C)HG)S5#McF|ud}BSNo1jtQ(I > > > > zyFAMMjSBu{K6_F@)OWeO;dxc3JtvnlQ;u)R0%e=7l^TDo9G_}h?J71Nb>rj2hmXD! > > > > zL)({6sw(36Gu+jzJ#TRq39d)x*$Jo5=kQedpX<FhHKNskvivq*Oo)bQ2PnM;pPA=L > > > > zpT^qKHxZ~^EX8|doYC^%_!+L~gRgng8`l=S!&7p9LBCxmnNFuOAk=;bG`|tQ^2VhS > > > > z$W_1NU3pb`?1sj=1{lJrZ2@mTTG7n$l<-`djWhnf()3Cm-7R3g1bnkHd@bfH)iE_h > > > > zD3AXYA_mve2$#mS8soDV<;%NdHG;cdC_P<D3CNb`3U|^Zi-x^cdsDwV6jW{XyK_&% > > > > zfN}Dt4y)s$*!7z+mYyK>R#$t~u0Kf#e@|M`Ho3AUHNT(?VBKN+u4>28UWt%l|9t<< > > > > zaK}+yg?fO*nX=}vH=byVm7Y)0DN~*cT66xq#T^AimQ@koOvHXG%AIBLD4_Xc-*}w( > > > > zgsmK8HmSnD04M6Xc}mClW!p4Nz(E!XTe5zI>$Ul=WVJN9>We-(X~=QYeJ;1154~Ss > > > > zK(-n^cb>L-4yAOfzx(OMoyD0QEVpuVtLI}L3)&tbB%pgR^_Yd+qYh#OLi8qc;sNgj > > > > z@i3KbQ1m9UHGWG^6TNq3VNrBi;d8fcUrzwjgN~A1ysj}cv%Q`-X%%}M&CFYWDEC?S > > > > z=d0qRock+Wt~XZDI2{qsvU4u5^#@LiT&9BTe&TUe<RfQ+I2~J`BNOPyv#xhG1=7@a > > > > z5_AMm6_%?Vsw1a=poK~C73wjer;8-5bLlOlu`~PqSaU+*?|O)K%j4BP;<{(Eg^R?v > > > > z4QiKnbPDqD0){2}*%J_XVD2|95Ciy~d*j9YHe3pN4BwI<2q`a^bslD^%t|s$yM(~7 > > > > z!0t*$VdU)S)q9D1%Y6pOdad^!e{Z;O*^E+XKS<V;e)oTve1tH%h)Qv(GrTwmXB-XW > > > > zqY~%cuBO7^1M9T&*%-uvG2rvH%hq_AxraK0j&(m<N%3~qE-{z(MW?)tz_OsEpJFf` > > > > z4s)5bvZAHug^?vC-bc%Szu9fyJuzF$eWp7=CLs2+g&VyC{?_zsN@s+B%KcNS=yXIR > > > > zW;K3Q5$<(uWwCDf+Qx*5a4`rj*Jr~oG`T)HeCYjbU8krV(aq;p!(rN$fq9^4++e3K > > > > z&Qi=AJHxHd6mA;x{%g2*oAAdke-emcf1q_A|D4ZDxPoq@X#%!~R1RZH4Y>4W!7CO7 > > > > zI5_kgIo;oa3p9~FdRXlctLl2tVQuem>+xW?iV;@%2ZDg0%pdAVT%2Gzl3+OYX!G0h > > > > z+e#W0lw)N<EHD<RhAi5`s>eBZCI5qb6ldIH^ED36@4}HnT#xkssDaJHN)BvG<r@E5 > > > > zij^ZN+`7%nRKJsX+tTm<P5a+k|Hllr-~Xb`QNOeK`ac-NDa7`Q<>g<?nd<+o<d$_T > > > > zoBx}m|IzLLvD#Ak=JY?yw0siNwt3;b>T2ot()E1F`zFNgvYhP3WHsOEbN$a=z(D<1 > > > > z2c1<oli>SPv`o2qeauhK-r{fq9CX^Q!9$4((ofDJ1*BA}u$`Cn3<RxuQ*>P16SMTr > > > > zIdVpgucZ_0?9_E@61KcE@pfAu@^0_Sort5c-NliMyrXX21bO%xsq!?Q-kigcovJ&u > > > > zKYmU~MsmwJN_FXo?Ke2pL$xA}L54W6f;6nA%@Xi5boTHm#vCZ<^Y;qa=y_Br3X@-} > > > > zohc5MOWNES{VtZec<tleQh$v@TZbs*EFdi`*EKHD$_0$y`QT^gQM-1sZLt#sMJ-|w > > > > zd)f)vejNUMa1*19cP6WvPbQRwV<Zibn4AQ^oRd1_8MTW5Wh1ZefPOb?t+A7BdeTL6 > > > > z_N*IE-4(apYh$bucAsJJnsIrjcaFDuKKXzVGI0U7X+J?{#)1#k)LXw`Lda{yug&<& > > > > za28eD)=t(l_yt=;GxL>m)cH^(z#yZ|3fEY<>5V(Xt%E~0`f`IE4#FLMjJshz)?ZI> > > > > zZD@ZPC+@x(`%A6l>!;k(bAmf<LN7zPIl~Xha7VCEeLlR}ZH)oeVRVeWC0u%v5+a^1 > > > > zIlj~JtxGsW@>y-VLyet+%C1lL9sp}MGCw@&E3^Zg=)5?wpBb-sR%S*pFPM9RToe&@ > > > > z*k%Q#XH9Whd*6|3TT^Ogc!6GFqm(o5x9Xn1v$eV}wX@fPj_D%>OL+CiynE!eM!V?? > > > > ztuk&NITRn=(eb5g3bq@&ct?t_9YIu_ZCBe}Z#Q+vw^^W$J~{(bhEjoOufHtMq1KMs > > > > z+>~o`ur}hfg+pw_5`{=#9s1;Y6hdSz6o<toA&m^;)&Xg17%_dpfJR4KVFhE`I7i*v > > > > zIF|9&pir^kdf~!%>HI&UzbfxOI{EM-*9pQ&6I;C(&Q2hB73xz`x^>5r+glgDL~^9r > > > > z@plrI1lpAzQ=qrIXn0AVFK&#{ZZ0Doj22gN+w^+d@%JIVVU~wBY(`=}?8E`PQ`{yC > > > > zH}=FRoOQ}LS9A(F@A(=}=qhjO^X4DxGZbe61xYmHchTD6A>j?SoBHaq$dp~$ad>rs > > > > z4Fl<J;unGC8sJbkJwzt~lyzW$3q`_3vrztgyezMPdkNjNL@@Ph$jD{=4iB&WxrGA{ > > > > z{mcF4`Ti8$#?~ZiTfYuo%o&5z_p24jvu(TdDZ#bPu+wZGl^Ls{Ux3o$f}g|+gSunY > > > > zg(=VnnCcaRIoM>fV%g$?zV0t?Ichw0)YvtnH{Z<fqn)D~>mOB+lt@J!m<4V_Hi`L9 > > > > z-G{b64IoLusS`(UeTQ7+a{R3ww~KAQ63^hQ4R-8LHIc8s1X_qpp~pp=1dg-nvPtPN > > > > zr~cS*gtfo;C$RwM@~w`F9K{6#^KVnvF$nANK4Jtz_T8Nzaf8C^XB3~${aBYA^>qy8 > > > > zjFS12;z;usP9NJ%=L`1;diUo)oQ4ZL=Kq>_fv3i=jaX?rd`~bJPHrhK22#$LN2TOC > > > > z4R=nIo3yytcxma%izp{kWz2k3?uN>tr!q1IkvFm9M^4^)K4rtgLDxwh2r9xITy9h< > > > > z5lnSG8Cl`6mF;%x2>yM!96JdPYHjjF^)vuNQ1zr<FUkCzj_F|vZGhN*5u7s~JRa02 > > > > zjk@#)S#!P><=+zCR9gFI<;7W_<Qjc{o_-LJoRoTLOP^H!>rS7<3)WAZ#j@s%D}TPQ > > > > zEJb&>n;?|jW`Zvr!wkrsy(TNU$8Suqk(OgIN+)CyCue@SX1SWq;rhk&-5QF}JqX$4 > > > > z%hG$T=Hnm+x%npDV_RQ=SNMjYm6np?46Ybi?>JIB&907IeM+{Mn}195P1^J3->crO > > > > zvX|$5F3nxMa;S7^-`ALHYS$gPLD_ujCKowt71!{WikHkemE+;Ho7Xliep<sLeG~05 > > > > zEAONUjO5lB%x+uiThmvM)}RlztV;s?*Yhc-Dk(a_drV8)Z3aP<7ka^gcPH-6?~dHl > > > > zRd?ET2w-1*Nv{S4_4Qx8fBceU_#V{rjS=(G>8G~M@ne<E)NIlcN3Kt99KY-NOPj=h > > > > zzmDx1O6vL={)hWTW6!>}4>XarMZL|aq1@hX<#ocdLjQDOb>h%H#;uY4g}*2Cns#!7 > > > > z<8>jEIrJxER$MMS%J^ola2qN-CcTgmRJEktGpEAdioa~6B}{fz8G@9zTo8>;e=Ju| > > > > zrbkSSJyC`$&e6DKZqoVUNy?4rje~t)JffCXU~g2B@>JHlSP|a$(}TOQn?CUkG>-D5 > > > > zCsmo}@3^RPu>?kGd*pZ^<?0mX-Yb>*%gGqx-+Uq>KY<G~5*Uy+)u1g8S?Dy_yckTi > > > > zR;K+ddnB1UdDouP`~6vJz<P*-#AJs`WMSj>FT9m}@{_<t>n1HTF~2erR2sQ6!AV2e > > > > zpR<U#z2d3yqqH9lMHXWwrxWu#yokfEHWo&D<6Dhpo3&(~vCs+C!SVUDixNAdVY`p@ > > > > zSsuN}81*tX1AXj;;mH!oI{=>0mCe@-rGp)roo^4w^D@Gft_}Inp=g6qXJ$IRj$0Sx > > > > zE(oi((o=}iN!jfL$dsD3_|?pV%7w8Wq<!-QIhQ0;?=O)S4oe?$-IR@z`)}jQ|1<rN > > > > z5Z1xuxJjr}VCz_)8K5}S@91>>p|84RNVtRqdG0!h8Lg22&szUq|NntEE8z|+OQ1p5 > > > > zzudZ6FOXVqDNA^_D(3{E!@~5)y7;`aG8(>7@6N}s`9bo(#4k!zi1u9^o}Syfm-)i5 > > > > zz(X8IFj+J0w6l}^!*MMplM%m`H*xWFEP<TT@I7|d2&>E0xdx__S-@Rr=QF88hc)U3 > > > > zv6=K|9P8O;BI-BMXz5k|h(kCS7kzrpDu~4!NN&+i7b!^k#}Z5-P?S|`n>z~JuB`&P > > > > z;WrmOLsN@bXR^fXKfkg#=jrapU`o5p$iC0FUfCH83zZk+Dw%Ub%s6q8ylEa*fecOp > > > > zRd&HX1PE4tf3_`<W0qlb&3n|nhrHYW%^ezknR1`vK8mpfY0)F=@AJ&LF?e=(U<`p; > > > > z8S!DrS>YVni`aJm>RP4S{G2+S)8w)oReJbE)G@Xe@=k6i*`=?M`k94SLPqW-;=231 > > > > z9$9dppC<Q5#kB^zTWX_WA}*`_$qF@*dCHy1?lG+Gs1g?l;|Kl#M@SMZ8u7}E@2uqF > > > > z@=1KM2&I;3SIIVh58Iur^VecLfo7PKd@06ycFRveG2Ai3IukF)t(BEJyX{TWV`L(P > > > > z6jMW)TntQD*S_VtX>upFc4K58vHF}niZS4vTNYKAIyi{8GCRv{T8Q12?U_`f(OhvG > > > > zb(g>7G;>K4;C`p#qCZ^zrtHnrzWT2xhy(|*n=Rpfv$WQ}s{1RMBiR@JVxF;U-tJT? > > > > zhE%QrD@_4$!%oKtfPoiwOqmvVj<4#qK{cn$MkQla>|b15tGQbjmJ=hR-LdyqjI73^ > > > > zh)?pA>J(mMzz-}^-8~6}>1(<VyzSIS%Pzs&5>;y4CBJ*AoQ=Js&xp8{qJD3RQ9ffV > > > > z28NpZ8)xK~2-Xwkn>ut8_Kno=`}UigPSZx0sYSiNcucsa>N3L|@6uR=^R{oxj%#Vv > > > > zaHBr1D{rIaG+XUdQ4gHbRQdHV;YFT*-t3gI>hm0#tHEv)whe`TIo8MC>TD+6fu=53 > > > > z2TJ2?8zpzMw^s++X<~YHKeJ9EoTcPUcSM&hu`0fGa&Qdo88MvE3>QVax#g9`n$1Y= > > > > zoyDRgqe8U-gJ&NgT#UU16unIEU;36KUQ|5}6k;oG%Ht$|1sP_w;*b7Z7tZHls^x3o > > > > zGp5Ev62kdo;9$c2JTNj$$&*IsRjGCaiBX#i{D&&R`E=aaNF^_o2ezJ5CsOe3WimVU > > > > z0Xy>e9G3Lc);^%0BZ#*Wi;_Ed+}CF_R=#2$e)wDv8~c_liIkP3Bu?9lKAuk&BzIm& > > > > zc@$lgD{?SJ_@nBTI_rkbBWE^Lca0JM-64asA>zCa-2nwy6s;(7B1JbQFt(%qvRO-2 > > > > z#@N*7s!NwFpz&);5|}ZCm50pv#I5}`*3iAOT%*WmdBCOwP7)H|Lz&`2zxKp=inR(i > > > > z*eke-1+M*@BtX>rU-WlS1aW(=O;N!jHG~8oXIEUbIG!ZxRc5S&8<$G7luQx{Z3r}1 > > > > z2agHu=vKbk(to6#bLncSXh-(OG&ve!z^1H6*R!F}eJ4K&Q9=Z>ymRivvovII($qB; > > > > zzk^U}v(P(u$2mWNZ<y0NAKgD5Ep)(kbG!Lu&wgILlq=36hq^$jShinuz}-A>y#&Nd > > > > zUs4f<CcZi#*Z<Hob!fuM$OI6Ive@4b;Tc~z0;lpPd!)GUU4Ic4(Fjck@cbHOW_!(! > > > > z(UNO4WL|nWqz4~06MW=c)pfY<AIONicI1Wy8Fo_!+V-~Y-JGnf%Gmca$H*m|vA88U > > > > zx!%}(tmCVy-*x+Uz`u0P9D}I1UaD|aeSgwLQe{Ml&hL+8o`rmw{_NtV&;4-LptmWK > > > > zECH(95C<ek(;ugJwlCE+tEhnsRiZdsvrp6c5+08#^$vl|s+5{7Lu8WNFIhLP#$W6X > > > > zT#{H-7|XVu>ot9e5aJ=vdtGycg&<aWUjvC7r+jH34ZI{aElO=H#Pk{6H_S$XO)2Rf > > > > zn~0xzKbThtCAuwEIskmM#OCCI2e5VsZD&oSgoxg4&_X{nGItgHz~lPu&%?%(zGa%| > > > > zgsIB;tY5)s+l~tp#)sRV2EEsd_^;r{5riMYS%hVryGVk>RHW_S#Nda<%CoXY{w1d- > > > > zE@f{Ph;z&4H|8-H13a(Rlz+hq0z8hX@>aBbU!JC1*}HkDL?z@{yQ;X*v0u~Ig?gqp > > > > zgS}LBb&aC{b^_nSQqlvH`L+n&+tWNqQn}xuh<|w@jGMwW_D;1=$gFf>dU=SEDo4nS > > > > zuiT}JN@If}erqVTdriX>yvrMZs$qg1#_zXpimCV!Niz*!+^++h1R>7egv^tO;bb!| > > > > z>^{K(c4^z63p;G|Y>$=CF%tO8wjYFGvvH`2%NI}64Mvw!I~6P<Ri%s&1KlkfM}{~J > > > > zs=PMX^5DzJPr~1#m|yD2QT?X(Yqv;19`4UYusD{dgnQol2ljgteo4MOupGB<^=@BN > > > > zk2XB{KqQoWF81ad_OAE7>dj64#@b_^e;x<sa;u(%1UWZBx>UGb55){5Lf>nlWA;Cr > > > > z5FMU329QWog`aK_mH%ylU(_5plziX*9Y7J05!+lISp3HK^@->KXGR9+<_-6W-}|A2 > > > > z`$~2|OiQ$O6nIiabmB#mw{ITGamz=12PD>-d%0k}ApH|mcC)3ga-E-M3oK~x^-O)K > > > > zM}nWm<-u=Jo~nw7+%rD$DqXvEjmAGF=MQ{2T<TcyIE&x1Qy;eEs)$x>$Z?+!cxh4& > > > > z%yQ3O9*Fr&L*gWluG=^O0sK@5Ceor4L6lYz(V3+*s}3nt1ug@RaaWP0qMBKPmYs&F > > > > z7dBqgR6>}tbvkAA`_-%V*&SfM#>h8|W<&mLTgfo!aEwNl9_ca}TnU)3rQn;O^U4PE > > > > ze)%UJ)^)RwPv)}9ZAAc}Tv&EneaD%!4-O9|?ov@lfBPgf{VFj0_$-v@A=ro@3zM$# > > > > zp}MF&f0*!FfLCCtu`$7Ncz2`q=-Tve{xH*ma+{&PL;!*X0B7@6nU5^;RWs(1)?HKj > > > > z{^dpx=qSb{9<Pfpky6PPau!d9#mC^N#zaSF8HQU|O=gCW6KS_O08LzrTeaKjQm@-< > > > > ziAbtSr_05KTO4HcBXx7)u<^Y79v*g{`Iv>bplO*lEiJ;qLdoMNcDg#`&MT}x)Pe;l > > > > zofm-YMqQ(HcHB|IOiSjFg6EVO;cuY&A`ynRxU~a~wJ`u}xAelC9Pe{yHM(PbVx~V6 > > > > z5jh<cn-jt`0F)r8XR|&oTa&g+y{U|jF{X9YOq%1JzkkJ@DrS{Zt$E;LHBpxTXL?0c > > > > z>5Vb-5>W~Y0LUtlWB&m=S{b%)nE_qtq{MY$-S}qExI9{<d(iJ%$H%yWS%KQe`cwQ0 > > > > zLUwZd=Vt->_fF>Yiuti2*0D_KE=8xr>#$F5Z#it?ACF$+nXp8z**u-fKn8SuI)e|k > > > > zh$F3&xB3YC>9@Q#V4_*C2qmaH7Zb_loD$sv(u89RhC_9nr_GN1k(L?Yp1S)EDaiUv > > > > z{{VW|H$c~)n7~9GRVT9B$h>5J@W&Vvdu+H5XO6a$Xk3oZFgl%%7#qKQuqb;gk(?dO > > > > zAA}Cb0Gq=a#P2(0cm3%LHWp#Ifv*U5??wTh+Wiw-!Qcd0W(%q>N?EPeVJA-H1{p?n > > > > zJ#PGz;(;$}09JungDN%LH9zkj2QB2qm=O`IR1AV1`air!6ww>J@<X!ep*f+F#FFrU > > > > ze7s!?GoGm0Tky$TO{2cVITj40{S0p{vH#|K6(Omf+eRJv)0Ykq?e`Fks%NPFugAq; > > > > z9cj`8kF3sRErbOw8>4cmOAUvDg`EBf%h+{S1?EX?E=Cg_k65=8`XyYge-Xa!(H&X` > > > > zeYU({?Q<@x664!Kxa`36smBPO)^;y3UdMO0_##5S^VUBjfwj#|ytA|$d2KERM;S1# > > > > z-Ywdk!+VYohg&PUcP$*$=W3vcS8HKt%BT{O>lkR=sMEUbomRb>=h3u!#SIbXv_BTF > > > > z&&AhBahCXAEsfTNay4_jgipj1#x{YGtP~>}FBl8w^A=faA1R%=8e0()r0qxzmi&EQ > > > > z;+!%_=IxoFf;b(O#T%-KWi}nGu;p>=2gMm}X^&WwKRazt3n~sl20FROt!(^0JovMR > > > > z*sjY;VI)E6F?~X0>{{%g6kY_xmQMuwn4k+p>QmNa)n*)chr&^wmok-6M~seG`}-@k > > > > zmpc6<zbftUx}C>)?5V>ylxKY6)z0o)Z&71h9LEFU1#F0`#0@#_TlaTV^)DgBeK9+n > > > > z(lb$|#Es|r#~%m1rK@bHxR^A@W3RdM;Z;Mew(~0mp$z4zm=A3njYlPE5yXk~@NU(I > > > > z)BeXBfwX}iHqX5u8y8bEnjBe?OENmj;LO|j8t<x*@-|^~jf=0RimzltoK@Rpn{aXF > > > > z#2MMe8;|Bc#C!-YDbeCFO#Pc!1q95WM-fGIzt#5IxR>T6-4+FM{%wyM&)9?4YBxGS > > > > zdEmlJqZ9r2QV4~3w`Y{6l0xXw8L*9aKjBZFpe;7aytaU<2zn<w3USfZhTJ?~75KBV > > > > z%0@S=>wlKvN5!?*#%WXR6*eZeqoIY%v@8#o?z&)|tY-oU=g4`7Wy{HoeTo*`XsJ!a > > > > z%@y(BmHvHF|8($6{>FO<w3`jjrYEnY4(yeyOC~rV{3XH+P$VqIb7PDcXM7&G<4u1a > > > > zl-biTf9~?p4Va&6q7c7l4ZD;xd^;WZTS!Mag%xy_LjHAMq0tW43o?p5bAoII?GDOa > > > > z->FSl<{KVw*Wi^Z59{ghnJ>0o8k$jOYnXJ{gCyIYEn!J<$ejOyK5iZF*z|Pi_V@pd > > > > zyiUr0&q;9pfklFYrEj4h*yjI<=Uc2NHsL?{Pm+j#D3yQckpD*V9~}J;lK*1*wmzZI > > > > zf05jFvae|!V<=DDz7cD<ku*9*-`Ln2yLFoDNX?{k-d))b9P*-8?Es&&-wK9*jh1(~ > > > > zubwhB&^00#A5UU&9UlYIxyf|fZLt76Bwb@m@5G4?{z^mi=S^;+;q_vdKi3iuu@GlN > > > > zEL`m0Ae`yMWqB$vN0vd*=oEo@M-4vKOX(Q(hTVP&XN`o}s5!|cNV}uu$=3Kvx}~3d > > > > zmnEMoCkNd3CBC7K+!P(Wf-SNDGUm#L=jh#X8g$bo<*?z`#U{m9d-`vP^sFGPRyi}+ > > > > zLY*+HdEk-RBeV2G-f@s+60UW^ne6~+kibH>$q6Ii5*4im2?mq<QtDbG`&1_lr7jG% > > > > zx&X1(au)+!!JKow@ybihCWqp)*_gS)3nS#U>+S{?OCL6mxoR$Ry2b5X+h?6d{0Y-% > > > > zQIsxg=f+O!{yv$@>08->&|MLiD3+4K5C<iKp?vy1wKr>;OMnxMW_WN79vFYFr+4ks > > > > z88N~k-q6-(OJig$?ESB_hVSGz@=$&99{!yl0%A@^n2Z#6`-QMz&eqbwu9c;h20y(^ > > > > zY&hT)MBx-feZN<<0oz|27A`(z1#pLGKJ|f4X!)21y3w?AfZG6CnLc;t&kyX_-lW7; > > > > zurCq)Y^)9fcUdZT8EU16BAl)k6sb3jo+h%&z;2@q4PH+dh<NIb>o+`yK>9&WQnU?w > > > > z&6zt1M#Px8Ew9)P@GfvecFNPnsa-?f_!#m0u6OitO2l5#O?2<(=(VuNAikkd*!N0o > > > > zQ2#<p;k;6%?hjS&tjFtpUaAJ%qfGtQ>|n}HJXD#Nt0Ak{r{tBJR#kb#I(q*(q0mM- > > > > zH}813qdIJ@ZlHwY`wpzf1u*F5doBCD)dg)v@s`Ir(`(>Vnv%I>_o^~<Pj-@cPMT`| > > > > z@KfT#{SB70CH+?#t$-(6HJn}_FIV{(hm)SAxOzw1Z`^qUm%8>Y#09(?{XB8}lSRtD > > > > zD@{ibZ%5&}%$%^g>0*8i6Zpx%s7sG$rOa!%)2ZtRLokHz;27a9y6|~jx_!ZU<B%Oh > > > > zvQ_u1BQ)R7pi53d>rZMzwW0QbMCOU@Q)%<q<Sl0gd_#88yZYbj_mqd}qI0$gVTtz` > > > > zv2b8aESTGvAV59YrRW4!c$t5kyl&O+SGAc@_R&}AD(U2$e+yV<LkB!n3b+1hHOI!i > > > > z^^nA`FAvNitUN~COm)3(F_oe7+x^VSPG{eq+vdATOS`YuZ_&8B2j~)$_bQOWJW*DV > > > > zn6|Y=n9;kSoHswH2gMe0OfH{E1avQ{ja+*1c_+|}1yKHsVZj2%<mr<lXq>ufFZ_yo > > > > z3bdwtw!#65^Bj0+!`Iq;6&Sls_<(ft?&y8)tYFR*Gh@wT+mBU6Qj3D7;$lupW;^`N > > > > z1;Fml0);<fGvCmTHtoRVI1f3YDpMQ3h3qzaqSIv)Gaf1<!!H8zV&6y5S0vxvt@|Np > > > > zW$aGmD`sr-IPm3X-W58rg56OMK>B?ry)jfzfv2sI2Y0Ff)6`Xrc09SW!)B`nMrV-N > > > > zAT=5dG0Zu+X(58)LRFSF$1nbJp8^IE6`Xf`jb`rf8SwKqX^F{i_TM|gNDia_kfuP5 > > > > zz!hLNqq>cA<F8MERYJukY1Y0MgFZXuKJncN#v&P{8Rag}(_A5@dhueM)ZbTUaR1!P > > > > z*PwC><@gMRBpnIBiD0gWJ9ujpzKiBPZkEFjQX3I4Sw6x@*ck$jzP!k?`8yU6AX<)# > > > > zHJbE6IaNhgy1!C9J}@LVShns$79#5v1B5QS>omIh)Wd^Ik}Cyj57;+4S~G2ColJ#a > > > > z|57kW1+y)=H@dsV)`?F{Kr#gURnX0&{<TG9`(~K>x~%62_YgJpBMY|4rcpVkzR2FD > > > > zb*I_f;T|1+pB?vDGgU#*o-j0ymqa#(T1zCQKBQ{0v;@=<k&Fy)0r$Vx8>R&zM`Akl > > > > zp!!1$(FBglN9R)LZznUVg_pUP4O%i@=Ho@CiI<tSeKYzIr^;sxuS%WSy5FHk&gys{ > > > > z23{G@>vr2G3nCa)m5hL6m+S*20B2guSygKT{<Sqtp&9CQW$qrqH{PinyKIJV&94<! > > > > z7SPklC-~YToJ-;<`=`fO!Ws-)`8-%PQT(Z3NWh(LDVIb=_6f-+yRZ^fsq?P9MD5L# > > > > zmM{JEJw5<jRM^sI0m4KYyrJ*|yQhWzKK4L~mQ*`FrY6e78#;%|Xj=;(2bra~@M-9? > > > > zrRqa?`I_)&6Fw5!bJ;;Vm9QKLg>^e9j=RpnnSy`71ImM}SsN`siWm=@*&U_XHPc^b > > > > zS!v1)%*t*=0rAQoMSgylxL;GQt}Y8ZnaxMqcSORsh=lya7Qa{C!@}gs?p(^X`Mmi? > > > > zEHjZg`Elga#R~G`_~1P1z7bCyzeqFvt96TkZZC@Q=4@lASgcoqJP1dU$*9~#u3E!x > > > > zU>iVSXt19zUQD|4EMR{<cJU$96Db63e(=dC6R!8s%?MZU?<mi&(+3CD_N68TG<fBL > > > > zm2=$1FH%8ktHPdx_Xgu>`cp~K9RTdJGJ!zPfp_c=UAuh+iefiypYm68v9~-pHJq{7 > > > > zLg?^PM5B$`gzGw^$o{&=YL5pp4K+)iYEL+nu~k$&Tk@ahx%)?u6T!r^aH*V3Y7Hb+ > > > > zrdI*^x6-4E9g(SoFdnhiOw_UEoN56uC_@-Y#NoupY4_Mz*E8jCXQX!6R`2`|-h9ek > > > > z3BT))3kJ>WYk6oQyxnhA+u!C-*n+Un9DH-%6xv9m^%-t<bRIbm>82U~ZM^vzSQz5i > > > > ze>OjIrhSq{M+B1vc#4<r63Yw*S8+{Ww<ILLB)z8e3gr4cJXQqmnc}v@K1^&b&Hk%E > > > > zTg>B-W^8@odvaDEE>f_Op(fG4IV|YQYd9l|eYbkFvbpISJM*&hXHxeb_mf1p(_Efe > > > > z>fxrBHf;}|#-#D8`$pg*i;!9Q*pKxRG(8dp&<OG~oVngAQ<&wcOXESfb7f~Vwl0sZ > > > > ziTfkbx!?$VrN^8aT_BYo2Y*ySjl-qA#hV}_fsjBASyZVH`S<b5{QkU^C4VnV7AE^t > > > > zouF%JT+~XH_R`z;Wt?z1aCJ}2TrrqUWWdJwD&Th>FVSpDQq$yY%KiRstFgVKmeRlo > > > > z&G)=Vg?Dj;;u#D@A2n@wrgm2@0j&nk<+ut^v50OLj%yBlqHd?uU0P=wL1@4Ad)7}D > > > > z?cHm5TiuyptKO4)f!m*8B+zRI2(K|mxl6v0)BF1acHU-hQeuE|5HfTqx!8`c<8)+b > > > > z*3(jYXdJk|Z!3Y^fs+RBC-1Ttx#7oWg9ZiDi&;q97b|ejWQ-V%NA`OzmHij@Ar!lu > > > > z_w>=x9Q*4q_gh<D03dWuj6WxBJ#aNJCFT`~J5I^-$}qt+5t@AYeMqlaqUVWGA(k+% > > > > z$*yG?0l8Rt_LQosg;lCHqW^*FlPcpF3m<qFS~>!3b^P!d^Q|7L&sJ^z{X>RL%X~X^ > > > > z%@;5<Ga>77#dAk&Nw8B-g#-;_2iw)^Gemc~?#7kQD|}4A9>6OwMC}&{!}Cvbog+(D > > > > zOgqWDE3u**ip(c>foSgk`c0Hv$^6P8k66GiT?XsB#cQA=e1j8Qa?miOb@NE<y)#UH > > > > z`}AgePC~vFQ?y{-_ywzTS$N+B0FaCg`#nLAjlD6qk2lu$M;-U>`19`~jyz<$i>E;x > > > > z*P|REM!DW9VabrROJ?b|bJc=#RigSaAa*3VmS3fq7j7O!HDJ^v7QYcRwEe@6WSycr > > > > zc<nG%wVFYN{T=q^y4_N^D2aRPcnJciQG)6&09FeHRi1t;6vhr&vE=*ZY+*u~)o^u~ > > > > z!BYzR#zQFw_KSeO77IDqN^s$>(fWL;fuQx0p1eiEhXiSu7S{^+&j;A{5?TNBOHJ!8 > > > > zVcWpb59X5MPU26FTx#8aD%BsfSz>>sat{?9)H-A;l%zuS^K`ysZ1)eB$gNM{|CrFx > > > > Z7*dM{yQhj}4sy3din1y)<x=lM{ueeblRN+b > > > > > > > > literal 0 > > > > HcmV?d00001 > > > > > > > > -- > > > > 1.8.3.2 > > > > > > > > > > > > _______________________________________________ > > > > lng-odp mailing list > > > > lng-odp@lists.linaro.org > > > > http://lists.linaro.org/mailman/listinfo/lng-odp > > > > > > -- > > > Anders Roxell > > > anders.roxell@linaro.org > > > M: +46 709 71 42 85 | IRC: roxell > > > > > -- > Anders Roxell > anders.roxell@linaro.org > M: +46 709 71 42 85 | IRC: roxell >
diff --git a/crypto_design.dox b/crypto_design.dox new file mode 100644 index 0000000..a46a2db --- /dev/null +++ b/crypto_design.dox @@ -0,0 +1,545 @@ +/* Copyright (c) 2043, Linaro Limited + * All rights reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** +@page crypto_design ODP Design - Crypto API +For the implimentation of the ODP crypto API please see @ref odp_crypto.h + +@tableofcontents + +@section revision_history Revision History +Revision | Issue Data | Description | Author +---------|------------|-------------|-------- +0.1 | 4/9/2014 | Introduction started, Basic Functions | Bill, Alexandru +0.2 | 4/15/2014 | Completed intro, added TOC, started use cases, miscellaneous formatting, API comments | Bill +0.3 | 4/22/2014 | Added Use Case section to include results of design discussions held during ODP team calls | Bill +0.4 | 4/30/2014 | Design review from ODP crypto sprint--action to resolve | Bill +0.5 | 5/5/2014 | Rewrite incorporating review comments--ready for final review | Bill +1.0 | 5/30/2014 | Final version for LNG-SC approval | Bill + +@section introduction Introduction +This document describes the ODP Crypto API. Cryptography is an important part of data plane processing as many communication protocols make use of cryptographic functions. +Moreover, many SoCs incorporate cryptographic hardware that can significantly accelerate these operations compared to their software equivalents as well as provide validated hardware functional correctness and security boundaries necessary for system-level security certifications such as FIPS-140 Level 2 and above. +@section requirements Requirements +@subsection use_of_terms Use of Terms +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119). +@subsection uses_of_cryptography Uses of Cryptography +Crypto functions cover a range of uses and capabilities designed to support data security, integrity, authentication, and non-repudiation. +@subsubsection data_security Data Security +Cryptography supports data security by making use of complex mathematical transformations that are not feasibly reversible without possession of the secret key used to encrypt message data. +@subsubsection data_integrity Data Integrity +Cryptography supports data integrity through the use of cryptographic checksums (also known as secure hashes) that ensure the recipient that message data has not been altered either accidentally or maliciously while in transit. +@subsubsection data_authentication Data Authentication +Cryptography supports data authentication through the uses of Message Authentication Codes (MACs) that enable the recipient to verify that a message was sent from an authorized counterparty, and hence was not forged. +@subsubsection data_non_repudiation Data Non-Repudiation +Cryptography supports data non-repudiation through the use of digital signatures that enable a recipient or third party to verify the identity of the sending party and prevents the sending party from later denying that they originated a signed message. +@subsection scope Scope +ODP crypto support is designed to provide a portable framework for accessing SoC-specific cryptographic functions of most use to the data plane. This is predominantly symmetric crypto operations used to support the encryption and decryption of data at line rate using hardware acceleration and offload. Specifically excluded in this support are public key operations and other crypto functions mainly used in the control plane. +@subsection cryptographic_operations_in_the_data_plane Cryptographic Operations in the Data Plane +ODP crypto APIs cover the following areas: +@subsubsection ciphering Ciphering +Ciphering refers to mathematical transformations that use a secret key to encipher data, transforming the original data (referred to as plaintext) into ciphertext, thereby making it unintelligible to anyone not in possession of the key. Similarly, ciphering is also used to decipher data, allowing someone in possession of the correct key to transform received ciphertext back into plaintext. Approved block ciphers are listed [here](http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html) and SHOULD be supported by each ODP implementation. +@subsubsection hasing Hashing +A hash is a cryptographic digest of a message that can be used to represent it for comparison or integrity checking. Hash functions are designed so that any alteration of a message will alter the hash and that it is computationally infeasible to craft a message that generates the same hash value as another message. Secure hash functions approved for cryptographic use are listed by NIST [here](http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html) and SHOULD be supported by each ODP implementation. +@subsubsection zeroization Zeroization +To preserve the security of data, certain transient data held in data buffers MUST be cleared to zeros upon buffer free. +Such capability is referred to as zeroization. +ODP supports zeroization as a buffer pool attribute. +@subsubsection random_number_generation Random Number Generation +Because cryptography relies heavily on “unguessable” keys of various sorts, random number generation (RNG) is an integral part of cryptographic processing. +Random numbers are used in key generation, initialization vectors (IVs), various types of padding bytes, and various other uses collectively referred to as nonces, that serve to “harden” cryptographic processing. + +There are two types of random number support of interest. +Hardware random data, also known as entropy, that is the result of inherently random physical processes, and deterministic random bit generation (DRBG) that is used in certain certified cryptographic operations. +Approved DRBG algorithms are listed in [NIST SP 800-90A](http://en.wikipedia.org/wiki/NIST_SP_800-90A) and ODP does not specify which algorithms are available on a given implementation. +As such ODP implementations MAY use any approved DRGB algorithm but SHOULD support at least one of them. +Additionally, ODP implementations MUST NOT represent non-approved algorithms as DRBG implementations. +Validated algorithms are listed in the [NIST DRBG Validation List](http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgval.html). + +@subsubsection capability_inquiry Capability Inquiry +To enable applications to adapt to the implementation models offered across different SoC platforms, ODP provides APIs to allow applications to inquire about underlying crypto capabilities. +A given ODP implementation may offer crypto as hardware features, software features, or not available on a given platform. +@subsection cryptographic_algorithms Cryptographic Algorithms and Protocols +A cryptographic algorithm is a mathematical transform that provides one of the cryptographic operations described above. +They in turn are used as building blocks in creating cryptographic protocols. +These are complete sets of rules for how to exchange data securely using cryptography. +Both cryptographic algorithm and protocol design are highly specialized disciplines that involve high levels of public scrutiny and validation. +As a result, applications simply make use of approved cryptographic algorithms and protocols. +@subsection cryptographic_operations Cryptographic Operations +Cryptographic operations may be initiated by software or directly by hardware as part of the RX or TX packet path processing. +For ODP software-initiated cryptographic operations are the primary use case. +ODP provides APIs for performing data ciphering, hashing, random number generation, and capability inquiry. +@subsection performance_expectations Performance Expectations +In the data plane, the total processing budget for a packet may only be a few hundred cycles, so function invocation overhead MUST be kept to a minimum. +This has several implications. + +-# When work is dispatched to a thread, all information needed by the thread to process the work request SHOULD be immediately at hand. +Ideally any context or variables needed for the operation have been pre-warmed in the cache to avoid the latency hits associated with cache misses. +SoCs having hardware schedulers generally do this pre-staging of data to minimize such latencies, and ODP implementations are expected to exploit such platform capabilities whenever possible.\n\n + +-# Calls to ODP functions SHOULD NOT involve excessive amounts of parameter passing and (depending on the implementation) SHOULD be inlined as much as possible to avoid call overhead. +One technique that has proven useful is to allow for parameters to be passed as an explicit thread-local static structure. +Such use of “templating” means that a single function can support a rich set of options but the caller can configure a template matched to specific use and only vary the one or two parameters that differ from call to call.\n\n + +-# Kernel traps or interrupts SHOULD NOT be part of any non-exception path function processing. +Kernel calls and such are acceptable only during one-time initialization logic or certain types of unusual error recovery operations. +Often the best way to handle the latter is to pass the work to a dedicated recovery thread (or back to the control plane) rather than attempting to handle the condition inline. +For example, a link-down condition will trigger various recovery actions that might best be handled in this manner. + +@subsection use_by_existing_code Use by Existing Code +Most applications wishing to make use of ODP represent substantial existing investment that must be preserved. +Insofar as possible, ODP functions need to be orthogonal to existing application environments and structures to permit easy intermixing with pre-existing code. +@subsection data_references Data References +Packet data is inherently of variable length however it is often more efficient to organize memory into fixed-sized buffers that can be chained together on demand to contain packets. +The application SHOULD normally not need to be aware of such lower-level segmentation and should be able to treat a packet as a single object. +Alternately, especially when dealing with existing code, data segmentation MUST be explicitly specifiable via scatter/gather lists. +For example, data encryption or decryption may be invoked on a list of data segments as part of a single function call. +@subsection chained_operations Chained Operations +Crypto operations such as hashing and encryption, or decryption and verification, are very commonly used in combination. +For ODP, it is sufficient to support one cipher and one hash/authentication operation in a single call and this combination MUST be supported to avoid the call and dispatch overhead of separate invocations. + +@subsection key_management Key Management and Session Data +Keying is an area of particular sensitivity in crypto processing since keys are highly confidential and may be subject to legal requirements for safeguarding within special hardware enclosures. + +A session is the security context used to represent an active set of crypto operations that need to be applied to a flow on a packet-by-packet basis. Generally a session is established upon detection of a flow requiring crypto processing and retained for the life of that flow. It has been noted that this can involve cooperative processing between the control and data planes so several requirements stem from this: + +-# Session creation MAY need to be handled in an asynchronous manner. This is to allow these to be created in batches by thread(s) that specialize in this activity.\n\n + +-# Sessions MAY need to reference keying material indirectly via key handling modules.\n\n + +-# Session creation MAY be performed by non-ODP code and communicated to data plane routines that make use of ODP crypto functions that need to reference the session information. + +ODP session APIs and data structures SHOULD be represented by abstract data types that encapsulate implementation details for both platform efficiency and to accommodate these needs. +Use Cases +For ODP the major use cases of interest involve cryptographic algorithm acceleration. Cryptographic protocol acceleration is reserved for future ODP releases. +Buffers and Data Blocks +Cryptographic operations may be performed directly on data contained in ODP packet buffers, or it may be performed on “raw” data blocks operating entirely under application control. +Note that when using raw data blocks not managed by ODP, the application must perform any needed zeroization using either its own or ODP-supplied buffer zeroization functions. +ODP automatic support for zeroization is limited to ODP-managed buffers. +ODP buffers allocated from buffer pools designated for crypto use will also have whatever alignment and/or addressability attributes needed by the implementation to support crypto API calls. + +Note: Some implementations may have difficulty dealing with application buffer addresses, as these may be virtual addresses that are mapped discontiguously into physical memory. +For such implementations, memory SHOULD be allocated contiguously and MAY need to be “registered” to have proper addressability for crypto operations. +This area of the design will be updated based on experience in dealing with different crypto implementations that have such requirements. +Synchronization +ODP operations fall into one of three categories: + +-# Inline (Synchronous): Upon return from a call the operation is complete. +Operation is thus completely synchronous to the caller. +Inline is the appropriate model when the invoked function takes relatively few cycles or when the caller cannot feasibly progress without the results of the invoked function.\n\n + +-# Parallel: Upon return from a call the operation has been initiated, but is expected to complete shortly. +The caller continues to execute until it needs the result at which point it waits to complete the parallel operation. +The effect is as if the operation were inline except that the caller was able to execute in parallel with the operation for some application-determined period of time. +Parallel is the appropriate model when the operation being performed is relatively short (a few dozen up to perhaps 100 or 200 cycles) and the caller can usefully accomplish other processing on the same unit of work while the parallel operation is in progress, but not enough to justify the overhead of a formal queued work dispatch.\n\n + +-# Offloaded (Asynchronous): Upon return from the call the operation has been queued for execution. +A completion event will be queued back to the scheduler when the event is completed. +Offload is the appropriate model when the invoked function will take a substantial amount of cycles (thousands to tens of thousands) allowing the invoking thread/core to service other work until the operation completes. +For offloaded work, completion is indicated by a completion event being posted back to an application-designated completion queue. +Upon receipt the unit of work that initiated the offloaded operation continues processing with the results of the call. + +The synchronization models of interest are summarized in Figure 1: + +![Figure 1: Synchronization Models](./images/syncmodels.png) + +Note: Because few implementations are expected to offer the Parallel mode of operation as described above, this mode is reserved for potential future use. +For ODP only synchronous and asynchronous crypto operations are defined. +@section functional_definition Functional Definition +@subsection abstract_data_types Abstract data types +The following enumerations define various algorithms used for ciphering and hashing. +These are the basic operations applied to input data. + +A particular ODP implementation should map these values to the actual information to be passed to the crypto engine. +As such, the actual values of these enums is implementation-defined. + +Cipher algorithm encoding specifies the algorithm and cipher mode employed (as per security relevant RFCs - [4305](http://tools.ietf.org/html/rfc4305), [4868](http://tools.ietf.org/html/rfc4868), [4494](http://tools.ietf.org/html/rfc4494)). + +@code +enum odp_cipher_alg { + ODP_CIPHER_ALG_NULL, + ODP_CIPHER_ALG_DES, + ODP_CIPHER_ALG_3DES_CBC, + ODP_CIPHER_ALG_AES_CBC, + ODP_CIPHER_ALG_AES_GCM, + ODP_CIPHER_ALG_AES_CTR, + ODP_CIPHER_ALG_KASUMI, + ODP_CIPHER_ALG_SNOW, + ... +}; +@endcode + +Authorization algorithm encoding specifies the algorithm and the length of the authorization used (as per security relevant RFCs - [4305](http://tools.ietf.org/html/rfc4305), [4868](http://tools.ietf.org/html/rfc4868), [4494](http://tools.ietf.org/html/rfc4494)): + +@code +enum odp_auth_alg { + ODP_AUTH_ALG_NULL, + ODP_AUTH_MD5_96, + ODP_AUTH_ALG_SHA1_96, + ODP_AUTH_ALG_SHA1_160 + ODP_AUTH_ALG_SHA2_256_128, + ODP_AUTH_ALG_SHA2_384_192, + ODP_AUTH_ALG_SHA2_512_256, + ODP_AUTH_ALG_AES_CMAC_96, + ODP_AUTH_ALG_AES_XCBC_MAC_96, + ODP_AUTH_ALG_SNOW, + ODP_AUTH_ALG_KASUMI, + ... +}; + +typedef union odp_crypto_alg_t { + enum odp_cipher_alg cipher; + enum odp_auth_alg auth; +}odp_crypto_alg_t; +@endcode +@subsection parameter_structures Parameter Structures +@subsubsection crypto_sessions Crypto Sessions +The following structure describes a crypto session. +All packets / raw data buffers processed in a session share the data that defines the session. +A crypto session is defined by: + +- Operation type : encode or decode\n\n + +- Algorithms specifications, keys and , if required, initialization vectors. +When initialization vectors are not provided and they should be provided automatically by the crypto engine.\n\n + +- The operation mode: synchronous or asynchronous. +Synchronous operation blocks the caller until an operation status and result are available. +In synchronous mode there is at most only one outstanding crypto operation in the calling thread. +In asynchronous mode, the caller starts the crypto operation and later it may receive the status and the result together with a request context. +The operation status and result may also be received by a different thread.\n\n + +- Operation mode parameters: For asynchronous operation a completion event containing the status, the result and the request context is enqueued to a completion queue. +In case the queue is under the scheduler control, the scheduler determines who will receive the completion event and when. +When the completion queue is not scheduled, the thread which is supposed to get the operation output has to explicitly poll the completion queue. + +Note that this is an abstract data type and its structure is implementation-specific. +The layout shown here is for illustrative purposes and the actual layout will vary from one implementation to the next to most closely align with the structures needed by the underlying SoC platform. +Applications set and reference fields in the session structure via accessor functions that hide the actual layout. + +@code +typedef enum odp_crypto_op_t { + ODP_CRYPTO_OP_ENCODE, + ODP_CRYPTO_OP_DECODE +}odp_crypto_op_t; + +typedef struct odp_key_t { +}odp_key_t; + +typedef struct odp_crypto_session_t { + odp_crypto_op_t op; + struct { + enum odp_cipher_alg cipher_alg; + odp_key_t *key; + uint8_t *iv; + size_t iv_len; + } cipher; + + struct { + enum odp_auth_alg auth_alg; + enum odp_auth_len auth_len; + odp_key_t *key; + } auth; + + enum odp_crypto_op_mode { + ODP_CRYPTO_SYNC, + ODP_CRYPTO_ASYNC, + } op_mode; + + struct { + uint32_t timeout; + struct { + odp_queue_t completion_queue; + } async; + } op_mode_params; + + odp_session_proc_info_t session_proc_info; +} odp_crxsypto_session_t; +@endcode + +The completion queue contained in the session structure is an in/out parameter. +If provided, then the queue specified is associated with the session and is used to ensure order preservation on that session. +If not provided, one is created and returned to the caller. +Note that this completion queue is used to order operations performed on this crypto session. +It should not be confused with the completion queue specified on the odp_crypto_session_create() call (see below) that is used to control whether that call is itself processed in a synchronous vs. asynchronous manner. + +The following structure comprises processing information. +This is logically divided in two parts: + +- Processing input info - When crypto engine provides support for protocol processing, this information is provided in a higher level common protocol terminology form and a particular implementation should be able to derive everything it needs from this definition. +In addition, for crypto engines able to automate tasks like memory allocation for the output a buffer pool id may be specified.\n\n + +- Processing output information - statistics about processed bytes/packets. +These are useful when a session expiration is based on traffic volume. +These statistics may be updated by the software or by the hardware crypto engine. + +Again, this is an abstract type whose specific layout will vary based on implementation considerations. +Access to fields contained in the structure is only via accessor functions. + +@code +typedef struct { + uint64_t pkts_processed; + uint64_t bytes_processed; + uint64_t pkts_errored; + uint64_t bytes_errored; + + odp_buffer_pool_t out_pool; + +} odp_session_proc_info_t; +@endcode + +This enumeration defines which operations are applied and the order. + +@code +enum odp_crypto_combination { + ODP_CRYPTO_CIPHER_ONLY, + ODP_CRYPTO_AUTH_ONLY, + ODP_CRYPTO_AUTH_CIPHERTEXT +}; +@endcode + +This structure defines a contiguous segment in the input data which starts at offset offset and is len bytes long. + +@code +struct odp_data_range { + unsigned offset:16; + unsigned len:16; +}; +@endcode + +@subsection api_functions API Functions + +@subsubfunction Session Creation + +This function is used to create a crypto session. +The required parameters are: + +- Operation : encode/decode +- Processing info : cipher/auth/both +- Preferred mode : sync or async. +- Algorithms suites, keys and optional IV + +Session creation can be synchronous or asynchronous. +Completion event argument is used to return the status and the session handle. +When completion queue is not provided (synchronous call), the completion event is available upon function call return. +When completion queue is provided (asynchronous call), the completion event is placed on the completion queue. + +@code +typedef uint64_t odp_crypto_session_t; + +struct odp_session_params { + enum odp_crypto_operation op; + odp_session_proc_info_t proc_info; + enum odp_crypto_op_mode pref_mode; + enum odp_cipher_alg cipher_alg; + odp_key_t *cipher_key; + uint8_t *iv; + size_t iv_len; + enum odp_auth_alg auth_alg; + odp_key_t *auth_key; +}; + +enum odp_crypto_ses_create_err { + ODP_CRYPTO_SES_CREATE_NONE, + ODP_CRYPTO_SES_CREATE_ENOMEM, + /* Session creation error codes */ +}; + +void +odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, enum odp_crypto_ses_create_err *status); + +void +odp_crypto_get_ses_create_compl_handle(odp_buffer_t completion_event, odp_crypto_session_t *handle); + +int odp_crypto_session_create( + struct odp_session_params *params, + odp_buffer_t completion_event, + odp_queue_t completion_queue); +@endcode +@subsection crypto_operation Crypto Operation + +Crypto operations are described by a parameter structure: +@code +struct odp_crypto_op_params { + odp_crypto_session_t session; + odp_packet_t pkt; + odp_packet_t out_pkt; + uint8_t *override_iv_ptr; + unsigned hash_result_offset; + struct odp_data_range cipher_range; + struct odp_data_range auth_range; +}; +@endcode + +<table> +<tr><th>Parameter</th><th>Meaning</th></tr> +<tr><td>session</td><td>Session to perform the operation</td></tr> +<tr><td>pkt</td><td>Packet / buffer to be processed</td></tr> +<tr><td>out_pkt</td><td>Handle of an output packet / buffer to be returned as the result of the operation. +There are three different ways this parameter is used, depending on the mode of operation requested by the caller and the capabilities of the underlying implementation:\n\n + +-# If out_pkt is the same as pkt this indicates that the operation should be performed in place.\n\n +-# If out_pkt is different from pkt this indicates that output should be placed in the buffer supplied by the caller.\n\n +-# If out_pkt is omitted (a null/invalid value supplied on input) this indicates that an output buffer should be allocated by the operation and returned as part of the completion event associated with the operation.\n\n + +Note that not every implementation will support all of these modes and MAY require that one mode be used in preference to others. +Any such implementation restrictions are communicated as output from session creation.</td></tr> +<tr><td>override_iv_ptr</td><td>Optional IV to use for this request</td></tr> +<tr><td>hash_result_offset</td><td>Offset into the output packet where the hash result should be stored.</td></tr> +<tr><td>cipher_range</td><td>The byte range (offset:length) of the data to be processed for ciphering.</td></tr> +<tr><td>auth_range</td><td>The byte range (offset:length) of the data to be processed for authentication.</td></tr> +</table> + +The crypto operation is initiated with a single call that passes the parameters for the operation and an event (for asynchronous completion). +@code +int odp_crypto_operation( + struct odp_crypto_op_params *params, + odp_buffer_t completion_event); +@endcode + +Parameter | Meaning +----------|-------- +params | The parameter structure describing the crypto operation to be performed. +completion_event | The event delivered on completion. +It provides information about the status of the operation, result and request context. +In synchronous mode the event is available upon function call return. +In asynchronous mode, the event is placed on the session / operation completion queue when the operation finished. + +Upon return the return code indicates whether the operation was synchronous or asynchronous, or if an error occurred that prevented the operation from being performed. + +Get session operation : +@code +odp_crypto_op_t odp_crypto_session_get_op(odp_crypto_session_t ses); +@endcode + +Get session cipher information : +@code +odp_cipher_alg odp_cipher_session_get_cipher_alg(odp_crypto_session_t ses); +@endcode + +Get session authentication information : +@code +odp_auth_alg odp_crypto_session_get_auth_alg(odp_crypto_session_t ses); +@endcode + +Change session IV : +@code +int odp_crypto_session_iv_set(odp_crypto_session_t ses, uint8_t *iv); +@emdcode + +Change cipher or/and hash keys: +@code +int odp_crypto_session_key_set(odp_crypto_session_t ses, odp_key_t *key); +@endcode + +Destroy crypto session. +All pending operations are cancelled. +@code +int odp_crypto_session_destroy(odp_crypto_session_t ses); +@endcode + +Get completion event information - algorithm error, output and context. +Note that implementations MAY define their own specific error codes that have meaning in that context. +For application portability it is sufficient to know whether an operation completed successfully or experienced an error of some sort. +@code +enum crypto_alg_err { + ODP_CRYPTO_ALG_ERR_NONE, + ODP_CRYPTO_ALG_ERR_MODE, + ODP_CRYPTO_ALG_ERR_DATA_SIZE, + ODP_CRYPTO_ALG_ERR_KEY_SIZE, + ODP_CRYPTO_ALG_ERR_ICV_CHECK, + ODP_CRYPTO_ALG_ERR_AAD_SIZE, +}; + +enum crypto_hw_err { + ODP_CRYPTO_HW_ERR_NONE, + ODP_CRYPTO_HW_ERR_DMA, + ODP_CRYPTO_HW_ERR_BP_DEPLETED, +}; + +struct odp_crypto_compl_status { + odp_crypto_alg_t alg; + enum crypto_alg_err alg_err; + enum crypto_hw_err hw_err; +}; + +void +odp_crypto_get_compl_status(odp_buffer_t completion_event, + struct odp_crypto_compl_status *auth, + struct odp_crypto_compl_status *cipher); +@endcode + +Returns the output packet handle associated with the completion event : +@code +odp_packet_t odp_crypto_get_out_pkt(odp_buffer_t completion_event); +@endcode + +Sets a context handle to be returned with the completion event : +@code +void odp_crypto_set_compl_ctx(odp_buffer_t completion_event, odp_compl_ctx_t *ctx); +@endcode + +Returns the context associated with the completion event : +@code +odp_compl_ctx_t odp_crypto_get_compl_ctx(odp_buffer_t completion_event); +@endcode + +This section describes the API/Interface being defined at a functional level in technical detail. +Sub-sections include header file names, where implementation files are expected to reside in the ODP git tree, as well as the name, parameters, abstract data types, functionality, return codes, and exception conditions of each function call defined by the API/Interface. +Appropriate diagrams, tables, etc. should be used to allow the programmer tasked with implementing the API/Interface to understand the function to be implemented as well as error conditions, corner cases, performance requirements, etc. needed to implement the described API/Interface in a functionally correct and efficient manner. + +@subsubsection random_number_functions Random Number Functions +As noted earlier, random number support consists of two functions: +@code +int odp_hw_random_get (uint8_t *buf, uint32_t *len, bool use_entropy); + +int odp_drgb_random_get (uint8_t *buf, uint32_t *len); +@endcode + +The difference is that the first provides access to hardware random number functions that return true random data. +This is typically used for seed values. +The second provides a deterministic random bit generator conforming to NIST standards and is used by various crypto protocols and algorithms. +The use_entropy parameter on odp_hw_random_get is used to disable any hardware pre-processing normally provided by the function and is mainly intended to be used for testing/validation purposes. + +@subsubsection buffer_pool_extensions Buffer Pool Extensions +To support zeroization a buffer may be allocated with an ODP_CLEAR_ON_FREE attribute that specifies that this buffer should be zeroized upon free. +Alternately, a new type (ODP_CLEAR_ON_FREE) is added to odp_buffer_pool_create() that specifies that all buffers allocated from this pool must be zeroized upon free. +Essentially, the buffer security attribute is set by default from the attributes of the buffer pool that it is allocated from. + +@subsubsection capability_inquiry Capability Inquiry +To enable applications to determine crypto capabilities. +@code +int odp_crypto_inquire (enum odp_cipher_alg, enum odp_auth_alg); +@endcode + +Inquires whether the specified crypto and auth algorithms are supported. +Responses include: +- ODP_HW_SYNC_SUPPORT +- ODP_HW_ASYNC_SUPPORT +- ODP_SW_SYNC_SUPPORT +- ODP_SW_ASYNC_SUPPORT +- ODP_NO_SUPPORT + +HW support means the combination is supported in hardware, SW support means the combination is supported in software by the implementation. +No support means the combination is not supported by the implementation. +The SYNC and ASYNC return options can help the application decide how to invoke these functions, or it can just check whether or not the response is ODP_NO_SUPPORT. + +@section implementation_considerations Implementation Considerations +One of the main purposes for the ODP crypto APIs is to provide portable access across different SoCs whose hardware crypto capabilities largely overlap but vary in terms of their implementation details. +As a result, implementations need not provide software fill-ins for specific cryptographic features that are not available as hardware features on that platform. +Presumably applications needing specific features will select platforms on which these features are present. +Therefore, while all APIs specified here MUST exist in each conforming ODP implementation, it is acceptable for these APIs to return ODP_RC_FEATURE_NOT_PRESENT in response to calls requesting crypto features not present on that platform. + +For example, the linux-generic ODP implementation may only implement the null cipher suite (ODP_CIPHER_ALG_NULL) and return a feature not present error code for any other cipher. +This indication will also be returned on that platform in response to odp_crypto_inquire calls for non-null cipher algorithms. + +@section verification Verification/Testing +This section describes the verification/test cases needed to ensure that the defined functionality is implemented correctly and performs adequately. +This should be at a level of detail such that the programmer tasked with writing test scripts/programs to verify the implementation(s) of the defined functions can be written to ensure that all relevant functional variants and error/exception cases are properly tested. + +This section needs to be completed before API testing begins. + +*/
Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> --- crypto_design.dox | 545 ++++++++++++++++++++++++++++++++++++++++++++++++++ images/syncmodels.png | Bin 0 -> 17179 bytes 2 files changed, 545 insertions(+) create mode 100644 crypto_design.dox create mode 100644 images/syncmodels.png \ No newline at end of file diff --git a/images/syncmodels.png b/images/syncmodels.png new file mode 100644 index 0000000000000000000000000000000000000000..44e4c551bd803b7dd4320875699828d7f20d2044 GIT binary patch literal 17179 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 Z7*dM{yQhj}4sy3din1y)<x=lM{ueeblRN+b literal 0 HcmV?d00001