diff mbox

[API-NEXT,PATCHv9,1/3] api: random: add explicit controls over random data

Message ID 1481555177-31503-1-git-send-email-bill.fischofer@linaro.org
State Accepted
Commit 2b36166d647c64aa545e6ecc23a1d464fcd2c3c0
Headers show

Commit Message

Bill Fischofer Dec. 12, 2016, 3:06 p.m. UTC
Rework the odp_random_data() API to replace the use_entropy with an
explicit odp_random_kind parameter that controls the type of random
desired. Two new APIs are also introduced:

- odp_random_max_kind() returns the maximum kind of random data available

- odp_random_test_data() permits applications to generate repeatable
  random sequences for testing purposes

Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

---
Changes in v9:
- Remove kind parameter and expand seed to uint64_t in odp_random_test_data()
- Clarify that seed variables must be thread-local

Changes in v8:
- Clarify random kind hierarchy more explicitly
- Rename odp_random_repeatable_data() to odp_random_test_data()

Changes in v7:
- Clarify hierarchy of random kinds
- Expand on intended use of odp_random_repeatable_data()

Changes in v6:
- Add odp_random_max_kind() API instead of adding this to the
  odp_crypto_capability() API.
- Rename odp_random_seeded_data() to odp_random_repeatable_data()
- Merge API defs, implementation, and validation to preserve bisectability

Changes in v5:
- Change return type from int to int32_t for random APIs

Changes in v4:
- Normalize random API signatures with other ODP APIs
- Add new odp_random_seeded_data() API for repeatable random data generation
- Add additional tests for new odp_random_seeded_data() API
- Break out crypto section of User Guide to its own sub-document
- Add User Guide docuemntation for ODP random data API.

Changes in v3:
- Address commments by Petri
- Rename ODP_RAND_NORMAL to ODP_RANDOM_BASIC to avoid confusion with the
mathematical term "normal"

 include/odp/api/spec/random.h                   | 72 +++++++++++++++++++++++--
 platform/linux-generic/odp_crypto.c             | 48 +++++++++++++++--
 test/common_plat/validation/api/random/random.c | 48 ++++++++++++++++-
 test/common_plat/validation/api/random/random.h |  2 +
 4 files changed, 160 insertions(+), 10 deletions(-)

-- 
2.7.4

Comments

Savolainen, Petri (Nokia - FI/Espoo) Dec. 19, 2016, 10:36 a.m. UTC | #1
Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>



> -----Original Message-----

> From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of Bill

> Fischofer

> Sent: Monday, December 12, 2016 5:06 PM

> To: lng-odp@lists.linaro.org

> Subject: [lng-odp] [API-NEXT PATCHv9 1/3] api: random: add explicit

> controls over random data

> 

> Rework the odp_random_data() API to replace the use_entropy with an

> explicit odp_random_kind parameter that controls the type of random

> desired. Two new APIs are also introduced:

> 

> - odp_random_max_kind() returns the maximum kind of random data available

> 

> - odp_random_test_data() permits applications to generate repeatable

>   random sequences for testing purposes

> 

> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

> ---

> Changes in v9:

> - Remove kind parameter and expand seed to uint64_t in

> odp_random_test_data()

> - Clarify that seed variables must be thread-local

> 

> Changes in v8:

> - Clarify random kind hierarchy more explicitly

> - Rename odp_random_repeatable_data() to odp_random_test_data()

> 

> Changes in v7:

> - Clarify hierarchy of random kinds

> - Expand on intended use of odp_random_repeatable_data()

> 

> Changes in v6:

> - Add odp_random_max_kind() API instead of adding this to the

>   odp_crypto_capability() API.

> - Rename odp_random_seeded_data() to odp_random_repeatable_data()

> - Merge API defs, implementation, and validation to preserve bisectability

> 

> Changes in v5:

> - Change return type from int to int32_t for random APIs

> 

> Changes in v4:

> - Normalize random API signatures with other ODP APIs

> - Add new odp_random_seeded_data() API for repeatable random data

> generation

> - Add additional tests for new odp_random_seeded_data() API

> - Break out crypto section of User Guide to its own sub-document

> - Add User Guide docuemntation for ODP random data API.

> 

> Changes in v3:

> - Address commments by Petri

> - Rename ODP_RAND_NORMAL to ODP_RANDOM_BASIC to avoid confusion with the

> mathematical term "normal"

> 

>  include/odp/api/spec/random.h                   | 72

> +++++++++++++++++++++++--

>  platform/linux-generic/odp_crypto.c             | 48 +++++++++++++++--

>  test/common_plat/validation/api/random/random.c | 48 ++++++++++++++++-

>  test/common_plat/validation/api/random/random.h |  2 +

>  4 files changed, 160 insertions(+), 10 deletions(-)

> 

> diff --git a/include/odp/api/spec/random.h b/include/odp/api/spec/random.h

> index 00fa15b..4765475 100644

> --- a/include/odp/api/spec/random.h

> +++ b/include/odp/api/spec/random.h

> @@ -24,18 +24,82 @@ extern "C" {

>   */

> 

>  /**

> + * Random kind selector

> + *

> + * The kind of random denotes the statistical quality of the random data

> + * returned. Basic random simply appears uniformly distributed,

> Cryptographic

> + * random is statistically random and suitable for use by cryptographic

> + * functions. True random is generated from a hardware entropy source

> rather

> + * than an algorithm and is thus completely unpredictable. These form a

> + * hierarchy where higher quality data is presumably more costly to

> generate

> + * than lower quality data.

> + */

> +typedef enum {

> +	/** Basic random, presumably pseudo-random generated by SW. This

> +	 *  is the lowest kind of random */

> +	ODP_RANDOM_BASIC,

> +	/** Cryptographic quality random */

> +	ODP_RANDOM_CRYPTO,

> +	/** True random, generated from a HW entropy source. This is the

> +	 *  highest kind of random */

> +	ODP_RANDOM_TRUE,

> +} odp_random_kind_t;

> +

> +/**

> + * Query random max kind

> + *

> + * Implementations support the returned max kind and all kinds weaker

> than it.

> + *

> + * @return kind The maximum odp_random_kind_t supported by this

> implementation

> + */

> +odp_random_kind_t odp_random_max_kind(void);

> +

> +/**

>   * Generate random byte data

>   *

> + * The intent in supporting different kinds of random data is to allow

> + * tradeoffs between performance and the quality of random data needed.

> The

> + * assumption is that basic random is cheap while true random is

> relatively

> + * expensive in terms of time to generate, with cryptographic random

> being

> + * something in between. Implementations that support highly efficient

> true

> + * random are free to use this for all requested kinds. So it is always

> + * permissible to "upgrade" a random data request, but never to

> "downgrade"

> + * such requests.

> + *

>   * @param[out]    buf   Output buffer

> - * @param         size  Size of output buffer

> - * @param use_entropy   Use entropy

> + * @param         len   Length of output buffer in bytes

> + * @param         kind  Specifies the type of random data required.

> Request

> + *                      is expected to fail if the implementation is

> unable to

> + *                      provide the requested type.

> + *

> + * @return Number of bytes written

> + * @retval <0 on failure

> + */

> +int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t

> kind);

> +

> +/**

> + * Generate repeatable random data for testing purposes

> + *

> + * For testing purposes it is often useful to generate "random" sequences

> that

> + * are repeatable. This is accomplished by supplying a seed value that is

> used

> + * for pseudo-random data generation. The caller-provided seed value is

> + * updated for each call to continue the sequence. Restarting a series of

> + * calls with the same initial seed value will generate the same sequence

> of

> + * random test data.

> + *

> + * This function returns data of ODP_RANDOM_BASIC quality and should be

> used

> + * only for testing purposes. Use odp_random_data() for production.

>   *

> - * @todo Define the implication of the use_entropy parameter

> + * @param[out]    buf  Output buffer

> + * @param         len  Length of output buffer in bytes

> + * @param[in,out] seed Seed value to use. This must be a thread-local

> + *                     variable. Results are undefined if multiple

> threads

> + *                     call this routine with the same seed variable.

>   *

>   * @return Number of bytes written

>   * @retval <0 on failure

>   */

> -int32_t odp_random_data(uint8_t *buf, int32_t size, odp_bool_t

> use_entropy);

> +int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed);

> 

>  /**

>   * @}

> diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-

> generic/odp_crypto.c

> index 7e686ff..c2d0c45 100644

> --- a/platform/linux-generic/odp_crypto.c

> +++ b/platform/linux-generic/odp_crypto.c

> @@ -4,6 +4,7 @@

>   * SPDX-License-Identifier:     BSD-3-Clause

>   */

> 

> +#include <odp_posix_extensions.h>

>  #include <odp/api/crypto.h>

>  #include <odp_internal.h>

>  #include <odp/api/atomic.h>

> @@ -19,6 +20,7 @@

>  #include <odp_packet_internal.h>

> 

>  #include <string.h>

> +#include <stdlib.h>

> 

>  #include <openssl/des.h>

>  #include <openssl/rand.h>

> @@ -877,12 +879,48 @@ int odp_crypto_term_global(void)

>  	return rc;

>  }

> 

> -int32_t

> -odp_random_data(uint8_t *buf, int32_t len, odp_bool_t use_entropy

> ODP_UNUSED)

> +odp_random_kind_t odp_random_max_kind(void)

>  {

> -	int32_t rc;

> -	rc = RAND_bytes(buf, len);

> -	return (1 == rc) ? len /*success*/: -1 /*failure*/;

> +	return ODP_RANDOM_CRYPTO;

> +}

> +

> +int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t

> kind)

> +{

> +	int rc;

> +

> +	switch (kind) {

> +	case ODP_RANDOM_BASIC:

> +		RAND_pseudo_bytes(buf, len);

> +		return len;

> +

> +	case ODP_RANDOM_CRYPTO:

> +		rc = RAND_bytes(buf, len);

> +		return (1 == rc) ? (int)len /*success*/: -1 /*failure*/;

> +

> +	case ODP_RANDOM_TRUE:

> +	default:

> +		return -1;

> +	}

> +}

> +

> +int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)

> +{

> +	union {

> +		uint32_t rand_word;

> +		uint8_t rand_byte[4];

> +	} u;

> +	uint32_t i = 0, j;

> +	uint32_t seed32 = (*seed) & 0xffffffff;

> +

> +	while (i < len) {

> +		u.rand_word = rand_r(&seed32);

> +

> +		for (j = 0; j < 4 && i < len; j++, i++)

> +			*buf++ = u.rand_byte[j];

> +	}

> +

> +	*seed = seed32;

> +	return len;

>  }

> 

>  odp_crypto_compl_t odp_crypto_compl_from_event(odp_event_t ev)

> diff --git a/test/common_plat/validation/api/random/random.c

> b/test/common_plat/validation/api/random/random.c

> index 7572366..a0e2ef7 100644

> --- a/test/common_plat/validation/api/random/random.c

> +++ b/test/common_plat/validation/api/random/random.c

> @@ -13,12 +13,58 @@ void random_test_get_size(void)

>  	int32_t ret;

>  	uint8_t buf[32];

> 

> -	ret = odp_random_data(buf, sizeof(buf), false);

> +	ret = odp_random_data(buf, sizeof(buf), ODP_RANDOM_BASIC);

>  	CU_ASSERT(ret == sizeof(buf));

>  }

> 

> +void random_test_kind(void)

> +{

> +	int32_t rc;

> +	uint8_t buf[4096];

> +	uint32_t buf_size = sizeof(buf);

> +	odp_random_kind_t max_kind = odp_random_max_kind();

> +

> +	rc = odp_random_data(buf, buf_size, max_kind);

> +	CU_ASSERT(rc > 0);

> +

> +	switch (max_kind) {

> +	case ODP_RANDOM_BASIC:

> +		rc = odp_random_data(buf, 4, ODP_RANDOM_CRYPTO);

> +		CU_ASSERT(rc < 0);

> +		/* Fall through */

> +

> +	case ODP_RANDOM_CRYPTO:

> +		rc = odp_random_data(buf, 4, ODP_RANDOM_TRUE);

> +		CU_ASSERT(rc < 0);

> +		break;

> +

> +	default:

> +		break;

> +	}

> +}

> +

> +void random_test_repeat(void)

> +{

> +	uint8_t buf1[1024];

> +	uint8_t buf2[1024];

> +	int32_t rc;

> +	uint64_t seed1 = 12345897;

> +	uint64_t seed2 = seed1;

> +

> +	rc = odp_random_test_data(buf1, sizeof(buf1), &seed1);

> +	CU_ASSERT(rc == sizeof(buf1));

> +

> +	rc = odp_random_test_data(buf2, sizeof(buf2), &seed2);

> +	CU_ASSERT(rc == sizeof(buf2));

> +

> +	CU_ASSERT(seed1 == seed2);

> +	CU_ASSERT(memcmp(buf1, buf2, sizeof(buf1)) == 0);

> +}

> +

>  odp_testinfo_t random_suite[] = {

>  	ODP_TEST_INFO(random_test_get_size),

> +	ODP_TEST_INFO(random_test_kind),

> +	ODP_TEST_INFO(random_test_repeat),

>  	ODP_TEST_INFO_NULL,

>  };

> 

> diff --git a/test/common_plat/validation/api/random/random.h

> b/test/common_plat/validation/api/random/random.h

> index 26202cc..c4bca78 100644

> --- a/test/common_plat/validation/api/random/random.h

> +++ b/test/common_plat/validation/api/random/random.h

> @@ -11,6 +11,8 @@

> 

>  /* test functions: */

>  void random_test_get_size(void);

> +void random_test_kind(void);

> +void random_test_repeat(void);

> 

>  /* test arrays: */

>  extern odp_testinfo_t random_suite[];

> --

> 2.7.4
Maxim Uvarov Dec. 19, 2016, 3:43 p.m. UTC | #2
Merged,
Maxim.

On 12/19/16 13:36, Savolainen, Petri (Nokia - FI/Espoo) wrote:
> Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>

> 

> 

>> -----Original Message-----

>> From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of Bill

>> Fischofer

>> Sent: Monday, December 12, 2016 5:06 PM

>> To: lng-odp@lists.linaro.org

>> Subject: [lng-odp] [API-NEXT PATCHv9 1/3] api: random: add explicit

>> controls over random data

>>

>> Rework the odp_random_data() API to replace the use_entropy with an

>> explicit odp_random_kind parameter that controls the type of random

>> desired. Two new APIs are also introduced:

>>

>> - odp_random_max_kind() returns the maximum kind of random data available

>>

>> - odp_random_test_data() permits applications to generate repeatable

>>   random sequences for testing purposes

>>

>> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>

>> ---

>> Changes in v9:

>> - Remove kind parameter and expand seed to uint64_t in

>> odp_random_test_data()

>> - Clarify that seed variables must be thread-local

>>

>> Changes in v8:

>> - Clarify random kind hierarchy more explicitly

>> - Rename odp_random_repeatable_data() to odp_random_test_data()

>>

>> Changes in v7:

>> - Clarify hierarchy of random kinds

>> - Expand on intended use of odp_random_repeatable_data()

>>

>> Changes in v6:

>> - Add odp_random_max_kind() API instead of adding this to the

>>   odp_crypto_capability() API.

>> - Rename odp_random_seeded_data() to odp_random_repeatable_data()

>> - Merge API defs, implementation, and validation to preserve bisectability

>>

>> Changes in v5:

>> - Change return type from int to int32_t for random APIs

>>

>> Changes in v4:

>> - Normalize random API signatures with other ODP APIs

>> - Add new odp_random_seeded_data() API for repeatable random data

>> generation

>> - Add additional tests for new odp_random_seeded_data() API

>> - Break out crypto section of User Guide to its own sub-document

>> - Add User Guide docuemntation for ODP random data API.

>>

>> Changes in v3:

>> - Address commments by Petri

>> - Rename ODP_RAND_NORMAL to ODP_RANDOM_BASIC to avoid confusion with the

>> mathematical term "normal"

>>

>>  include/odp/api/spec/random.h                   | 72

>> +++++++++++++++++++++++--

>>  platform/linux-generic/odp_crypto.c             | 48 +++++++++++++++--

>>  test/common_plat/validation/api/random/random.c | 48 ++++++++++++++++-

>>  test/common_plat/validation/api/random/random.h |  2 +

>>  4 files changed, 160 insertions(+), 10 deletions(-)

>>

>> diff --git a/include/odp/api/spec/random.h b/include/odp/api/spec/random.h

>> index 00fa15b..4765475 100644

>> --- a/include/odp/api/spec/random.h

>> +++ b/include/odp/api/spec/random.h

>> @@ -24,18 +24,82 @@ extern "C" {

>>   */

>>

>>  /**

>> + * Random kind selector

>> + *

>> + * The kind of random denotes the statistical quality of the random data

>> + * returned. Basic random simply appears uniformly distributed,

>> Cryptographic

>> + * random is statistically random and suitable for use by cryptographic

>> + * functions. True random is generated from a hardware entropy source

>> rather

>> + * than an algorithm and is thus completely unpredictable. These form a

>> + * hierarchy where higher quality data is presumably more costly to

>> generate

>> + * than lower quality data.

>> + */

>> +typedef enum {

>> +	/** Basic random, presumably pseudo-random generated by SW. This

>> +	 *  is the lowest kind of random */

>> +	ODP_RANDOM_BASIC,

>> +	/** Cryptographic quality random */

>> +	ODP_RANDOM_CRYPTO,

>> +	/** True random, generated from a HW entropy source. This is the

>> +	 *  highest kind of random */

>> +	ODP_RANDOM_TRUE,

>> +} odp_random_kind_t;

>> +

>> +/**

>> + * Query random max kind

>> + *

>> + * Implementations support the returned max kind and all kinds weaker

>> than it.

>> + *

>> + * @return kind The maximum odp_random_kind_t supported by this

>> implementation

>> + */

>> +odp_random_kind_t odp_random_max_kind(void);

>> +

>> +/**

>>   * Generate random byte data

>>   *

>> + * The intent in supporting different kinds of random data is to allow

>> + * tradeoffs between performance and the quality of random data needed.

>> The

>> + * assumption is that basic random is cheap while true random is

>> relatively

>> + * expensive in terms of time to generate, with cryptographic random

>> being

>> + * something in between. Implementations that support highly efficient

>> true

>> + * random are free to use this for all requested kinds. So it is always

>> + * permissible to "upgrade" a random data request, but never to

>> "downgrade"

>> + * such requests.

>> + *

>>   * @param[out]    buf   Output buffer

>> - * @param         size  Size of output buffer

>> - * @param use_entropy   Use entropy

>> + * @param         len   Length of output buffer in bytes

>> + * @param         kind  Specifies the type of random data required.

>> Request

>> + *                      is expected to fail if the implementation is

>> unable to

>> + *                      provide the requested type.

>> + *

>> + * @return Number of bytes written

>> + * @retval <0 on failure

>> + */

>> +int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t

>> kind);

>> +

>> +/**

>> + * Generate repeatable random data for testing purposes

>> + *

>> + * For testing purposes it is often useful to generate "random" sequences

>> that

>> + * are repeatable. This is accomplished by supplying a seed value that is

>> used

>> + * for pseudo-random data generation. The caller-provided seed value is

>> + * updated for each call to continue the sequence. Restarting a series of

>> + * calls with the same initial seed value will generate the same sequence

>> of

>> + * random test data.

>> + *

>> + * This function returns data of ODP_RANDOM_BASIC quality and should be

>> used

>> + * only for testing purposes. Use odp_random_data() for production.

>>   *

>> - * @todo Define the implication of the use_entropy parameter

>> + * @param[out]    buf  Output buffer

>> + * @param         len  Length of output buffer in bytes

>> + * @param[in,out] seed Seed value to use. This must be a thread-local

>> + *                     variable. Results are undefined if multiple

>> threads

>> + *                     call this routine with the same seed variable.

>>   *

>>   * @return Number of bytes written

>>   * @retval <0 on failure

>>   */

>> -int32_t odp_random_data(uint8_t *buf, int32_t size, odp_bool_t

>> use_entropy);

>> +int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed);

>>

>>  /**

>>   * @}

>> diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-

>> generic/odp_crypto.c

>> index 7e686ff..c2d0c45 100644

>> --- a/platform/linux-generic/odp_crypto.c

>> +++ b/platform/linux-generic/odp_crypto.c

>> @@ -4,6 +4,7 @@

>>   * SPDX-License-Identifier:     BSD-3-Clause

>>   */

>>

>> +#include <odp_posix_extensions.h>

>>  #include <odp/api/crypto.h>

>>  #include <odp_internal.h>

>>  #include <odp/api/atomic.h>

>> @@ -19,6 +20,7 @@

>>  #include <odp_packet_internal.h>

>>

>>  #include <string.h>

>> +#include <stdlib.h>

>>

>>  #include <openssl/des.h>

>>  #include <openssl/rand.h>

>> @@ -877,12 +879,48 @@ int odp_crypto_term_global(void)

>>  	return rc;

>>  }

>>

>> -int32_t

>> -odp_random_data(uint8_t *buf, int32_t len, odp_bool_t use_entropy

>> ODP_UNUSED)

>> +odp_random_kind_t odp_random_max_kind(void)

>>  {

>> -	int32_t rc;

>> -	rc = RAND_bytes(buf, len);

>> -	return (1 == rc) ? len /*success*/: -1 /*failure*/;

>> +	return ODP_RANDOM_CRYPTO;

>> +}

>> +

>> +int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t

>> kind)

>> +{

>> +	int rc;

>> +

>> +	switch (kind) {

>> +	case ODP_RANDOM_BASIC:

>> +		RAND_pseudo_bytes(buf, len);

>> +		return len;

>> +

>> +	case ODP_RANDOM_CRYPTO:

>> +		rc = RAND_bytes(buf, len);

>> +		return (1 == rc) ? (int)len /*success*/: -1 /*failure*/;

>> +

>> +	case ODP_RANDOM_TRUE:

>> +	default:

>> +		return -1;

>> +	}

>> +}

>> +

>> +int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)

>> +{

>> +	union {

>> +		uint32_t rand_word;

>> +		uint8_t rand_byte[4];

>> +	} u;

>> +	uint32_t i = 0, j;

>> +	uint32_t seed32 = (*seed) & 0xffffffff;

>> +

>> +	while (i < len) {

>> +		u.rand_word = rand_r(&seed32);

>> +

>> +		for (j = 0; j < 4 && i < len; j++, i++)

>> +			*buf++ = u.rand_byte[j];

>> +	}

>> +

>> +	*seed = seed32;

>> +	return len;

>>  }

>>

>>  odp_crypto_compl_t odp_crypto_compl_from_event(odp_event_t ev)

>> diff --git a/test/common_plat/validation/api/random/random.c

>> b/test/common_plat/validation/api/random/random.c

>> index 7572366..a0e2ef7 100644

>> --- a/test/common_plat/validation/api/random/random.c

>> +++ b/test/common_plat/validation/api/random/random.c

>> @@ -13,12 +13,58 @@ void random_test_get_size(void)

>>  	int32_t ret;

>>  	uint8_t buf[32];

>>

>> -	ret = odp_random_data(buf, sizeof(buf), false);

>> +	ret = odp_random_data(buf, sizeof(buf), ODP_RANDOM_BASIC);

>>  	CU_ASSERT(ret == sizeof(buf));

>>  }

>>

>> +void random_test_kind(void)

>> +{

>> +	int32_t rc;

>> +	uint8_t buf[4096];

>> +	uint32_t buf_size = sizeof(buf);

>> +	odp_random_kind_t max_kind = odp_random_max_kind();

>> +

>> +	rc = odp_random_data(buf, buf_size, max_kind);

>> +	CU_ASSERT(rc > 0);

>> +

>> +	switch (max_kind) {

>> +	case ODP_RANDOM_BASIC:

>> +		rc = odp_random_data(buf, 4, ODP_RANDOM_CRYPTO);

>> +		CU_ASSERT(rc < 0);

>> +		/* Fall through */

>> +

>> +	case ODP_RANDOM_CRYPTO:

>> +		rc = odp_random_data(buf, 4, ODP_RANDOM_TRUE);

>> +		CU_ASSERT(rc < 0);

>> +		break;

>> +

>> +	default:

>> +		break;

>> +	}

>> +}

>> +

>> +void random_test_repeat(void)

>> +{

>> +	uint8_t buf1[1024];

>> +	uint8_t buf2[1024];

>> +	int32_t rc;

>> +	uint64_t seed1 = 12345897;

>> +	uint64_t seed2 = seed1;

>> +

>> +	rc = odp_random_test_data(buf1, sizeof(buf1), &seed1);

>> +	CU_ASSERT(rc == sizeof(buf1));

>> +

>> +	rc = odp_random_test_data(buf2, sizeof(buf2), &seed2);

>> +	CU_ASSERT(rc == sizeof(buf2));

>> +

>> +	CU_ASSERT(seed1 == seed2);

>> +	CU_ASSERT(memcmp(buf1, buf2, sizeof(buf1)) == 0);

>> +}

>> +

>>  odp_testinfo_t random_suite[] = {

>>  	ODP_TEST_INFO(random_test_get_size),

>> +	ODP_TEST_INFO(random_test_kind),

>> +	ODP_TEST_INFO(random_test_repeat),

>>  	ODP_TEST_INFO_NULL,

>>  };

>>

>> diff --git a/test/common_plat/validation/api/random/random.h

>> b/test/common_plat/validation/api/random/random.h

>> index 26202cc..c4bca78 100644

>> --- a/test/common_plat/validation/api/random/random.h

>> +++ b/test/common_plat/validation/api/random/random.h

>> @@ -11,6 +11,8 @@

>>

>>  /* test functions: */

>>  void random_test_get_size(void);

>> +void random_test_kind(void);

>> +void random_test_repeat(void);

>>

>>  /* test arrays: */

>>  extern odp_testinfo_t random_suite[];

>> --

>> 2.7.4

>
diff mbox

Patch

diff --git a/include/odp/api/spec/random.h b/include/odp/api/spec/random.h
index 00fa15b..4765475 100644
--- a/include/odp/api/spec/random.h
+++ b/include/odp/api/spec/random.h
@@ -24,18 +24,82 @@  extern "C" {
  */
 
 /**
+ * Random kind selector
+ *
+ * The kind of random denotes the statistical quality of the random data
+ * returned. Basic random simply appears uniformly distributed, Cryptographic
+ * random is statistically random and suitable for use by cryptographic
+ * functions. True random is generated from a hardware entropy source rather
+ * than an algorithm and is thus completely unpredictable. These form a
+ * hierarchy where higher quality data is presumably more costly to generate
+ * than lower quality data.
+ */
+typedef enum {
+	/** Basic random, presumably pseudo-random generated by SW. This
+	 *  is the lowest kind of random */
+	ODP_RANDOM_BASIC,
+	/** Cryptographic quality random */
+	ODP_RANDOM_CRYPTO,
+	/** True random, generated from a HW entropy source. This is the
+	 *  highest kind of random */
+	ODP_RANDOM_TRUE,
+} odp_random_kind_t;
+
+/**
+ * Query random max kind
+ *
+ * Implementations support the returned max kind and all kinds weaker than it.
+ *
+ * @return kind The maximum odp_random_kind_t supported by this implementation
+ */
+odp_random_kind_t odp_random_max_kind(void);
+
+/**
  * Generate random byte data
  *
+ * The intent in supporting different kinds of random data is to allow
+ * tradeoffs between performance and the quality of random data needed. The
+ * assumption is that basic random is cheap while true random is relatively
+ * expensive in terms of time to generate, with cryptographic random being
+ * something in between. Implementations that support highly efficient true
+ * random are free to use this for all requested kinds. So it is always
+ * permissible to "upgrade" a random data request, but never to "downgrade"
+ * such requests.
+ *
  * @param[out]    buf   Output buffer
- * @param         size  Size of output buffer
- * @param use_entropy   Use entropy
+ * @param         len   Length of output buffer in bytes
+ * @param         kind  Specifies the type of random data required. Request
+ *                      is expected to fail if the implementation is unable to
+ *                      provide the requested type.
+ *
+ * @return Number of bytes written
+ * @retval <0 on failure
+ */
+int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind);
+
+/**
+ * Generate repeatable random data for testing purposes
+ *
+ * For testing purposes it is often useful to generate "random" sequences that
+ * are repeatable. This is accomplished by supplying a seed value that is used
+ * for pseudo-random data generation. The caller-provided seed value is
+ * updated for each call to continue the sequence. Restarting a series of
+ * calls with the same initial seed value will generate the same sequence of
+ * random test data.
+ *
+ * This function returns data of ODP_RANDOM_BASIC quality and should be used
+ * only for testing purposes. Use odp_random_data() for production.
  *
- * @todo Define the implication of the use_entropy parameter
+ * @param[out]    buf  Output buffer
+ * @param         len  Length of output buffer in bytes
+ * @param[in,out] seed Seed value to use. This must be a thread-local
+ *                     variable. Results are undefined if multiple threads
+ *                     call this routine with the same seed variable.
  *
  * @return Number of bytes written
  * @retval <0 on failure
  */
-int32_t odp_random_data(uint8_t *buf, int32_t size, odp_bool_t use_entropy);
+int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed);
 
 /**
  * @}
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index 7e686ff..c2d0c45 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -4,6 +4,7 @@ 
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
+#include <odp_posix_extensions.h>
 #include <odp/api/crypto.h>
 #include <odp_internal.h>
 #include <odp/api/atomic.h>
@@ -19,6 +20,7 @@ 
 #include <odp_packet_internal.h>
 
 #include <string.h>
+#include <stdlib.h>
 
 #include <openssl/des.h>
 #include <openssl/rand.h>
@@ -877,12 +879,48 @@  int odp_crypto_term_global(void)
 	return rc;
 }
 
-int32_t
-odp_random_data(uint8_t *buf, int32_t len, odp_bool_t use_entropy ODP_UNUSED)
+odp_random_kind_t odp_random_max_kind(void)
 {
-	int32_t rc;
-	rc = RAND_bytes(buf, len);
-	return (1 == rc) ? len /*success*/: -1 /*failure*/;
+	return ODP_RANDOM_CRYPTO;
+}
+
+int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
+{
+	int rc;
+
+	switch (kind) {
+	case ODP_RANDOM_BASIC:
+		RAND_pseudo_bytes(buf, len);
+		return len;
+
+	case ODP_RANDOM_CRYPTO:
+		rc = RAND_bytes(buf, len);
+		return (1 == rc) ? (int)len /*success*/: -1 /*failure*/;
+
+	case ODP_RANDOM_TRUE:
+	default:
+		return -1;
+	}
+}
+
+int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
+{
+	union {
+		uint32_t rand_word;
+		uint8_t rand_byte[4];
+	} u;
+	uint32_t i = 0, j;
+	uint32_t seed32 = (*seed) & 0xffffffff;
+
+	while (i < len) {
+		u.rand_word = rand_r(&seed32);
+
+		for (j = 0; j < 4 && i < len; j++, i++)
+			*buf++ = u.rand_byte[j];
+	}
+
+	*seed = seed32;
+	return len;
 }
 
 odp_crypto_compl_t odp_crypto_compl_from_event(odp_event_t ev)
diff --git a/test/common_plat/validation/api/random/random.c b/test/common_plat/validation/api/random/random.c
index 7572366..a0e2ef7 100644
--- a/test/common_plat/validation/api/random/random.c
+++ b/test/common_plat/validation/api/random/random.c
@@ -13,12 +13,58 @@  void random_test_get_size(void)
 	int32_t ret;
 	uint8_t buf[32];
 
-	ret = odp_random_data(buf, sizeof(buf), false);
+	ret = odp_random_data(buf, sizeof(buf), ODP_RANDOM_BASIC);
 	CU_ASSERT(ret == sizeof(buf));
 }
 
+void random_test_kind(void)
+{
+	int32_t rc;
+	uint8_t buf[4096];
+	uint32_t buf_size = sizeof(buf);
+	odp_random_kind_t max_kind = odp_random_max_kind();
+
+	rc = odp_random_data(buf, buf_size, max_kind);
+	CU_ASSERT(rc > 0);
+
+	switch (max_kind) {
+	case ODP_RANDOM_BASIC:
+		rc = odp_random_data(buf, 4, ODP_RANDOM_CRYPTO);
+		CU_ASSERT(rc < 0);
+		/* Fall through */
+
+	case ODP_RANDOM_CRYPTO:
+		rc = odp_random_data(buf, 4, ODP_RANDOM_TRUE);
+		CU_ASSERT(rc < 0);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void random_test_repeat(void)
+{
+	uint8_t buf1[1024];
+	uint8_t buf2[1024];
+	int32_t rc;
+	uint64_t seed1 = 12345897;
+	uint64_t seed2 = seed1;
+
+	rc = odp_random_test_data(buf1, sizeof(buf1), &seed1);
+	CU_ASSERT(rc == sizeof(buf1));
+
+	rc = odp_random_test_data(buf2, sizeof(buf2), &seed2);
+	CU_ASSERT(rc == sizeof(buf2));
+
+	CU_ASSERT(seed1 == seed2);
+	CU_ASSERT(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+}
+
 odp_testinfo_t random_suite[] = {
 	ODP_TEST_INFO(random_test_get_size),
+	ODP_TEST_INFO(random_test_kind),
+	ODP_TEST_INFO(random_test_repeat),
 	ODP_TEST_INFO_NULL,
 };
 
diff --git a/test/common_plat/validation/api/random/random.h b/test/common_plat/validation/api/random/random.h
index 26202cc..c4bca78 100644
--- a/test/common_plat/validation/api/random/random.h
+++ b/test/common_plat/validation/api/random/random.h
@@ -11,6 +11,8 @@ 
 
 /* test functions: */
 void random_test_get_size(void);
+void random_test_kind(void);
+void random_test_repeat(void);
 
 /* test arrays: */
 extern odp_testinfo_t random_suite[];