Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F40366669
random-drbg.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
79 KB
Subscribers
None
random-drbg.c
View Options
/* random-drbg.c - Deterministic Random Bits Generator
* Copyright 2014 Stephan Mueller <smueller@chronox.de>
*
* DRBG: Deterministic Random Bits Generator
* Based on NIST Recommended DRBG from NIST SP800-90A with the following
* properties:
* * CTR DRBG with DF with AES-128, AES-192, AES-256 cores
* * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores
* * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores
* * with and without prediction resistance
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, and the entire permission notice in its entirety,
* including the disclaimer of warranties.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
* LGPLv2+, in which case the provisions of the LGPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the LGPL and
* the restrictions contained in a BSD-style copyright.)
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
* WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*
* gcry_control GCRYCTL_DRBG_REINIT
* ================================
* This control request re-initializes the DRBG completely, i.e. the entire
* state of the DRBG is zeroized (with two exceptions listed in
* GCRYCTL_DRBG_SET_ENTROPY).
*
* The control request takes the following values which influences how
* the DRBG is re-initialized:
*
* - const char *flagstr
*
* This variable specifies the DRBG type to be used for the next
* initialization. If set to NULL, the previous DRBG type is
* used for the initialization. If not NULL a space separated
* list of tokens with associated flag values is expected which
* are ORed to form the mandatory flags of the requested DRBG
* strength and cipher type. Optionally, the prediction
* resistance flag can be ORed into the flags variable.
*
* | String token | Flag value |
* |--------------+------------------------|
* | aes | DRBG_CTRAES |
* | serpent | DRBG_CTRSERPENT |
* | twofish | DRBG_CTRTWOFISH |
* | sha1 | DRBG_HASHSHA1 |
* | sha256 | DRBG_HASHSHA256 |
* | sha512 | DRBG_HASHSHA512 |
* | hmac | DRBG_HMAC |
* | sym128 | DRBG_SYM128 |
* | sym192 | DRBG_SYM192 |
* | sym256 | DRBG_SYM256 |
* | pr | DRBG_PREDICTION_RESIST |
*
* For example:
*
* - CTR-DRBG with AES-128 without prediction resistance:
* "aes sym128"
* - HMAC-DRBG with SHA-512 with prediction resistance:
* "hmac sha512 pr"
*
* - gcry_buffer_t *pers
*
* NULL terminated array with personalization strings to be used
* for initialization.
*
* - int npers
*
* Size of PERS.
*
* - void *guard
*
* A value of NULL must be passed for this.
*
* The variable of flags is independent from the pers/perslen variables. If
* flags is set to 0 and perslen is set to 0, the current DRBG type is
* completely reset without using a personalization string.
*
* DRBG Usage
* ==========
* The SP 800-90A DRBG allows the user to specify a personalization string
* for initialization as well as an additional information string for each
* random number request. The following code fragments show how a caller
* uses the API to use the full functionality of the DRBG.
*
* Usage without any additional data
* ---------------------------------
* gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM);
*
*
* Usage with personalization string during initialization
* -------------------------------------------------------
* drbg_string_t pers;
* char personalization[11] = "some-string";
*
* drbg_string_fill(&pers, personalization, strlen(personalization));
* // The reset completely re-initializes the DRBG with the provided
* // personalization string without changing the DRBG type
* ret = gcry_control(GCRYCTL_DRBG_REINIT, 0, &pers);
* gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM);
*
*
* Usage with additional information string during random number request
* ---------------------------------------------------------------------
* drbg_string_t addtl;
* char addtl_string[11] = "some-string";
*
* drbg_string_fill(&addtl, addtl_string, strlen(addtl_string));
* // The following call is a wrapper to gcry_randomize() and returns
* // the same error codes.
* gcry_randomize_drbg(outbuf, OUTLEN, GCRY_STRONG_RANDOM, &addtl);
*
*
* Usage with personalization and additional information strings
* -------------------------------------------------------------
* Just mix both scenarios above.
*
*
* Switch the DRBG type to some other type
* ---------------------------------------
* // Switch to CTR DRBG AES-128 without prediction resistance
* ret = gcry_control(GCRYCTL_DRBG_REINIT, DRBG_NOPR_CTRAES128, NULL);
* gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM);
*/
#include
<string.h>
#include
<unistd.h>
#include
<stdint.h>
#include
<config.h>
#include
"g10lib.h"
#include
"random.h"
#include
"rand-internal.h"
#include
"../cipher/bufhelp.h"
/******************************************************************
* Constants
******************************************************************/
/*
* DRBG flags bitmasks
*
* 31 (B) 28 19 (A) 0
* +-+-+-+--------+---+-----------+-----+
* |~|~|u|~~~~~~~~| 3 | 2 | 1 |
* +-+-+-+--------+- -+-----------+-----+
* ctl flg| |drbg use selection flags
*
*/
/* Internal state control flags (B) */
#define DRBG_PREDICTION_RESIST ((u32)1<<28)
/* CTR type modifiers (A.1)*/
#define DRBG_CTRAES ((u32)1<<0)
#define DRBG_CTRSERPENT ((u32)1<<1)
#define DRBG_CTRTWOFISH ((u32)1<<2)
#define DRBG_CTR_MASK (DRBG_CTRAES | DRBG_CTRSERPENT \
| DRBG_CTRTWOFISH)
/* HASH type modifiers (A.2)*/
#define DRBG_HASHSHA1 ((u32)1<<4)
#define DRBG_HASHSHA224 ((u32)1<<5)
#define DRBG_HASHSHA256 ((u32)1<<6)
#define DRBG_HASHSHA384 ((u32)1<<7)
#define DRBG_HASHSHA512 ((u32)1<<8)
#define DRBG_HASH_MASK (DRBG_HASHSHA1 | DRBG_HASHSHA224 \
| DRBG_HASHSHA256 | DRBG_HASHSHA384 \
| DRBG_HASHSHA512)
/* type modifiers (A.3)*/
#define DRBG_HMAC ((u32)1<<12)
#define DRBG_SYM128 ((u32)1<<13)
#define DRBG_SYM192 ((u32)1<<14)
#define DRBG_SYM256 ((u32)1<<15)
#define DRBG_TYPE_MASK (DRBG_HMAC | DRBG_SYM128 | DRBG_SYM192 \
| DRBG_SYM256)
#define DRBG_CIPHER_MASK (DRBG_CTR_MASK | DRBG_HASH_MASK \
| DRBG_TYPE_MASK)
#define DRBG_PR_CTRAES128 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM128)
#define DRBG_PR_CTRAES192 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM192)
#define DRBG_PR_CTRAES256 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM256)
#define DRBG_NOPR_CTRAES128 (DRBG_CTRAES | DRBG_SYM128)
#define DRBG_NOPR_CTRAES192 (DRBG_CTRAES | DRBG_SYM192)
#define DRBG_NOPR_CTRAES256 (DRBG_CTRAES | DRBG_SYM256)
#define DRBG_PR_HASHSHA1 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1)
#define DRBG_PR_HASHSHA256 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256)
#define DRBG_PR_HASHSHA384 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384)
#define DRBG_PR_HASHSHA512 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512)
#define DRBG_NOPR_HASHSHA1 (DRBG_HASHSHA1)
#define DRBG_NOPR_HASHSHA256 (DRBG_HASHSHA256)
#define DRBG_NOPR_HASHSHA384 (DRBG_HASHSHA384)
#define DRBG_NOPR_HASHSHA512 (DRBG_HASHSHA512)
#define DRBG_PR_HMACSHA1 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1 \
| DRBG_HMAC)
#define DRBG_PR_HMACSHA256 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256 \
| DRBG_HMAC)
#define DRBG_PR_HMACSHA384 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384 \
| DRBG_HMAC)
#define DRBG_PR_HMACSHA512 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512 \
| DRBG_HMAC)
#define DRBG_NOPR_HMACSHA1 (DRBG_HASHSHA1 | DRBG_HMAC)
#define DRBG_NOPR_HMACSHA256 (DRBG_HASHSHA256 | DRBG_HMAC)
#define DRBG_NOPR_HMACSHA384 (DRBG_HASHSHA384 | DRBG_HMAC)
#define DRBG_NOPR_HMACSHA512 (DRBG_HASHSHA512 | DRBG_HMAC)
/* The default DRGB type. */
#define DRBG_DEFAULT_TYPE DRBG_NOPR_HMACSHA256
/******************************************************************
* Common data structures
******************************************************************/
/*
* SP800-90A requires the concatenation of different data. To avoid copying
* buffers around or allocate additional memory, the following data structure
* is used to point to the original memory with its size. In addition, it
* is used to build a linked list. The linked list defines the concatenation
* of individual buffers. The order of memory block referenced in that
* linked list determines the order of concatenation.
*/
struct
drbg_string_s
{
const
unsigned
char
*
buf
;
size_t
len
;
struct
drbg_string_s
*
next
;
};
typedef
struct
drbg_string_s
drbg_string_t
;
/* DRBG input data structure for DRBG generate with additional
* information string. */
struct
drbg_gen_s
{
unsigned
char
*
outbuf
;
/* output buffer for random numbers */
unsigned
int
outlen
;
/* size of output buffer */
drbg_string_t
*
addtl
;
/* input buffer for
* additional information string */
};
typedef
struct
drbg_gen_s
drbg_gen_t
;
/* Forward declaration of the state object pointer. */
struct
drbg_state_s
;
typedef
struct
drbg_state_s
*
drbg_state_t
;
struct
drbg_core_s
{
u32
flags
;
/* flags for the cipher */
ushort
statelen
;
/* maximum state length */
ushort
blocklen_bytes
;
/* block size of output in bytes */
int
backend_cipher
;
/* libgcrypt backend cipher */
};
struct
drbg_state_ops_s
{
gpg_err_code_t
(
*
update
)
(
drbg_state_t
drbg
,
drbg_string_t
*
seed
,
int
reseed
);
gpg_err_code_t
(
*
generate
)
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
,
drbg_string_t
*
addtl
);
gpg_err_code_t
(
*
crypto_init
)
(
drbg_state_t
drbg
);
void
(
*
crypto_fini
)
(
drbg_state_t
drbg
);
};
struct
drbg_test_data_s
{
drbg_string_t
*
testentropy
;
/* TEST PARAMETER: test entropy */
int
fail_seed_source
:
1
;
/* If set, the seed function will
* return an error. */
};
/* This state object keeps the state of an DRBG instance. */
struct
drbg_state_s
{
unsigned
char
*
V
;
/* internal state 10.1.1.1 1a) */
unsigned
char
*
C
;
/* hash: static value 10.1.1.1 1b)
* hmac / ctr: key */
size_t
reseed_ctr
;
/* Number of RNG requests since last reseed --
* 10.1.1.1 1c) */
unsigned
char
*
scratchpad
;
/* some memory the DRBG can use for its
* operation -- allocated during init */
void
*
priv_data
;
/* Cipher handle */
gcry_cipher_hd_t
ctr_handle
;
/* CTR mode cipher handle */
#define DRBG_CTR_NULL_LEN 128
unsigned
char
*
ctr_null
;
/* CTR mode zero buffer */
int
seeded
:
1
;
/* DRBG fully seeded? */
int
pr
:
1
;
/* Prediction resistance enabled? */
/* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the
* process which did the initialization so that we can detect a fork.
* The volatile modifier is required so that the compiler does not
* optimize it away in case the getpid function is badly attributed. */
pid_t
seed_init_pid
;
const
struct
drbg_state_ops_s
*
d_ops
;
const
struct
drbg_core_s
*
core
;
struct
drbg_test_data_s
*
test_data
;
};
enum
drbg_prefixes
{
DRBG_PREFIX0
=
0x00
,
DRBG_PREFIX1
,
DRBG_PREFIX2
,
DRBG_PREFIX3
};
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
/***************************************************************
* Global variables
***************************************************************/
/* Global state variable holding the current instance of the DRBG. */
static
drbg_state_t
drbg_state
;
/* This is the lock variable we use to serialize access to this RNG. */
GPGRT_LOCK_DEFINE
(
drbg_lock_var
);
/***************************************************************
* Backend cipher definitions available to DRBG
***************************************************************/
static
const
struct
drbg_core_s
drbg_cores
[]
=
{
/* Hash DRBGs */
{
DRBG_HASHSHA1
,
55
,
20
,
GCRY_MD_SHA1
},
{
DRBG_HASHSHA256
,
55
,
32
,
GCRY_MD_SHA256
},
{
DRBG_HASHSHA384
,
111
,
48
,
GCRY_MD_SHA384
},
{
DRBG_HASHSHA512
,
111
,
64
,
GCRY_MD_SHA512
},
/* HMAC DRBGs */
{
DRBG_HASHSHA1
|
DRBG_HMAC
,
20
,
20
,
GCRY_MD_SHA1
},
{
DRBG_HASHSHA256
|
DRBG_HMAC
,
32
,
32
,
GCRY_MD_SHA256
},
{
DRBG_HASHSHA384
|
DRBG_HMAC
,
48
,
48
,
GCRY_MD_SHA384
},
{
DRBG_HASHSHA512
|
DRBG_HMAC
,
64
,
64
,
GCRY_MD_SHA512
},
/* block ciphers */
{
DRBG_CTRAES
|
DRBG_SYM128
,
32
,
16
,
GCRY_CIPHER_AES128
},
{
DRBG_CTRAES
|
DRBG_SYM192
,
40
,
16
,
GCRY_CIPHER_AES192
},
{
DRBG_CTRAES
|
DRBG_SYM256
,
48
,
16
,
GCRY_CIPHER_AES256
}
};
static
gpg_err_code_t
drbg_hash_init
(
drbg_state_t
drbg
);
static
gpg_err_code_t
drbg_hmac_init
(
drbg_state_t
drbg
);
static
gpg_err_code_t
drbg_hmac_setkey
(
drbg_state_t
drbg
,
const
unsigned
char
*
key
);
static
void
drbg_hash_fini
(
drbg_state_t
drbg
);
static
byte
*
drbg_hash
(
drbg_state_t
drbg
,
const
drbg_string_t
*
buf
);
static
gpg_err_code_t
drbg_sym_init
(
drbg_state_t
drbg
);
static
void
drbg_sym_fini
(
drbg_state_t
drbg
);
static
gpg_err_code_t
drbg_sym_setkey
(
drbg_state_t
drbg
,
const
unsigned
char
*
key
);
static
gpg_err_code_t
drbg_sym
(
drbg_state_t
drbg
,
unsigned
char
*
outval
,
const
drbg_string_t
*
buf
);
static
gpg_err_code_t
drbg_sym_ctr
(
drbg_state_t
drbg
,
const
unsigned
char
*
inbuf
,
unsigned
int
inbuflen
,
unsigned
char
*
outbuf
,
unsigned
int
outbuflen
);
/******************************************************************
******************************************************************
******************************************************************
* Generic DRBG code
******************************************************************
******************************************************************
******************************************************************/
/******************************************************************
* Generic helper functions
******************************************************************/
#if 0
#define dbg(x) do { log_debug x; } while(0)
#else
#define dbg(x)
#endif
/*
* Parse a string of flags and store the flag values at R_FLAGS.
* Return 0 on success.
*/
static
gpg_err_code_t
parse_flag_string
(
const
char
*
string
,
u32
*
r_flags
)
{
struct
{
const
char
*
name
;
u32
flag
;
}
table
[]
=
{
{
"aes"
,
DRBG_CTRAES
},
{
"serpent"
,
DRBG_CTRSERPENT
},
{
"twofish"
,
DRBG_CTRTWOFISH
},
{
"sha1"
,
DRBG_HASHSHA1
},
{
"sha256"
,
DRBG_HASHSHA256
},
{
"sha512"
,
DRBG_HASHSHA512
},
{
"hmac"
,
DRBG_HMAC
},
{
"sym128"
,
DRBG_SYM128
},
{
"sym192"
,
DRBG_SYM192
},
{
"sym256"
,
DRBG_SYM256
},
{
"pr"
,
DRBG_PREDICTION_RESIST
}
};
*
r_flags
=
0
;
if
(
string
)
{
char
**
tl
;
const
char
*
s
;
int
i
,
j
;
tl
=
_gcry_strtokenize
(
string
,
NULL
);
if
(
!
tl
)
return
gpg_err_code_from_syserror
();
for
(
i
=
0
;
(
s
=
tl
[
i
]);
i
++
)
{
for
(
j
=
0
;
j
<
DIM
(
table
);
j
++
)
if
(
!
strcmp
(
s
,
table
[
j
].
name
))
{
*
r_flags
|=
table
[
j
].
flag
;
break
;
}
if
(
!
(
j
<
DIM
(
table
)))
{
xfree
(
tl
);
return
GPG_ERR_INV_FLAG
;
}
}
xfree
(
tl
);
}
return
0
;
}
static
inline
void
drbg_string_fill
(
drbg_string_t
*
string
,
const
unsigned
char
*
buf
,
size_t
len
)
{
string
->
buf
=
buf
;
string
->
len
=
len
;
string
->
next
=
NULL
;
}
static
inline
ushort
drbg_statelen
(
drbg_state_t
drbg
)
{
if
(
drbg
&&
drbg
->
core
)
return
drbg
->
core
->
statelen
;
return
0
;
}
static
inline
ushort
drbg_blocklen
(
drbg_state_t
drbg
)
{
if
(
drbg
&&
drbg
->
core
)
return
drbg
->
core
->
blocklen_bytes
;
return
0
;
}
static
inline
ushort
drbg_keylen
(
drbg_state_t
drbg
)
{
if
(
drbg
&&
drbg
->
core
)
return
(
drbg
->
core
->
statelen
-
drbg
->
core
->
blocklen_bytes
);
return
0
;
}
static
inline
size_t
drbg_max_request_bytes
(
void
)
{
/* SP800-90A requires the limit 2**19 bits, but we return bytes */
return
(
1
<<
16
);
}
static
inline
size_t
drbg_max_addtl
(
void
)
{
/* SP800-90A requires 2**35 bytes additional info str / pers str */
#ifdef __LP64__
return
(
1UL
<<
35
);
#else
/*
* SP800-90A allows smaller maximum numbers to be returned -- we
* return SIZE_MAX - 1 to allow the verification of the enforcement
* of this value in drbg_healthcheck_sanity.
*/
return
(
SIZE_MAX
-
1
);
#endif
}
static
inline
size_t
drbg_max_requests
(
void
)
{
/* SP800-90A requires 2**48 maximum requests before reseeding */
#ifdef __LP64__
return
(
1UL
<<
48
);
#else
return
SIZE_MAX
;
#endif
}
/*
* Return strength of DRBG according to SP800-90A section 8.4
*
* flags: DRBG flags reference
*
* Return: normalized strength value or 32 as a default to counter
* programming errors
*/
static
inline
unsigned
short
drbg_sec_strength
(
u32
flags
)
{
if
((
flags
&
DRBG_HASHSHA1
)
||
(
flags
&
DRBG_SYM128
))
return
16
;
else
if
(
flags
&
DRBG_SYM192
)
return
24
;
else
if
((
flags
&
DRBG_SYM256
)
||
(
flags
&
DRBG_HASHSHA256
)
||
(
flags
&
DRBG_HASHSHA384
)
||
(
flags
&
DRBG_HASHSHA512
))
return
32
;
else
return
32
;
}
static
void
drbg_add_buf
(
unsigned
char
*
dst
,
size_t
dstlen
,
unsigned
char
*
add
,
size_t
addlen
)
{
/* implied: dstlen > addlen */
unsigned
char
*
dstptr
,
*
addptr
;
unsigned
int
remainder
=
0
;
size_t
len
=
addlen
;
dstptr
=
dst
+
(
dstlen
-
1
);
addptr
=
add
+
(
addlen
-
1
);
while
(
len
)
{
remainder
+=
*
dstptr
+
*
addptr
;
*
dstptr
=
remainder
&
0xff
;
remainder
>>=
8
;
len
--
;
dstptr
--
;
addptr
--
;
}
len
=
dstlen
-
addlen
;
while
(
len
&&
remainder
>
0
)
{
remainder
=
*
dstptr
+
1
;
*
dstptr
=
remainder
&
0xff
;
remainder
>>=
8
;
len
--
;
dstptr
--
;
}
}
/* Helper variables for read_cb().
*
* The _gcry_rnd*_gather_random interface does not allow to provide a
* data pointer. Thus we need to use a global variable for
* communication. However, the then required locking is anyway a good
* idea because it does not make sense to have several readers of (say
* /dev/random). It is easier to serve them one after the other.
*/
static
unsigned
char
*
read_cb_buffer
;
/* The buffer. */
static
size_t
read_cb_size
;
/* Size of the buffer. */
static
size_t
read_cb_len
;
/* Used length. */
/* Callback for generating seed from kernel device. */
static
void
drbg_read_cb
(
const
void
*
buffer
,
size_t
length
,
enum
random_origins
origin
)
{
const
unsigned
char
*
p
=
buffer
;
(
void
)
origin
;
gcry_assert
(
read_cb_buffer
);
/* Note that we need to protect against gatherers returning more
* than the requested bytes (e.g. rndw32). */
while
(
length
--
&&
read_cb_len
<
read_cb_size
)
read_cb_buffer
[
read_cb_len
++
]
=
*
p
++
;
}
static
inline
int
drbg_get_entropy
(
drbg_state_t
drbg
,
unsigned
char
*
buffer
,
size_t
len
)
{
int
rc
=
0
;
/* Perform testing as defined in 11.3.2 */
if
(
drbg
->
test_data
&&
drbg
->
test_data
->
fail_seed_source
)
return
-1
;
read_cb_buffer
=
buffer
;
read_cb_size
=
len
;
read_cb_len
=
0
;
#if USE_RNDLINUX
rc
=
_gcry_rndlinux_gather_random
(
drbg_read_cb
,
0
,
len
,
GCRY_VERY_STRONG_RANDOM
);
#elif USE_RNDUNIX
rc
=
_gcry_rndunix_gather_random
(
drbg_read_cb
,
0
,
len
,
GCRY_VERY_STRONG_RANDOM
);
#elif USE_RNDW32
do
{
rc
=
_gcry_rndw32_gather_random
(
drbg_read_cb
,
0
,
len
,
GCRY_VERY_STRONG_RANDOM
);
}
while
(
rc
>=
0
&&
read_cb_len
<
read_cb_size
);
#else
rc
=
-1
;
#endif
return
rc
;
}
/******************************************************************
* CTR DRBG callback functions
******************************************************************/
/* BCC function for CTR DRBG as defined in 10.4.3 */
static
gpg_err_code_t
drbg_ctr_bcc
(
drbg_state_t
drbg
,
unsigned
char
*
out
,
const
unsigned
char
*
key
,
drbg_string_t
*
in
)
{
gpg_err_code_t
ret
=
GPG_ERR_GENERAL
;
drbg_string_t
*
curr
=
in
;
size_t
inpos
=
curr
->
len
;
const
unsigned
char
*
pos
=
curr
->
buf
;
drbg_string_t
data
;
drbg_string_fill
(
&
data
,
out
,
drbg_blocklen
(
drbg
));
/* 10.4.3 step 1 */
memset
(
out
,
0
,
drbg_blocklen
(
drbg
));
ret
=
drbg_sym_setkey
(
drbg
,
key
);
if
(
ret
)
return
ret
;
/* 10.4.3 step 2 / 4 */
while
(
inpos
)
{
short
cnt
=
0
;
/* 10.4.3 step 4.1 */
for
(
cnt
=
0
;
cnt
<
drbg_blocklen
(
drbg
);
cnt
++
)
{
out
[
cnt
]
^=
*
pos
;
pos
++
;
inpos
--
;
/* the following branch implements the linked list
* iteration. If we are at the end of the current data
* set, we have to start using the next data set if
* available -- the inpos value always points to the
* current byte and will be zero if we have processed
* the last byte of the last linked list member */
if
(
0
==
inpos
)
{
curr
=
curr
->
next
;
if
(
NULL
!=
curr
)
{
pos
=
curr
->
buf
;
inpos
=
curr
->
len
;
}
else
{
inpos
=
0
;
break
;
}
}
}
/* 10.4.3 step 4.2 */
ret
=
drbg_sym
(
drbg
,
out
,
&
data
);
if
(
ret
)
return
ret
;
/* 10.4.3 step 2 */
}
return
0
;
}
/*
* scratchpad usage: drbg_ctr_update is interlinked with drbg_ctr_df
* (and drbg_ctr_bcc, but this function does not need any temporary buffers),
* the scratchpad is used as follows:
* drbg_ctr_update:
* temp
* start: drbg->scratchpad
* length: drbg_statelen(drbg) + drbg_blocklen(drbg)
* note: the cipher writing into this variable works
* blocklen-wise. Now, when the statelen is not a multiple
* of blocklen, the generateion loop below "spills over"
* by at most blocklen. Thus, we need to give sufficient
* memory.
* df_data
* start: drbg->scratchpad +
* drbg_statelen(drbg) +
* drbg_blocklen(drbg)
* length: drbg_statelen(drbg)
*
* drbg_ctr_df:
* pad
* start: df_data + drbg_statelen(drbg)
* length: drbg_blocklen(drbg)
* iv
* start: pad + drbg_blocklen(drbg)
* length: drbg_blocklen(drbg)
* temp
* start: iv + drbg_blocklen(drbg)
* length: drbg_satelen(drbg) + drbg_blocklen(drbg)
* note: temp is the buffer that the BCC function operates
* on. BCC operates blockwise. drbg_statelen(drbg)
* is sufficient when the DRBG state length is a multiple
* of the block size. For AES192 (and maybe other ciphers)
* this is not correct and the length for temp is
* insufficient (yes, that also means for such ciphers,
* the final output of all BCC rounds are truncated).
* Therefore, add drbg_blocklen(drbg) to cover all
* possibilities.
*/
/* Derivation Function for CTR DRBG as defined in 10.4.2 */
static
gpg_err_code_t
drbg_ctr_df
(
drbg_state_t
drbg
,
unsigned
char
*
df_data
,
size_t
bytes_to_return
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
=
GPG_ERR_GENERAL
;
unsigned
char
L_N
[
8
];
/* S3 is input */
drbg_string_t
S1
,
S2
,
S4
,
cipherin
;
drbg_string_t
*
tempstr
=
addtl
;
unsigned
char
*
pad
=
df_data
+
drbg_statelen
(
drbg
);
unsigned
char
*
iv
=
pad
+
drbg_blocklen
(
drbg
);
unsigned
char
*
temp
=
iv
+
drbg_blocklen
(
drbg
);
size_t
padlen
=
0
;
unsigned
int
templen
=
0
;
/* 10.4.2 step 7 */
unsigned
int
i
=
0
;
/* 10.4.2 step 8 */
const
unsigned
char
*
K
=
(
unsigned
char
*
)
"
\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f
"
"
\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f
"
;
unsigned
char
*
X
;
size_t
generated_len
=
0
;
size_t
inputlen
=
0
;
memset
(
pad
,
0
,
drbg_blocklen
(
drbg
));
memset
(
iv
,
0
,
drbg_blocklen
(
drbg
));
memset
(
temp
,
0
,
drbg_statelen
(
drbg
));
/* 10.4.2 step 1 is implicit as we work byte-wise */
/* 10.4.2 step 2 */
if
((
512
/
8
)
<
bytes_to_return
)
return
GPG_ERR_INV_ARG
;
/* 10.4.2 step 2 -- calculate the entire length of all input data */
for
(;
NULL
!=
tempstr
;
tempstr
=
tempstr
->
next
)
inputlen
+=
tempstr
->
len
;
buf_put_be32
(
&
L_N
[
0
],
inputlen
);
/* 10.4.2 step 3 */
buf_put_be32
(
&
L_N
[
4
],
bytes_to_return
);
/* 10.4.2 step 5: length is size of L_N, input_string, one byte, padding */
padlen
=
(
inputlen
+
sizeof
(
L_N
)
+
1
)
%
(
drbg_blocklen
(
drbg
));
/* wrap the padlen appropriately */
if
(
padlen
)
padlen
=
drbg_blocklen
(
drbg
)
-
padlen
;
/* pad / padlen contains the 0x80 byte and the following zero bytes, so
* add one for byte for 0x80 */
padlen
++
;
pad
[
0
]
=
0x80
;
/* 10.4.2 step 4 -- first fill the linked list and then order it */
drbg_string_fill
(
&
S1
,
iv
,
drbg_blocklen
(
drbg
));
drbg_string_fill
(
&
S2
,
L_N
,
sizeof
(
L_N
));
drbg_string_fill
(
&
S4
,
pad
,
padlen
);
S1
.
next
=
&
S2
;
S2
.
next
=
addtl
;
/* Splice in addtl between S2 and S4 -- we place S4 at the end of the
* input data chain. As this code is only triggered when addtl is not
* NULL, no NULL checks are necessary.*/
tempstr
=
addtl
;
while
(
tempstr
->
next
)
tempstr
=
tempstr
->
next
;
tempstr
->
next
=
&
S4
;
/* 10.4.2 step 9 */
while
(
templen
<
(
drbg_keylen
(
drbg
)
+
(
drbg_blocklen
(
drbg
))))
{
/* 10.4.2 step 9.1 - the padding is implicit as the buffer
* holds zeros after allocation -- even the increment of i
* is irrelevant as the increment remains within length of i */
buf_put_be32
(
iv
,
i
);
/* 10.4.2 step 9.2 -- BCC and concatenation with temp */
ret
=
drbg_ctr_bcc
(
drbg
,
temp
+
templen
,
K
,
&
S1
);
if
(
ret
)
goto
out
;
/* 10.4.2 step 9.3 */
i
++
;
templen
+=
drbg_blocklen
(
drbg
);
}
/* 10.4.2 step 11 */
/* implicit key len with seedlen - blocklen according to table 3 */
X
=
temp
+
(
drbg_keylen
(
drbg
));
drbg_string_fill
(
&
cipherin
,
X
,
drbg_blocklen
(
drbg
));
/* 10.4.2 step 12: overwriting of outval */
/* 10.4.2 step 13 */
ret
=
drbg_sym_setkey
(
drbg
,
temp
);
if
(
ret
)
goto
out
;
while
(
generated_len
<
bytes_to_return
)
{
short
blocklen
=
0
;
/* 10.4.2 step 13.1 */
/* the truncation of the key length is implicit as the key
* is only drbg_blocklen in size -- check for the implementation
* of the cipher function callback */
ret
=
drbg_sym
(
drbg
,
X
,
&
cipherin
);
if
(
ret
)
goto
out
;
blocklen
=
(
drbg_blocklen
(
drbg
)
<
(
bytes_to_return
-
generated_len
))
?
drbg_blocklen
(
drbg
)
:
(
bytes_to_return
-
generated_len
);
/* 10.4.2 step 13.2 and 14 */
memcpy
(
df_data
+
generated_len
,
X
,
blocklen
);
generated_len
+=
blocklen
;
}
ret
=
0
;
out
:
memset
(
iv
,
0
,
drbg_blocklen
(
drbg
));
memset
(
temp
,
0
,
drbg_statelen
(
drbg
));
memset
(
pad
,
0
,
drbg_blocklen
(
drbg
));
return
ret
;
}
/*
* Update function of CTR DRBG as defined in 10.2.1.2
*
* The reseed variable has an enhanced meaning compared to the update
* functions of the other DRBGs as follows:
* 0 => initial seed from initialization
* 1 => reseed via drbg_seed
* 2 => first invocation from drbg_ctr_update when addtl is present. In
* this case, the df_data scratchpad is not deleted so that it is
* available for another calls to prevent calling the DF function
* again.
* 3 => second invocation from drbg_ctr_update. When the update function
* was called with addtl, the df_data memory already contains the
* DFed addtl information and we do not need to call DF again.
*/
static
gpg_err_code_t
drbg_ctr_update
(
drbg_state_t
drbg
,
drbg_string_t
*
addtl
,
int
reseed
)
{
gpg_err_code_t
ret
=
GPG_ERR_GENERAL
;
/* 10.2.1.2 step 1 */
unsigned
char
*
temp
=
drbg
->
scratchpad
;
unsigned
char
*
df_data
=
drbg
->
scratchpad
+
drbg_statelen
(
drbg
)
+
drbg_blocklen
(
drbg
);
unsigned
char
prefix
=
DRBG_PREFIX1
;
memset
(
temp
,
0
,
drbg_statelen
(
drbg
)
+
drbg_blocklen
(
drbg
));
if
(
3
>
reseed
)
memset
(
df_data
,
0
,
drbg_statelen
(
drbg
));
if
(
!
reseed
)
{
/*
* The DRBG uses the CTR mode of the underlying AES cipher. The
* CTR mode increments the counter value after the AES operation
* but SP800-90A requires that the counter is incremented before
* the AES operation. Hence, we increment it at the time we set
* it by one.
*/
drbg_add_buf
(
drbg
->
V
,
drbg_blocklen
(
drbg
),
&
prefix
,
1
);
ret
=
_gcry_cipher_setkey
(
drbg
->
ctr_handle
,
drbg
->
C
,
drbg_keylen
(
drbg
));
if
(
ret
)
goto
out
;
}
/* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */
if
(
addtl
&&
0
<
addtl
->
len
)
{
ret
=
drbg_ctr_df
(
drbg
,
df_data
,
drbg_statelen
(
drbg
),
addtl
);
if
(
ret
)
goto
out
;
}
ret
=
drbg_sym_ctr
(
drbg
,
df_data
,
drbg_statelen
(
drbg
),
temp
,
drbg_statelen
(
drbg
));
if
(
ret
)
goto
out
;
/* 10.2.1.2 step 5 */
ret
=
_gcry_cipher_setkey
(
drbg
->
ctr_handle
,
temp
,
drbg_keylen
(
drbg
));
if
(
ret
)
goto
out
;
/* 10.2.1.2 step 6 */
memcpy
(
drbg
->
V
,
temp
+
drbg_keylen
(
drbg
),
drbg_blocklen
(
drbg
));
/* See above: increment counter by one to compensate timing of CTR op */
drbg_add_buf
(
drbg
->
V
,
drbg_blocklen
(
drbg
),
&
prefix
,
1
);
ret
=
0
;
out
:
memset
(
temp
,
0
,
drbg_statelen
(
drbg
)
+
drbg_blocklen
(
drbg
));
if
(
2
!=
reseed
)
memset
(
df_data
,
0
,
drbg_statelen
(
drbg
));
return
ret
;
}
/*
* scratchpad use: drbg_ctr_update is called independently from
* drbg_ctr_extract_bytes. Therefore, the scratchpad is reused
*/
/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */
static
gpg_err_code_t
drbg_ctr_generate
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
=
0
;
memset
(
drbg
->
scratchpad
,
0
,
drbg_blocklen
(
drbg
));
/* 10.2.1.5.2 step 2 */
if
(
addtl
&&
0
<
addtl
->
len
)
{
addtl
->
next
=
NULL
;
ret
=
drbg_ctr_update
(
drbg
,
addtl
,
2
);
if
(
ret
)
return
ret
;
}
/* 10.2.1.5.2 step 4.1 */
ret
=
drbg_sym_ctr
(
drbg
,
drbg
->
ctr_null
,
DRBG_CTR_NULL_LEN
,
buf
,
buflen
);
if
(
ret
)
goto
out
;
/* 10.2.1.5.2 step 6 */
if
(
addtl
)
addtl
->
next
=
NULL
;
ret
=
drbg_ctr_update
(
drbg
,
addtl
,
3
);
out
:
return
ret
;
}
static
struct
drbg_state_ops_s
drbg_ctr_ops
=
{
drbg_ctr_update
,
drbg_ctr_generate
,
drbg_sym_init
,
drbg_sym_fini
,
};
/******************************************************************
* HMAC DRBG callback functions
******************************************************************/
static
gpg_err_code_t
drbg_hmac_update
(
drbg_state_t
drbg
,
drbg_string_t
*
seed
,
int
reseed
)
{
gpg_err_code_t
ret
=
GPG_ERR_GENERAL
;
int
i
=
0
;
drbg_string_t
seed1
,
seed2
,
cipherin
;
if
(
!
reseed
)
{
/* 10.1.2.3 step 2 already implicitly covered with
* the initial memset(0) of drbg->C */
memset
(
drbg
->
V
,
1
,
drbg_statelen
(
drbg
));
ret
=
drbg_hmac_setkey
(
drbg
,
drbg
->
C
);
if
(
ret
)
return
ret
;
}
/* build linked list which implements the concatenation and fill
* first part*/
drbg_string_fill
(
&
seed1
,
drbg
->
V
,
drbg_statelen
(
drbg
));
/* buffer will be filled in for loop below with one byte */
drbg_string_fill
(
&
seed2
,
NULL
,
1
);
seed1
.
next
=
&
seed2
;
/* seed may be NULL */
seed2
.
next
=
seed
;
drbg_string_fill
(
&
cipherin
,
drbg
->
V
,
drbg_statelen
(
drbg
));
/* we execute two rounds of V/K massaging */
for
(
i
=
2
;
0
<
i
;
i
--
)
{
byte
*
retval
;
/* first round uses 0x0, second 0x1 */
unsigned
char
prefix
=
DRBG_PREFIX0
;
if
(
1
==
i
)
prefix
=
DRBG_PREFIX1
;
/* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */
seed2
.
buf
=
&
prefix
;
retval
=
drbg_hash
(
drbg
,
&
seed1
);
ret
=
drbg_hmac_setkey
(
drbg
,
retval
);
if
(
ret
)
return
ret
;
/* 10.1.2.2 step 2 and 5 -- HMAC for V */
retval
=
drbg_hash
(
drbg
,
&
cipherin
);
memcpy
(
drbg
->
V
,
retval
,
drbg_blocklen
(
drbg
));
/* 10.1.2.2 step 3 */
if
(
!
seed
||
0
==
seed
->
len
)
return
ret
;
}
return
0
;
}
/* generate function of HMAC DRBG as defined in 10.1.2.5 */
static
gpg_err_code_t
drbg_hmac_generate
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
=
0
;
unsigned
int
len
=
0
;
drbg_string_t
data
;
/* 10.1.2.5 step 2 */
if
(
addtl
&&
0
<
addtl
->
len
)
{
addtl
->
next
=
NULL
;
ret
=
drbg_hmac_update
(
drbg
,
addtl
,
1
);
if
(
ret
)
return
ret
;
}
drbg_string_fill
(
&
data
,
drbg
->
V
,
drbg_statelen
(
drbg
));
while
(
len
<
buflen
)
{
unsigned
int
outlen
=
0
;
/* 10.1.2.5 step 4.1 */
byte
*
retval
=
drbg_hash
(
drbg
,
&
data
);
memcpy
(
drbg
->
V
,
retval
,
drbg_blocklen
(
drbg
));
outlen
=
(
drbg_blocklen
(
drbg
)
<
(
buflen
-
len
))
?
drbg_blocklen
(
drbg
)
:
(
buflen
-
len
);
/* 10.1.2.5 step 4.2 */
memcpy
(
buf
+
len
,
drbg
->
V
,
outlen
);
len
+=
outlen
;
}
/* 10.1.2.5 step 6 */
if
(
addtl
)
addtl
->
next
=
NULL
;
ret
=
drbg_hmac_update
(
drbg
,
addtl
,
1
);
return
ret
;
}
static
struct
drbg_state_ops_s
drbg_hmac_ops
=
{
drbg_hmac_update
,
drbg_hmac_generate
,
drbg_hmac_init
,
drbg_hash_fini
,
};
/******************************************************************
* Hash DRBG callback functions
******************************************************************/
/*
* scratchpad usage: as drbg_hash_update and drbg_hash_df are used
* interlinked, the scratchpad is used as follows:
* drbg_hash_update
* start: drbg->scratchpad
* length: drbg_statelen(drbg)
* drbg_hash_df:
* start: drbg->scratchpad + drbg_statelen(drbg)
* length: drbg_blocklen(drbg)
*/
/* Derivation Function for Hash DRBG as defined in 10.4.1 */
static
gpg_err_code_t
drbg_hash_df
(
drbg_state_t
drbg
,
unsigned
char
*
outval
,
size_t
outlen
,
drbg_string_t
*
entropy
)
{
size_t
len
=
0
;
unsigned
char
input
[
5
];
drbg_string_t
data1
;
/* 10.4.1 step 3 */
input
[
0
]
=
1
;
buf_put_be32
(
&
input
[
1
],
(
outlen
*
8
));
/* 10.4.1 step 4.1 -- concatenation of data for input into hash */
drbg_string_fill
(
&
data1
,
input
,
5
);
data1
.
next
=
entropy
;
/* 10.4.1 step 4 */
while
(
len
<
outlen
)
{
short
blocklen
=
0
;
/* 10.4.1 step 4.1 */
byte
*
retval
=
drbg_hash
(
drbg
,
&
data1
);
/* 10.4.1 step 4.2 */
input
[
0
]
++
;
blocklen
=
(
drbg_blocklen
(
drbg
)
<
(
outlen
-
len
))
?
drbg_blocklen
(
drbg
)
:
(
outlen
-
len
);
memcpy
(
outval
+
len
,
retval
,
blocklen
);
len
+=
blocklen
;
}
return
0
;
}
/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */
static
gpg_err_code_t
drbg_hash_update
(
drbg_state_t
drbg
,
drbg_string_t
*
seed
,
int
reseed
)
{
gpg_err_code_t
ret
=
0
;
drbg_string_t
data1
,
data2
;
unsigned
char
*
V
=
drbg
->
scratchpad
;
unsigned
char
prefix
=
DRBG_PREFIX1
;
memset
(
drbg
->
scratchpad
,
0
,
drbg_statelen
(
drbg
));
if
(
!
seed
)
return
GPG_ERR_INV_ARG
;
if
(
reseed
)
{
/* 10.1.1.3 step 1: string length is concatenation of
* 1 byte, V and seed (which is concatenated entropy/addtl
* input)
*/
memcpy
(
V
,
drbg
->
V
,
drbg_statelen
(
drbg
));
drbg_string_fill
(
&
data1
,
&
prefix
,
1
);
drbg_string_fill
(
&
data2
,
V
,
drbg_statelen
(
drbg
));
data1
.
next
=
&
data2
;
data2
.
next
=
seed
;
}
else
{
drbg_string_fill
(
&
data1
,
seed
->
buf
,
seed
->
len
);
data1
.
next
=
seed
->
next
;
}
/* 10.1.1.2 / 10.1.1.3 step 2 and 3 */
ret
=
drbg_hash_df
(
drbg
,
drbg
->
V
,
drbg_statelen
(
drbg
),
&
data1
);
if
(
ret
)
goto
out
;
/* 10.1.1.2 / 10.1.1.3 step 4 -- concatenation */
prefix
=
DRBG_PREFIX0
;
drbg_string_fill
(
&
data1
,
&
prefix
,
1
);
drbg_string_fill
(
&
data2
,
drbg
->
V
,
drbg_statelen
(
drbg
));
data1
.
next
=
&
data2
;
/* 10.1.1.2 / 10.1.1.3 step 4 -- df operation */
ret
=
drbg_hash_df
(
drbg
,
drbg
->
C
,
drbg_statelen
(
drbg
),
&
data1
);
out
:
memset
(
drbg
->
scratchpad
,
0
,
drbg_statelen
(
drbg
));
return
ret
;
}
/* Processing of additional information string for Hash DRBG. */
static
gpg_err_code_t
drbg_hash_process_addtl
(
drbg_state_t
drbg
,
drbg_string_t
*
addtl
)
{
drbg_string_t
data1
,
data2
;
drbg_string_t
*
data3
;
unsigned
char
prefix
=
DRBG_PREFIX2
;
byte
*
retval
;
/* 10.1.1.4 step 2 */
if
(
!
addtl
||
0
==
addtl
->
len
)
return
0
;
/* 10.1.1.4 step 2a -- concatenation */
drbg_string_fill
(
&
data1
,
&
prefix
,
1
);
drbg_string_fill
(
&
data2
,
drbg
->
V
,
drbg_statelen
(
drbg
));
data3
=
addtl
;
data1
.
next
=
&
data2
;
data2
.
next
=
data3
;
data3
->
next
=
NULL
;
/* 10.1.1.4 step 2a -- cipher invocation */
retval
=
drbg_hash
(
drbg
,
&
data1
);
/* 10.1.1.4 step 2b */
drbg_add_buf
(
drbg
->
V
,
drbg_statelen
(
drbg
),
retval
,
drbg_blocklen
(
drbg
));
return
0
;
}
/*
* Hashgen defined in 10.1.1.4
*/
static
gpg_err_code_t
drbg_hash_hashgen
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
unsigned
int
len
=
0
;
unsigned
char
*
src
=
drbg
->
scratchpad
;
drbg_string_t
data
;
unsigned
char
prefix
=
DRBG_PREFIX1
;
/* 10.1.1.4 step hashgen 2 */
memcpy
(
src
,
drbg
->
V
,
drbg_statelen
(
drbg
));
drbg_string_fill
(
&
data
,
src
,
drbg_statelen
(
drbg
));
while
(
len
<
buflen
)
{
unsigned
int
outlen
=
0
;
/* 10.1.1.4 step hashgen 4.1 */
byte
*
retval
=
drbg_hash
(
drbg
,
&
data
);
outlen
=
(
drbg_blocklen
(
drbg
)
<
(
buflen
-
len
))
?
drbg_blocklen
(
drbg
)
:
(
buflen
-
len
);
/* 10.1.1.4 step hashgen 4.2 */
memcpy
(
buf
+
len
,
retval
,
outlen
);
len
+=
outlen
;
/* 10.1.1.4 hashgen step 4.3 */
if
(
len
<
buflen
)
drbg_add_buf
(
src
,
drbg_statelen
(
drbg
),
&
prefix
,
1
);
}
memset
(
drbg
->
scratchpad
,
0
,
drbg_statelen
(
drbg
));
return
0
;
}
/* Generate function for Hash DRBG as defined in 10.1.1.4 */
static
gpg_err_code_t
drbg_hash_generate
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
;
unsigned
char
prefix
=
DRBG_PREFIX3
;
drbg_string_t
data1
,
data2
;
byte
*
retval
;
union
{
unsigned
char
req
[
8
];
u64
req_int
;
}
u
;
/* 10.1.1.4 step 2 */
ret
=
drbg_hash_process_addtl
(
drbg
,
addtl
);
if
(
ret
)
return
ret
;
/* 10.1.1.4 step 3 -- invocation of the Hashgen function defined in
* 10.1.1.4 */
ret
=
drbg_hash_hashgen
(
drbg
,
buf
,
buflen
);
if
(
ret
)
return
ret
;
/* 10.1.1.4 step 4 */
drbg_string_fill
(
&
data1
,
&
prefix
,
1
);
drbg_string_fill
(
&
data2
,
drbg
->
V
,
drbg_statelen
(
drbg
));
data1
.
next
=
&
data2
;
/* this is the value H as documented in 10.1.1.4 */
retval
=
drbg_hash
(
drbg
,
&
data1
);
/* 10.1.1.4 step 5 */
drbg_add_buf
(
drbg
->
V
,
drbg_statelen
(
drbg
),
retval
,
drbg_blocklen
(
drbg
));
drbg_add_buf
(
drbg
->
V
,
drbg_statelen
(
drbg
),
drbg
->
C
,
drbg_statelen
(
drbg
));
u
.
req_int
=
be_bswap64
(
drbg
->
reseed_ctr
);
drbg_add_buf
(
drbg
->
V
,
drbg_statelen
(
drbg
),
u
.
req
,
sizeof
(
u
.
req
));
return
ret
;
}
/*
* scratchpad usage: as update and generate are used isolated, both
* can use the scratchpad
*/
static
struct
drbg_state_ops_s
drbg_hash_ops
=
{
drbg_hash_update
,
drbg_hash_generate
,
drbg_hash_init
,
drbg_hash_fini
,
};
/******************************************************************
* Functions common for DRBG implementations
******************************************************************/
/*
* Seeding or reseeding of the DRBG
*
* @drbg: DRBG state struct
* @pers: personalization / additional information buffer
* @reseed: 0 for initial seed process, 1 for reseeding
*
* return:
* 0 on success
* error value otherwise
*/
static
gpg_err_code_t
drbg_seed
(
drbg_state_t
drbg
,
drbg_string_t
*
pers
,
int
reseed
)
{
gpg_err_code_t
ret
=
0
;
unsigned
char
*
entropy
=
NULL
;
size_t
entropylen
=
0
;
drbg_string_t
data1
;
/* 9.1 / 9.2 / 9.3.1 step 3 */
if
(
pers
&&
pers
->
len
>
(
drbg_max_addtl
()))
{
dbg
((
"DRBG: personalization string too long %lu
\n
"
,
pers
->
len
));
return
GPG_ERR_INV_ARG
;
}
if
(
drbg
->
test_data
&&
drbg
->
test_data
->
testentropy
)
{
drbg_string_fill
(
&
data1
,
drbg
->
test_data
->
testentropy
->
buf
,
drbg
->
test_data
->
testentropy
->
len
);
dbg
((
"DRBG: using test entropy
\n
"
));
}
else
{
/* Gather entropy equal to the security strength of the DRBG.
* With a derivation function, a nonce is required in addition
* to the entropy. A nonce must be at least 1/2 of the security
* strength of the DRBG in size. Thus, entropy * nonce is 3/2
* of the strength. The consideration of a nonce is only
* applicable during initial seeding. */
entropylen
=
drbg_sec_strength
(
drbg
->
core
->
flags
);
if
(
!
entropylen
)
return
GPG_ERR_GENERAL
;
if
(
0
==
reseed
)
/* make sure we round up strength/2 in
* case it is not divisible by 2 */
entropylen
=
((
entropylen
+
1
)
/
2
)
*
3
;
dbg
((
"DRBG: (re)seeding with %lu bytes of entropy
\n
"
,
entropylen
));
entropy
=
xcalloc_secure
(
1
,
entropylen
);
if
(
!
entropy
)
return
GPG_ERR_ENOMEM
;
ret
=
drbg_get_entropy
(
drbg
,
entropy
,
entropylen
);
if
(
ret
)
goto
out
;
drbg_string_fill
(
&
data1
,
entropy
,
entropylen
);
}
/* concatenation of entropy with personalization str / addtl input)
* the variable pers is directly handed by the caller, check its
* contents whether it is appropriate */
if
(
pers
&&
pers
->
buf
&&
0
<
pers
->
len
&&
NULL
==
pers
->
next
)
{
data1
.
next
=
pers
;
dbg
((
"DRBG: using personalization string
\n
"
));
}
ret
=
drbg
->
d_ops
->
update
(
drbg
,
&
data1
,
reseed
);
dbg
((
"DRBG: state updated with seed
\n
"
));
if
(
ret
)
goto
out
;
drbg
->
seeded
=
1
;
/* 10.1.1.2 / 10.1.1.3 step 5 */
drbg
->
reseed_ctr
=
1
;
out
:
xfree
(
entropy
);
return
ret
;
}
/*************************************************************************
* Exported interfaces.
*************************************************************************/
/*
* DRBG generate function as required by SP800-90A - this function
* generates random numbers
*
* @drbg DRBG state handle
* @buf Buffer where to store the random numbers -- the buffer must already
* be pre-allocated by caller
* @buflen Length of output buffer - this value defines the number of random
* bytes pulled from DRBG
* @addtl Additional input that is mixed into state, may be NULL -- note
* the entropy is pulled by the DRBG internally unconditionally
* as defined in SP800-90A. The additional input is mixed into
* the state in addition to the pulled entropy.
*
* return: Generated number of bytes.
*/
static
gpg_err_code_t
drbg_generate
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
=
GPG_ERR_INV_ARG
;
if
(
0
==
buflen
||
!
buf
)
{
dbg
((
"DRBG: no buffer provided
\n
"
));
return
ret
;
}
if
(
addtl
&&
NULL
==
addtl
->
buf
&&
0
<
addtl
->
len
)
{
dbg
((
"DRBG: wrong format of additional information
\n
"
));
return
ret
;
}
/* 9.3.1 step 2 */
if
(
buflen
>
(
drbg_max_request_bytes
()))
{
dbg
((
"DRBG: requested random numbers too large %u
\n
"
,
buflen
));
return
ret
;
}
/* 9.3.1 step 3 is implicit with the chosen DRBG */
/* 9.3.1 step 4 */
if
(
addtl
&&
addtl
->
len
>
(
drbg_max_addtl
()))
{
dbg
((
"DRBG: additional information string too long %lu
\n
"
,
addtl
->
len
));
return
ret
;
}
/* 9.3.1 step 5 is implicit with the chosen DRBG */
/* 9.3.1 step 6 and 9 supplemented by 9.3.2 step c -- the spec is a
* bit convoluted here, we make it simpler */
if
((
drbg_max_requests
())
<
drbg
->
reseed_ctr
)
drbg
->
seeded
=
0
;
if
(
drbg
->
pr
||
!
drbg
->
seeded
)
{
dbg
((
"DRBG: reseeding before generation (prediction resistance: %s, state %s)
\n
"
,
drbg
->
pr
?
"true"
:
"false"
,
drbg
->
seeded
?
"seeded"
:
"unseeded"
));
/* 9.3.1 steps 7.1 through 7.3 */
ret
=
drbg_seed
(
drbg
,
addtl
,
1
);
if
(
ret
)
return
ret
;
/* 9.3.1 step 7.4 */
addtl
=
NULL
;
}
if
(
addtl
&&
addtl
->
buf
)
{
dbg
((
"DRBG: using additional information string
\n
"
));
}
/* 9.3.1 step 8 and 10 */
ret
=
drbg
->
d_ops
->
generate
(
drbg
,
buf
,
buflen
,
addtl
);
/* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */
drbg
->
reseed_ctr
++
;
if
(
ret
)
return
ret
;
/* 11.3.3 -- re-perform self tests after some generated random
* numbers, the chosen value after which self test is performed
* is arbitrary, but it should be reasonable */
/* Here we do not perform the self tests because of the following
* reasons: it is mathematically impossible that the initial self tests
* were successfully and the following are not. If the initial would
* pass and the following would not, the system integrity is violated.
* In this case, the entire system operation is questionable and it
* is unlikely that the integrity violation only affects to the
* correct operation of the DRBG.
*/
#if 0
if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096))
{
dbg (("DRBG: start to perform self test\n"));
ret = drbg_healthcheck ();
if (ret)
{
log_fatal (("DRBG: self test failed\n"));
return ret;
}
else
{
dbg (("DRBG: self test successful\n"));
}
}
#endif
return
ret
;
}
/*
* Wrapper around drbg_generate which can pull arbitrary long strings
* from the DRBG without hitting the maximum request limitation.
*
* Parameters: see drbg_generate
* Return codes: see drbg_generate -- if one drbg_generate request fails,
* the entire drbg_generate_long request fails
*/
static
gpg_err_code_t
drbg_generate_long
(
drbg_state_t
drbg
,
unsigned
char
*
buf
,
unsigned
int
buflen
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
=
0
;
unsigned
int
slice
=
0
;
unsigned
char
*
buf_p
=
buf
;
unsigned
len
=
0
;
do
{
unsigned
int
chunk
=
0
;
slice
=
((
buflen
-
len
)
/
drbg_max_request_bytes
());
chunk
=
slice
?
drbg_max_request_bytes
()
:
(
buflen
-
len
);
ret
=
drbg_generate
(
drbg
,
buf_p
,
chunk
,
addtl
);
if
(
ret
)
return
ret
;
buf_p
+=
chunk
;
len
+=
chunk
;
}
while
(
slice
>
0
&&
(
len
<
buflen
));
return
ret
;
}
/*
* DRBG uninstantiate function as required by SP800-90A - this function
* frees all buffers and the DRBG handle
*
* @drbg DRBG state handle
*
* return
* 0 on success
*/
static
gpg_err_code_t
drbg_uninstantiate
(
drbg_state_t
drbg
)
{
if
(
!
drbg
)
return
GPG_ERR_INV_ARG
;
drbg
->
d_ops
->
crypto_fini
(
drbg
);
xfree
(
drbg
->
V
);
drbg
->
V
=
NULL
;
xfree
(
drbg
->
C
);
drbg
->
C
=
NULL
;
drbg
->
reseed_ctr
=
0
;
xfree
(
drbg
->
scratchpad
);
drbg
->
scratchpad
=
NULL
;
drbg
->
seeded
=
0
;
drbg
->
pr
=
0
;
drbg
->
seed_init_pid
=
0
;
return
0
;
}
/*
* DRBG instantiation function as required by SP800-90A - this function
* sets up the DRBG handle, performs the initial seeding and all sanity
* checks required by SP800-90A
*
* @drbg memory of state -- if NULL, new memory is allocated
* @pers Personalization string that is mixed into state, may be NULL -- note
* the entropy is pulled by the DRBG internally unconditionally
* as defined in SP800-90A. The additional input is mixed into
* the state in addition to the pulled entropy.
* @coreref reference to core
* @flags Flags defining the requested DRBG type and cipher type. The flags
* are defined in drbg.h and may be XORed. Beware, if you XOR multiple
* cipher types together, the code picks the core on a first come first
* serve basis as it iterates through the available cipher cores and
* uses the one with the first match. The minimum required flags are:
* cipher type flag
*
* return
* 0 on success
* error value otherwise
*/
static
gpg_err_code_t
drbg_instantiate
(
drbg_state_t
drbg
,
drbg_string_t
*
pers
,
int
coreref
,
int
pr
)
{
gpg_err_code_t
ret
=
GPG_ERR_ENOMEM
;
unsigned
int
sb_size
=
0
;
if
(
!
drbg
)
return
GPG_ERR_INV_ARG
;
dbg
((
"DRBG: Initializing DRBG core %d with prediction resistance %s
\n
"
,
coreref
,
pr
?
"enabled"
:
"disabled"
));
drbg
->
core
=
&
drbg_cores
[
coreref
];
drbg
->
pr
=
pr
;
drbg
->
seeded
=
0
;
if
(
drbg
->
core
->
flags
&
DRBG_HMAC
)
drbg
->
d_ops
=
&
drbg_hmac_ops
;
else
if
(
drbg
->
core
->
flags
&
DRBG_HASH_MASK
)
drbg
->
d_ops
=
&
drbg_hash_ops
;
else
if
(
drbg
->
core
->
flags
&
DRBG_CTR_MASK
)
drbg
->
d_ops
=
&
drbg_ctr_ops
;
else
return
GPG_ERR_GENERAL
;
/* 9.1 step 1 is implicit with the selected DRBG type -- see
* drbg_sec_strength() */
/* 9.1 step 2 is implicit as caller can select prediction resistance
* and the flag is copied into drbg->flags --
* all DRBG types support prediction resistance */
/* 9.1 step 4 is implicit in drbg_sec_strength */
ret
=
drbg
->
d_ops
->
crypto_init
(
drbg
);
if
(
ret
)
goto
err
;
drbg
->
V
=
xcalloc_secure
(
1
,
drbg_statelen
(
drbg
));
if
(
!
drbg
->
V
)
goto
fini
;
drbg
->
C
=
xcalloc_secure
(
1
,
drbg_statelen
(
drbg
));
if
(
!
drbg
->
C
)
goto
fini
;
/* scratchpad is only generated for CTR and Hash */
if
(
drbg
->
core
->
flags
&
DRBG_HMAC
)
sb_size
=
0
;
else
if
(
drbg
->
core
->
flags
&
DRBG_CTR_MASK
)
sb_size
=
drbg_statelen
(
drbg
)
+
drbg_blocklen
(
drbg
)
+
/* temp */
drbg_statelen
(
drbg
)
+
/* df_data */
drbg_blocklen
(
drbg
)
+
/* pad */
drbg_blocklen
(
drbg
)
+
/* iv */
drbg_statelen
(
drbg
)
+
drbg_blocklen
(
drbg
);
/* temp */
else
sb_size
=
drbg_statelen
(
drbg
);
if
(
0
<
sb_size
)
{
drbg
->
scratchpad
=
xcalloc_secure
(
1
,
sb_size
);
if
(
!
drbg
->
scratchpad
)
goto
fini
;
}
dbg
((
"DRBG: state allocated with scratchpad size %u bytes
\n
"
,
sb_size
));
/* 9.1 step 6 through 11 */
ret
=
drbg_seed
(
drbg
,
pers
,
0
);
if
(
ret
)
goto
fini
;
dbg
((
"DRBG: core %d %s prediction resistance successfully initialized
\n
"
,
coreref
,
pr
?
"with"
:
"without"
));
return
0
;
fini
:
drbg
->
d_ops
->
crypto_fini
(
drbg
);
err
:
drbg_uninstantiate
(
drbg
);
return
ret
;
}
/*
* DRBG reseed function as required by SP800-90A
*
* @drbg DRBG state handle
* @addtl Additional input that is mixed into state, may be NULL -- note
* the entropy is pulled by the DRBG internally unconditionally
* as defined in SP800-90A. The additional input is mixed into
* the state in addition to the pulled entropy.
*
* return
* 0 on success
* error value otherwise
*/
static
gpg_err_code_t
drbg_reseed
(
drbg_state_t
drbg
,
drbg_string_t
*
addtl
)
{
gpg_err_code_t
ret
=
0
;
ret
=
drbg_seed
(
drbg
,
addtl
,
1
);
return
ret
;
}
/******************************************************************
* Libgcrypt integration code.
******************************************************************/
/***************************************************
* Libgcrypt backend functions to the RNG API code.
***************************************************/
static
inline
void
drbg_lock
(
void
)
{
gpg_err_code_t
ec
;
ec
=
gpgrt_lock_lock
(
&
drbg_lock_var
);
if
(
ec
)
log_fatal
(
"failed to acquire the RNG lock: %s
\n
"
,
gpg_strerror
(
ec
));
}
static
inline
void
drbg_unlock
(
void
)
{
gpg_err_code_t
ec
;
ec
=
gpgrt_lock_unlock
(
&
drbg_lock_var
);
if
(
ec
)
log_fatal
(
"failed to release the RNG lock: %s
\n
"
,
gpg_strerror
(
ec
));
}
/* Basic initialization is required to initialize mutexes and
do a few checks on the implementation. */
static
void
basic_initialization
(
void
)
{
static
int
initialized
;
if
(
initialized
)
return
;
initialized
=
1
;
/* Make sure that we are still using the values we have
traditionally used for the random levels. */
gcry_assert
(
GCRY_WEAK_RANDOM
==
0
&&
GCRY_STRONG_RANDOM
==
1
&&
GCRY_VERY_STRONG_RANDOM
==
2
);
}
/****** helper functions where lock must be held by caller *****/
/* Check whether given flags are known to point to an applicable DRBG */
static
gpg_err_code_t
drbg_algo_available
(
u32
flags
,
int
*
coreref
)
{
int
i
=
0
;
for
(
i
=
0
;
ARRAY_SIZE
(
drbg_cores
)
>
i
;
i
++
)
{
if
((
drbg_cores
[
i
].
flags
&
DRBG_CIPHER_MASK
)
==
(
flags
&
DRBG_CIPHER_MASK
))
{
*
coreref
=
i
;
return
0
;
}
}
return
GPG_ERR_GENERAL
;
}
static
gpg_err_code_t
_drbg_init_internal
(
u32
flags
,
drbg_string_t
*
pers
)
{
static
u32
oldflags
;
gpg_err_code_t
ret
=
0
;
int
coreref
=
0
;
int
pr
=
0
;
/* If a caller provides 0 as flags, use the flags of the previous
* initialization, otherwise use the current flags and remember them
* for the next invocation. If no flag is given and no global state
* is set this is the first initialization and we set the default
* type.
*/
if
(
!
flags
&&
!
drbg_state
)
flags
=
oldflags
=
DRBG_DEFAULT_TYPE
;
else
if
(
!
flags
)
flags
=
oldflags
;
else
oldflags
=
flags
;
ret
=
drbg_algo_available
(
flags
,
&
coreref
);
if
(
ret
)
return
ret
;
if
(
drbg_state
)
{
drbg_uninstantiate
(
drbg_state
);
}
else
{
drbg_state
=
xtrycalloc_secure
(
1
,
sizeof
*
drbg_state
);
if
(
!
drbg_state
)
return
gpg_err_code_from_syserror
();
}
if
(
flags
&
DRBG_PREDICTION_RESIST
)
pr
=
1
;
ret
=
drbg_instantiate
(
drbg_state
,
pers
,
coreref
,
pr
);
if
(
ret
)
fips_signal_error
(
"DRBG cannot be initialized"
);
else
drbg_state
->
seed_init_pid
=
getpid
();
return
ret
;
}
/************* calls available to common RNG code **************/
/*
* Initialize one DRBG invoked by the libgcrypt API
*/
void
_gcry_rngdrbg_inititialize
(
int
full
)
{
basic_initialization
();
if
(
!
full
)
return
;
drbg_lock
();
if
(
!
drbg_state
)
_drbg_init_internal
(
0
,
NULL
);
drbg_unlock
();
}
/*
* Backend handler function for GCRYCTL_DRBG_REINIT
*
* Select a different DRBG type and initialize it.
* Function checks whether requested DRBG type exists and returns an error in
* case it does not. In case of an error, the previous instantiated DRBG is
* left untouched and alive. Thus, in case of an error, a DRBG is always
* available, even if it is not the chosen one.
*
* Re-initialization will be performed in any case regardless whether flags
* or personalization string are set.
*
* If flags is NULL, do not change current DRBG. If PERS is NULL and
* NPERS is 0, re-initialize without personalization string. If PERS
* is not NULL NPERS must be one and PERS and the first ietm from the
* bufer is take as personalization string.
*/
gpg_err_code_t
_gcry_rngdrbg_reinit
(
const
char
*
flagstr
,
gcry_buffer_t
*
pers
,
int
npers
)
{
gpg_err_code_t
ret
;
unsigned
int
flags
;
/* If PERS is not given we expect NPERS to be zero; if given we
expect a one-item array. */
if
((
!
pers
&&
npers
)
||
(
pers
&&
npers
!=
1
))
return
GPG_ERR_INV_ARG
;
ret
=
parse_flag_string
(
flagstr
,
&
flags
);
if
(
!
ret
)
{
dbg
((
"DRBG: reinitialize internal DRBG state with flags %u
\n
"
,
flags
));
drbg_lock
();
if
(
pers
)
{
drbg_string_t
persbuf
;
drbg_string_fill
(
&
persbuf
,
(
const
unsigned
char
*
)
pers
[
0
].
data
+
pers
[
0
].
off
,
pers
[
0
].
len
);
ret
=
_drbg_init_internal
(
flags
,
&
persbuf
);
}
else
ret
=
_drbg_init_internal
(
flags
,
NULL
);
drbg_unlock
();
}
return
ret
;
}
/* Try to close the FDs of the random gather module. This is
* currently only implemented for rndlinux. */
void
_gcry_rngdrbg_close_fds
(
void
)
{
#if USE_RNDLINUX
drbg_lock
();
_gcry_rndlinux_gather_random
(
NULL
,
0
,
0
,
0
);
drbg_unlock
();
#endif
}
/* Print some statistics about the RNG. */
void
_gcry_rngdrbg_dump_stats
(
void
)
{
/* Not yet implemented. */
/* Maybe dumping of reseed counter? */
}
/* This function returns true if no real RNG is available or the
* quality of the RNG has been degraded for test purposes. */
int
_gcry_rngdrbg_is_faked
(
void
)
{
return
0
;
/* Faked random is not allowed. */
}
/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
* should be in the range of 0..100 to indicate the goodness of the
* entropy added, or -1 for goodness not known. */
gcry_error_t
_gcry_rngdrbg_add_bytes
(
const
void
*
buf
,
size_t
buflen
,
int
quality
)
{
gpg_err_code_t
ret
=
0
;
drbg_string_t
seed
;
(
void
)
quality
;
_gcry_rngdrbg_inititialize
(
1
);
/* Auto-initialize if needed */
if
(
!
drbg_state
)
return
GPG_ERR_GENERAL
;
drbg_string_fill
(
&
seed
,
(
unsigned
char
*
)
buf
,
buflen
);
drbg_lock
();
ret
=
drbg_reseed
(
drbg_state
,
&
seed
);
drbg_unlock
();
return
ret
;
}
/* This function is to be used for all types of random numbers, including
* nonces
*/
void
_gcry_rngdrbg_randomize
(
void
*
buffer
,
size_t
length
,
enum
gcry_random_level
level
)
{
(
void
)
level
;
_gcry_rngdrbg_inititialize
(
1
);
/* Auto-initialize if needed */
drbg_lock
();
if
(
!
drbg_state
)
{
fips_signal_error
(
"DRBG is not initialized"
);
goto
bailout
;
}
/* As reseeding changes the entire state of the DRBG, including any
* key, either a re-init or a reseed is sufficient for a fork */
if
(
drbg_state
->
seed_init_pid
!=
getpid
())
{
/* We are in a child of us. Perform a reseeding. */
if
(
drbg_reseed
(
drbg_state
,
NULL
))
{
fips_signal_error
(
"reseeding upon fork failed"
);
log_fatal
(
"severe error getting random
\n
"
);
goto
bailout
;
}
}
/* potential integer overflow is covered by drbg_generate which
* ensures that length cannot overflow an unsigned int */
if
(
0
<
length
)
{
if
(
!
buffer
)
goto
bailout
;
if
(
drbg_generate_long
(
drbg_state
,
buffer
,
(
unsigned
int
)
length
,
NULL
))
log_fatal
(
"No random numbers generated
\n
"
);
}
else
{
drbg_gen_t
*
data
=
(
drbg_gen_t
*
)
buffer
;
/* catch NULL pointer */
if
(
!
data
||
!
data
->
outbuf
)
{
fips_signal_error
(
"No output buffer provided"
);
goto
bailout
;
}
if
(
drbg_generate_long
(
drbg_state
,
data
->
outbuf
,
data
->
outlen
,
data
->
addtl
))
log_fatal
(
"No random numbers generated
\n
"
);
}
bailout
:
drbg_unlock
();
return
;
}
/***************************************************************
* Self-test code
***************************************************************/
/*
* Test vectors from
* http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip
*/
struct
gcry_drbg_test_vector
drbg_test_pr
[]
=
{
{
/* .flags = */
"sha256 pr"
/* DRBG_PR_HASHSHA256 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d
"
"
\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0
"
"
\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1
"
"
\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6
"
,
/* .entropylen = */
48
,
/* .entpra = */
(
unsigned
char
*
)
"
\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb
"
"
\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13
"
"
\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15
"
,
/* .entprb = */
(
unsigned
char
*
)
"
\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09
"
"
\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde
"
"
\x76\xaa\x55\x04\x8b\x0a\x72\x95
"
,
/* .entprlen = */
32
,
/* .addtla = */
(
unsigned
char
*
)
"
\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d
"
"
\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad
"
"
\xa9\xd0\x1d\x59\x02\xc4\xff\x70
"
,
/* .addtlb = */
(
unsigned
char
*
)
"
\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31
"
"
\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41
"
"
\x9f\xeb\xe4\x38\xfe\x67\x00\xcd
"
,
/* .addtllen = */
32
,
/* .pers = */
NULL
,
/* .perslen = */
0
,
/* .expected = */
(
unsigned
char
*
)
"
\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32
"
"
\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c
"
"
\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18
"
"
\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb
"
"
\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81
"
"
\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4
"
"
\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6
"
"
\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13
"
"
\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9
"
"
\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60
"
"
\x50\x47\xa3\x63\x81\x16\xaf\x19
"
,
/* .expectedlen = */
128
,
/* .entropyreseed = */
NULL
,
/* .entropyreseed_len = */
0
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
},
{
/* flags = */
"hmac sha256 pr"
/* DRBG_PR_HMACSHA256 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89
"
"
\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf
"
"
\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20
"
"
\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67
"
,
/* .entropylen = */
48
,
/* .entpra = */
(
unsigned
char
*
)
"
\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79
"
"
\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57
"
"
\x20\x28\xad\xf2\x60\xd7\xcd\x45
"
,
/* .entprb = */
(
unsigned
char
*
)
"
\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71
"
"
\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66
"
"
\x1f\xfa\x74\xd3\xac\xa6\x74\x60
"
,
/* .entprlen = */
32
,
/* .addtla = */
NULL
,
/* .addtlb = */
NULL
,
/* .addtllen = */
0
,
/* .pers = */
(
unsigned
char
*
)
"
\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f
"
"
\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce
"
"
\xcd\x56\x80\xbc\xb8\x15\xc8\xaa
"
,
/* .perslen = */
32
,
/* .expected = */
(
unsigned
char
*
)
"
\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99
"
"
\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3
"
"
\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75
"
"
\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61
"
"
\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88
"
"
\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e
"
"
\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c
"
"
\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce
"
"
\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc
"
"
\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc
"
"
\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3
"
,
/* .expectedlen = */
128
,
/* .entropyreseed = */
NULL
,
/* .entropyreseed_len = */
0
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
},
{
/* .flags = */
"aes sym128 pr"
,
/* DRBG_PR_CTRAES128 */
/* .entropy = */
(
unsigned
char
*
)
"
\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06
"
"
\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97
"
,
/* .entropylen = */
24
,
/* .entpra = */
(
unsigned
char
*
)
"
\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7
"
"
\xc4\x2c\xe8\x10
"
,
/* .entprb = */
(
unsigned
char
*
)
"
\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22
"
"
\x08\xf7\xa5\x01
"
,
/* .entprlen = */
16
,
/* .addtla = */
(
unsigned
char
*
)
"
\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59
"
"
\x23\x6d\xad\x1d
"
,
/* .addtlb = */
(
unsigned
char
*
)
"
\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12
"
"
\xbc\x59\x31\x8c
"
,
/* .addtllen = */
16
,
/* .pers = */
(
unsigned
char
*
)
"
\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4
"
"
\x37\x3c\x5c\x0b
"
,
/* .perslen = */
16
,
/* .expected = */
(
unsigned
char
*
)
"
\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71
"
"
\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28
"
"
\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45
"
"
\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08
"
"
\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4
"
"
\x23\xc5\x1f\x68
"
,
/* .expectedlen = */
64
,
/* .entropyreseed = */
NULL
,
/* .entropyreseed_len = */
0
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
}
};
struct
gcry_drbg_test_vector
drbg_test_nopr
[]
=
{
{
/* .flags = */
"sha256"
/* DRBG_NOPR_HASHSHA256 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c
"
"
\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d
"
"
\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff
"
"
\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56
"
,
/* .entropylen = */
48
,
/* .entpra = */
NULL
,
/* .entprb = */
NULL
,
/* .entprlen = */
0
,
/* .addtla = */
(
unsigned
char
*
)
"
\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73
"
"
\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10
"
"
\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd
"
,
/* .addtlb = */
(
unsigned
char
*
)
"
\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0
"
"
\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d
"
"
\xa8\xc0\x85\xd1\x5a\x0c\x59\x40
"
,
/* .addtllen = */
32
,
/* .pers = */
NULL
,
/* .perslen = */
0
,
/* .expected = */
(
unsigned
char
*
)
"
\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7
"
"
\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b
"
"
\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0
"
"
\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8
"
"
\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f
"
"
\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d
"
"
\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59
"
"
\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b
"
"
\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0
"
"
\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c
"
"
\x70\xa8\x07\x59\x97\xeb\xf6\xbe
"
,
/* .expectedlen = */
128
,
/* .entropyreseed = */
NULL
,
/* .entropyreseed_len = */
0
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
},
{
/* .flags = */
"hmac sha256"
/* DRBG_NOPR_HMACSHA256 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf
"
"
\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54
"
"
\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf
"
"
\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e
"
,
/* .entropylen = */
48
,
/* .entpra = */
NULL
,
/* .entprb = */
NULL
,
/* .entprlen = */
0
,
/* .addtla = */
NULL
,
/* .addtlb = */
NULL
,
/* .addtllen = */
0
,
/* .pers = */
(
unsigned
char
*
)
"
\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37
"
"
\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58
"
"
\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9
"
,
/* .perslen = */
32
,
/* .expected = */
(
unsigned
char
*
)
"
\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81
"
"
\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37
"
"
\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10
"
"
\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61
"
"
\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28
"
"
\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f
"
"
\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07
"
"
\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66
"
"
\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2
"
"
\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29
"
"
\x10\x37\x41\x03\x0c\xcc\x3a\x56
"
,
/* .expectedlen = */
128
,
/* .entropyreseed = */
NULL
,
/* .entropyreseed_len = */
0
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
},
{
/* .flags = */
"aes sym128"
/* DRBG_NOPR_CTRAES128 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98
"
"
\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6
"
,
/* .entropylen = */
24
,
/* .entpra = */
NULL
,
/* .entprb = */
NULL
,
/* .entprlen = */
0
,
/* .addtla = */
(
unsigned
char
*
)
"
\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2
"
"
\x44\x85\xe7\xfe
"
,
/* .addtlb = */
(
unsigned
char
*
)
"
\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4
"
"
\x82\x16\x62\x7f
"
,
/* .addtllen = */
16
,
/* .pers = */
(
unsigned
char
*
)
"
\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f
"
"
\x8e\xcf\xe0\x02
"
,
/* .perslen = */
16
,
/* .expected = */
(
unsigned
char
*
)
"
\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a
"
"
\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95
"
"
\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f
"
"
\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a
"
"
\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a
"
"
\x2b\x49\x1e\x5c
"
,
/* .expectedlen = */
64
,
/* .entropyreseed = */
NULL
,
/* .entropyreseed_len = */
0
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
},
{
/* .flags = */
"sha1"
/* DRBG_NOPR_HASHSHA1 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\x16\x10\xb8\x28\xcc\xd2\x7d\xe0\x8c\xee\xa0\x32
"
"
\xa2\x0e\x92\x08\x49\x2c\xf1\x70\x92\x42\xf6\xb5
"
,
/* .entropylen = */
24
,
/* .entpra = */
NULL
,
/* .entprb = */
NULL
,
/* .entprlen = */
0
,
/* .addtla = */
NULL
,
/* .addtlb = */
NULL
,
/* .addtllen = */
0
,
/* .pers = */
NULL
,
/* .perslen = */
0
,
/* .expected = */
(
unsigned
char
*
)
"
\x56\xf3\x3d\x4f\xdb\xb9\xa5\xb6\x4d\x26\x23\x44
"
"
\x97\xe9\xdc\xb8\x77\x98\xc6\x8d\x08\xf7\xc4\x11
"
"
\x99\xd4\xbd\xdf\x97\xeb\xbf\x6c\xb5\x55\x0e\x5d
"
"
\x14\x9f\xf4\xd5\xbd\x0f\x05\xf2\x5a\x69\x88\xc1
"
"
\x74\x36\x39\x62\x27\x18\x4a\xf8\x4a\x56\x43\x35
"
"
\x65\x8e\x2f\x85\x72\xbe\xa3\x33\xee\xe2\xab\xff
"
"
\x22\xff\xa6\xde\x3e\x22\xac\xa2
"
,
/* .expectedlen = */
80
,
/* .entropyreseed = */
(
unsigned
char
*
)
"
\x72\xd2\x8c\x90\x8e\xda\xf9\xa4\xd1\xe5\x26\xd8
"
"
\xf2\xde\xd5\x44
"
,
/* .entropyreseed_len = */
16
,
/* .addtl_reseed = */
NULL
,
/* .addtl_reseed_len = */
0
},
{
/* .flags = */
"sha1"
/* DRBG_NOPR_HASHSHA1 */
,
/* .entropy = */
(
unsigned
char
*
)
"
\xd9\xba\xb5\xce\xdc\xa9\x6f\x61\x78\xd6\x45\x09
"
"
\xa0\xdf\xdc\x5e\xda\xd8\x98\x94\x14\x45\x0e\x01
"
,
/* .entropylen = */
24
,
/* .entpra = */
NULL
,
/* .entprb = */
NULL
,
/* .entprlen = */
0
,
/* .addtla = */
(
unsigned
char
*
)
"
\x04\xfa\x28\x95\xaa\x5a\x6f\x8c\x57\x43\x34\x3b
"
"
\x80\x5e\x5e\xa4
"
,
/* .addtlb = */
(
unsigned
char
*
)
"
\xdf\x5d\xc4\x59\xdf\xf0\x2a\xa2\xf0\x52\xd7\x21
"
"
\xec\x60\x72\x30
"
,
/* .addtllen = */
16
,
/* .pers = */
NULL
,
/* .perslen = */
0
,
/* .expected = */
(
unsigned
char
*
)
"
\xc4\x8b\x89\xf9\xda\x3f\x74\x82\x45\x55\x5d\x5d
"
"
\x03\x3b\x69\x3d\xd7\x1a\x4d\xf5\x69\x02\x05\xce
"
"
\xfc\xd7\x20\x11\x3c\xc2\x4e\x09\x89\x36\xff\x5e
"
"
\x77\xb5\x41\x53\x58\x70\xb3\x39\x46\x8c\xdd\x8d
"
"
\x6f\xaf\x8c\x56\x16\x3a\x70\x0a\x75\xb2\x3e\x59
"
"
\x9b\x5a\xec\xf1\x6f\x3b\xaf\x6d\x5f\x24\x19\x97
"
"
\x1f\x24\xf4\x46\x72\x0f\xea\xbe
"
,
/* .expectedlen = */
80
,
/* .entropyreseed = */
(
unsigned
char
*
)
"
\xc6\xba\xd0\x74\xc5\x90\x67\x86\xf5\xe1\xf3\x20
"
"
\x99\xf5\xb4\x91
"
,
/* .entropyreseed_len = */
16
,
/* .addtl_reseed = */
(
unsigned
char
*
)
"
\x3e\x6b\xf4\x6f\x4d\xaa\x38\x25\xd7\x19\x4e\x69
"
"
\x4e\x77\x52\xf7
"
,
/* .addtl_reseed_len = */
16
}
};
/*
* Tests implement the CAVS test approach as documented in
* http://csrc.nist.gov/groups/STM/cavp/documents/drbg/DRBGVS.pdf
*/
/*
* CAVS test
*
* This function is not static as it is needed for as a private API
* call for the CAVS test tool.
*/
gpg_err_code_t
_gcry_rngdrbg_cavs_test
(
struct
gcry_drbg_test_vector
*
test
,
unsigned
char
*
buf
)
{
gpg_err_code_t
ret
=
0
;
drbg_state_t
drbg
=
NULL
;
struct
drbg_test_data_s
test_data
;
drbg_string_t
addtl
,
pers
,
testentropy
;
int
coreref
=
0
;
int
pr
=
0
;
u32
flags
;
ret
=
parse_flag_string
(
test
->
flagstr
,
&
flags
);
if
(
ret
)
goto
outbuf
;
ret
=
drbg_algo_available
(
flags
,
&
coreref
);
if
(
ret
)
goto
outbuf
;
drbg
=
xtrycalloc_secure
(
1
,
sizeof
*
drbg
);
if
(
!
drbg
)
{
ret
=
gpg_err_code_from_syserror
();
goto
outbuf
;
}
if
((
flags
&
DRBG_PREDICTION_RESIST
))
pr
=
1
;
test_data
.
testentropy
=
&
testentropy
;
drbg_string_fill
(
&
testentropy
,
test
->
entropy
,
test
->
entropylen
);
drbg
->
test_data
=
&
test_data
;
drbg_string_fill
(
&
pers
,
test
->
pers
,
test
->
perslen
);
ret
=
drbg_instantiate
(
drbg
,
&
pers
,
coreref
,
pr
);
if
(
ret
)
goto
outbuf
;
if
(
test
->
entropyreseed
)
{
drbg_string_fill
(
&
testentropy
,
test
->
entropyreseed
,
test
->
entropyreseed_len
);
drbg_string_fill
(
&
addtl
,
test
->
addtl_reseed
,
test
->
addtl_reseed_len
);
if
(
drbg_reseed
(
drbg
,
&
addtl
))
goto
outbuf
;
}
drbg_string_fill
(
&
addtl
,
test
->
addtla
,
test
->
addtllen
);
if
(
test
->
entpra
)
{
drbg_string_fill
(
&
testentropy
,
test
->
entpra
,
test
->
entprlen
);
drbg
->
test_data
=
&
test_data
;
}
drbg_generate_long
(
drbg
,
buf
,
test
->
expectedlen
,
&
addtl
);
drbg_string_fill
(
&
addtl
,
test
->
addtlb
,
test
->
addtllen
);
if
(
test
->
entprb
)
{
drbg_string_fill
(
&
testentropy
,
test
->
entprb
,
test
->
entprlen
);
drbg
->
test_data
=
&
test_data
;
}
drbg_generate_long
(
drbg
,
buf
,
test
->
expectedlen
,
&
addtl
);
drbg_uninstantiate
(
drbg
);
outbuf
:
xfree
(
drbg
);
return
ret
;
}
/*
* Invoke the CAVS test and perform the final check whether the
* calculated random value matches the expected one.
*
* This function is not static as it is needed for as a private API
* call for the CAVS test tool.
*/
gpg_err_code_t
_gcry_rngdrbg_healthcheck_one
(
struct
gcry_drbg_test_vector
*
test
)
{
gpg_err_code_t
ret
=
GPG_ERR_ENOMEM
;
unsigned
char
*
buf
=
xcalloc_secure
(
1
,
test
->
expectedlen
);
if
(
!
buf
)
return
GPG_ERR_ENOMEM
;
ret
=
_gcry_rngdrbg_cavs_test
(
test
,
buf
);
/* FIXME: The next line is wrong. */
ret
=
memcmp
(
test
->
expected
,
buf
,
test
->
expectedlen
);
xfree
(
buf
);
return
ret
;
}
/*
* Tests as defined in 11.3.2 in addition to the cipher tests: testing
* of the error handling.
*
* Note, testing the reseed counter is not done as an automatic reseeding
* is performed in drbg_generate when the reseed counter is too large.
*/
static
gpg_err_code_t
drbg_healthcheck_sanity
(
struct
gcry_drbg_test_vector
*
test
)
{
unsigned
int
len
=
0
;
drbg_state_t
drbg
=
NULL
;
gpg_err_code_t
ret
=
GPG_ERR_GENERAL
;
gpg_err_code_t
tmpret
=
GPG_ERR_GENERAL
;
struct
drbg_test_data_s
test_data
;
drbg_string_t
addtl
,
testentropy
;
int
coreref
=
0
;
unsigned
char
*
buf
=
NULL
;
size_t
max_addtllen
,
max_request_bytes
;
u32
flags
;
/* only perform test in FIPS mode */
if
(
0
==
fips_mode
())
return
0
;
ret
=
parse_flag_string
(
test
->
flagstr
,
&
flags
);
if
(
ret
)
return
ret
;
ret
=
GPG_ERR_GENERAL
;
/* Fixme: Improve handling of RET. */
buf
=
xtrycalloc_secure
(
1
,
test
->
expectedlen
);
if
(
!
buf
)
return
gpg_err_code_from_syserror
();
tmpret
=
drbg_algo_available
(
flags
,
&
coreref
);
if
(
tmpret
)
goto
outbuf
;
drbg
=
xtrycalloc_secure
(
1
,
sizeof
*
drbg
);
if
(
!
drbg
)
{
ret
=
gpg_err_code_from_syserror
();
goto
outbuf
;
}
/* if the following tests fail, it is likely that there is a buffer
* overflow and we get a SIGSEV */
ret
=
drbg_instantiate
(
drbg
,
NULL
,
coreref
,
1
);
if
(
ret
)
goto
outbuf
;
max_addtllen
=
drbg_max_addtl
();
max_request_bytes
=
drbg_max_request_bytes
();
/* overflow addtllen with additional info string */
drbg_string_fill
(
&
addtl
,
test
->
addtla
,
(
max_addtllen
+
1
));
len
=
drbg_generate
(
drbg
,
buf
,
test
->
expectedlen
,
&
addtl
);
if
(
len
)
goto
outdrbg
;
/* overflow max_bits */
len
=
drbg_generate
(
drbg
,
buf
,
(
max_request_bytes
+
1
),
NULL
);
if
(
len
)
goto
outdrbg
;
drbg_uninstantiate
(
drbg
);
/* test failing entropy source as defined in 11.3.2 */
test_data
.
testentropy
=
NULL
;
test_data
.
fail_seed_source
=
1
;
drbg
->
test_data
=
&
test_data
;
tmpret
=
drbg_instantiate
(
drbg
,
NULL
,
coreref
,
0
);
if
(
!
tmpret
)
goto
outdrbg
;
test_data
.
fail_seed_source
=
0
;
test_data
.
testentropy
=
&
testentropy
;
drbg_string_fill
(
&
testentropy
,
test
->
entropy
,
test
->
entropylen
);
/* overflow max addtllen with personalization string */
tmpret
=
drbg_instantiate
(
drbg
,
&
addtl
,
coreref
,
0
);
if
(
!
tmpret
)
goto
outdrbg
;
dbg
((
"DRBG: Sanity tests for failure code paths successfully completed
\n
"
));
ret
=
0
;
outdrbg
:
drbg_uninstantiate
(
drbg
);
outbuf
:
xfree
(
buf
);
xfree
(
drbg
);
return
ret
;
}
/*
* DRBG Healthcheck function as required in SP800-90A
*
* return:
* 0 on success (all tests pass)
* >0 on error (return code indicate the number of failures)
*/
static
int
drbg_healthcheck
(
void
)
{
int
ret
=
0
;
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_nopr
[
0
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_nopr
[
1
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_nopr
[
2
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_nopr
[
3
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_nopr
[
4
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_pr
[
0
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_pr
[
1
]);
ret
+=
_gcry_rngdrbg_healthcheck_one
(
&
drbg_test_pr
[
2
]);
ret
+=
drbg_healthcheck_sanity
(
&
drbg_test_nopr
[
0
]);
return
ret
;
}
/* Run the self-tests. */
gcry_error_t
_gcry_rngdrbg_selftest
(
selftest_report_func_t
report
)
{
gcry_err_code_t
ec
;
const
char
*
errtxt
=
NULL
;
drbg_lock
();
if
(
0
!=
drbg_healthcheck
())
errtxt
=
"RNG output does not match known value"
;
drbg_unlock
();
if
(
report
&&
errtxt
)
report
(
"random"
,
0
,
"KAT"
,
errtxt
);
ec
=
errtxt
?
GPG_ERR_SELFTEST_FAILED
:
0
;
return
gpg_error
(
ec
);
}
/***************************************************************
* Cipher invocations requested by DRBG
***************************************************************/
static
gpg_err_code_t
drbg_hash_init
(
drbg_state_t
drbg
)
{
gcry_md_hd_t
hd
;
gpg_error_t
err
;
err
=
_gcry_md_open
(
&
hd
,
drbg
->
core
->
backend_cipher
,
0
);
if
(
err
)
return
err
;
drbg
->
priv_data
=
hd
;
return
0
;
}
static
gpg_err_code_t
drbg_hmac_init
(
drbg_state_t
drbg
)
{
gcry_md_hd_t
hd
;
gpg_error_t
err
;
err
=
_gcry_md_open
(
&
hd
,
drbg
->
core
->
backend_cipher
,
GCRY_MD_FLAG_HMAC
);
if
(
err
)
return
err
;
drbg
->
priv_data
=
hd
;
return
0
;
}
static
gpg_err_code_t
drbg_hmac_setkey
(
drbg_state_t
drbg
,
const
unsigned
char
*
key
)
{
gcry_md_hd_t
hd
=
(
gcry_md_hd_t
)
drbg
->
priv_data
;
return
_gcry_md_setkey
(
hd
,
key
,
drbg_statelen
(
drbg
));
}
static
void
drbg_hash_fini
(
drbg_state_t
drbg
)
{
gcry_md_hd_t
hd
=
(
gcry_md_hd_t
)
drbg
->
priv_data
;
_gcry_md_close
(
hd
);
}
static
byte
*
drbg_hash
(
drbg_state_t
drbg
,
const
drbg_string_t
*
buf
)
{
gcry_md_hd_t
hd
=
(
gcry_md_hd_t
)
drbg
->
priv_data
;
_gcry_md_reset
(
hd
);
for
(;
NULL
!=
buf
;
buf
=
buf
->
next
)
_gcry_md_write
(
hd
,
buf
->
buf
,
buf
->
len
);
_gcry_md_final
(
hd
);
return
_gcry_md_read
(
hd
,
drbg
->
core
->
backend_cipher
);
}
static
void
drbg_sym_fini
(
drbg_state_t
drbg
)
{
gcry_cipher_hd_t
hd
=
(
gcry_cipher_hd_t
)
drbg
->
priv_data
;
if
(
hd
)
_gcry_cipher_close
(
hd
);
if
(
drbg
->
ctr_handle
)
_gcry_cipher_close
(
drbg
->
ctr_handle
);
if
(
drbg
->
ctr_null
)
free
(
drbg
->
ctr_null
);
}
static
gpg_err_code_t
drbg_sym_init
(
drbg_state_t
drbg
)
{
gcry_cipher_hd_t
hd
;
gpg_error_t
err
;
drbg
->
ctr_null
=
calloc
(
1
,
DRBG_CTR_NULL_LEN
);
if
(
!
drbg
->
ctr_null
)
return
GPG_ERR_ENOMEM
;
err
=
_gcry_cipher_open
(
&
hd
,
drbg
->
core
->
backend_cipher
,
GCRY_CIPHER_MODE_ECB
,
0
);
if
(
err
)
{
drbg_sym_fini
(
drbg
);
return
err
;
}
drbg
->
priv_data
=
hd
;
err
=
_gcry_cipher_open
(
&
drbg
->
ctr_handle
,
drbg
->
core
->
backend_cipher
,
GCRY_CIPHER_MODE_CTR
,
0
);
if
(
err
)
{
drbg_sym_fini
(
drbg
);
return
err
;
}
if
(
drbg_blocklen
(
drbg
)
!=
_gcry_cipher_get_algo_blklen
(
drbg
->
core
->
backend_cipher
))
{
drbg_sym_fini
(
drbg
);
return
-
GPG_ERR_NO_ERROR
;
}
return
0
;
}
static
gpg_err_code_t
drbg_sym_setkey
(
drbg_state_t
drbg
,
const
unsigned
char
*
key
)
{
gcry_cipher_hd_t
hd
=
(
gcry_cipher_hd_t
)
drbg
->
priv_data
;
return
_gcry_cipher_setkey
(
hd
,
key
,
drbg_keylen
(
drbg
));
}
static
gpg_err_code_t
drbg_sym
(
drbg_state_t
drbg
,
unsigned
char
*
outval
,
const
drbg_string_t
*
buf
)
{
gcry_cipher_hd_t
hd
=
(
gcry_cipher_hd_t
)
drbg
->
priv_data
;
_gcry_cipher_reset
(
hd
);
if
(
drbg_blocklen
(
drbg
)
<
buf
->
len
)
return
-
GPG_ERR_NO_ERROR
;
/* in is only component */
return
_gcry_cipher_encrypt
(
hd
,
outval
,
drbg_blocklen
(
drbg
),
buf
->
buf
,
buf
->
len
);
}
static
gpg_err_code_t
drbg_sym_ctr
(
drbg_state_t
drbg
,
const
unsigned
char
*
inbuf
,
unsigned
int
inbuflen
,
unsigned
char
*
outbuf
,
unsigned
int
outbuflen
)
{
gpg_error_t
err
;
_gcry_cipher_reset
(
drbg
->
ctr_handle
);
err
=
_gcry_cipher_setctr
(
drbg
->
ctr_handle
,
drbg
->
V
,
drbg_blocklen
(
drbg
));
if
(
err
)
return
err
;
while
(
outbuflen
)
{
unsigned
int
cryptlen
=
(
inbuflen
>
outbuflen
)
?
outbuflen
:
inbuflen
;
err
=
_gcry_cipher_encrypt
(
drbg
->
ctr_handle
,
outbuf
,
cryptlen
,
inbuf
,
cryptlen
);
if
(
err
)
return
err
;
outbuflen
-=
cryptlen
;
outbuf
+=
cryptlen
;
}
return
_gcry_cipher_getctr
(
drbg
->
ctr_handle
,
drbg
->
V
,
drbg_blocklen
(
drbg
));
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Apr 14, 9:22 PM (3 h, 47 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
fd/7d/8722d3a6cf02242389e7f5448290
Attached To
rC libgcrypt
Event Timeline
Log In to Comment