diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index 17816ef9..e3daf53b 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -1,1311 +1,1313 @@
/* pubkey-util.c - Supporting functions for all pubkey modules.
* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
* 2007, 2008, 2011 Free Software Foundation, Inc.
* Copyright (C) 2013, 2015 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
*/
#include
#include
#include
#include
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "pubkey-internal.h"
/* Callback for the pubkey algorithm code to verify PSS signatures.
OPAQUE is the data provided by the actual caller. The meaning of
TMP depends on the actual algorithm (but there is only RSA); now
for RSA it is the output of running the public key function on the
input. */
static int
pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
{
struct pk_encoding_ctx *ctx = opaque;
gcry_mpi_t value = ctx->verify_arg;
return _gcry_rsa_pss_verify (value, !(ctx->flags & PUBKEY_FLAG_PREHASH),
tmp, ctx->nbits - 1,
ctx->hash_algo, ctx->saltlen);
}
/* Parser for a flag list. On return the encoding is stored at
R_ENCODING and the flags are stored at R_FLAGS. If any of them is
not needed, NULL may be passed. The function returns 0 on success
or an error code. */
gpg_err_code_t
_gcry_pk_util_parse_flaglist (gcry_sexp_t list,
int *r_flags, enum pk_encoding *r_encoding)
{
gpg_err_code_t rc = 0;
const char *s;
size_t n;
int i;
int encoding = PUBKEY_ENC_UNKNOWN;
int flags = 0;
int igninvflag = 0;
for (i = list ? sexp_length (list)-1 : 0; i > 0; i--)
{
s = sexp_nth_data (list, i, &n);
if (!s)
continue; /* Not a data element. */
switch (n)
{
case 3:
if (!memcmp (s, "pss", 3) && encoding == PUBKEY_ENC_UNKNOWN)
{
encoding = PUBKEY_ENC_PSS;
flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if (!memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN)
{
encoding = PUBKEY_ENC_RAW;
flags |= PUBKEY_FLAG_RAW_FLAG; /* Explicitly given. */
}
else if (!memcmp (s, "sm2", 3))
{
encoding = PUBKEY_ENC_RAW;
flags |= PUBKEY_FLAG_SM2 | PUBKEY_FLAG_RAW_FLAG;
}
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 4:
if (!memcmp (s, "comp", 4))
flags |= PUBKEY_FLAG_COMP;
else if (!memcmp (s, "oaep", 4) && encoding == PUBKEY_ENC_UNKNOWN)
{
encoding = PUBKEY_ENC_OAEP;
flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if (!memcmp (s, "gost", 4))
{
encoding = PUBKEY_ENC_RAW;
flags |= PUBKEY_FLAG_GOST;
}
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 5:
if (!memcmp (s, "eddsa", 5))
{
encoding = PUBKEY_ENC_RAW;
flags |= PUBKEY_FLAG_EDDSA;
flags |= PUBKEY_FLAG_DJB_TWEAK;
}
else if (!memcmp (s, "pkcs1", 5) && encoding == PUBKEY_ENC_UNKNOWN)
{
encoding = PUBKEY_ENC_PKCS1;
flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if (!memcmp (s, "param", 5))
flags |= PUBKEY_FLAG_PARAM;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 6:
if (!memcmp (s, "nocomp", 6))
flags |= PUBKEY_FLAG_NOCOMP;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 7:
if (!memcmp (s, "rfc6979", 7))
flags |= PUBKEY_FLAG_RFC6979;
else if (!memcmp (s, "noparam", 7))
; /* Ignore - it is the default. */
else if (!memcmp (s, "prehash", 7))
flags |= PUBKEY_FLAG_PREHASH;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 8:
if (!memcmp (s, "use-x931", 8))
flags |= PUBKEY_FLAG_USE_X931;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 9:
if (!memcmp (s, "pkcs1-raw", 9) && encoding == PUBKEY_ENC_UNKNOWN)
{
encoding = PUBKEY_ENC_PKCS1_RAW;
flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if (!memcmp (s, "djb-tweak", 9))
{
encoding = PUBKEY_ENC_RAW;
flags |= PUBKEY_FLAG_DJB_TWEAK;
}
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 10:
if (!memcmp (s, "igninvflag", 10))
igninvflag = 1;
else if (!memcmp (s, "no-keytest", 10))
flags |= PUBKEY_FLAG_NO_KEYTEST;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 11:
if (!memcmp (s, "no-blinding", 11))
flags |= PUBKEY_FLAG_NO_BLINDING;
else if (!memcmp (s, "use-fips186", 11))
flags |= PUBKEY_FLAG_USE_FIPS186;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
case 13:
if (!memcmp (s, "use-fips186-2", 13))
flags |= PUBKEY_FLAG_USE_FIPS186_2;
else if (!memcmp (s, "transient-key", 13))
flags |= PUBKEY_FLAG_TRANSIENT_KEY;
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
default:
if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
}
}
if (r_flags)
*r_flags = flags;
if (r_encoding)
*r_encoding = encoding;
return rc;
}
static int
get_hash_algo (const char *s, size_t n)
{
static const struct { const char *name; int algo; } hashnames[] = {
{ "sha1", GCRY_MD_SHA1 },
{ "md5", GCRY_MD_MD5 },
{ "sha256", GCRY_MD_SHA256 },
{ "ripemd160", GCRY_MD_RMD160 },
{ "rmd160", GCRY_MD_RMD160 },
{ "sha384", GCRY_MD_SHA384 },
{ "sha512", GCRY_MD_SHA512 },
{ "sha224", GCRY_MD_SHA224 },
{ "md2", GCRY_MD_MD2 },
{ "md4", GCRY_MD_MD4 },
{ "tiger", GCRY_MD_TIGER },
{ "haval", GCRY_MD_HAVAL },
{ "sha3-224", GCRY_MD_SHA3_224 },
{ "sha3-256", GCRY_MD_SHA3_256 },
{ "sha3-384", GCRY_MD_SHA3_384 },
{ "sha3-512", GCRY_MD_SHA3_512 },
{ "sm3", GCRY_MD_SM3 },
{ "shake128", GCRY_MD_SHAKE128 },
{ "shake256", GCRY_MD_SHAKE256 },
+ { "sha512-224", GCRY_MD_SHA512_224 },
+ { "sha512-256", GCRY_MD_SHA512_256 },
{ NULL, 0 }
};
int algo;
int i;
for (i=0; hashnames[i].name; i++)
{
if ( strlen (hashnames[i].name) == n
&& !memcmp (hashnames[i].name, s, n))
break;
}
if (hashnames[i].name)
algo = hashnames[i].algo;
else
{
/* In case of not listed or dynamically allocated hash
algorithm we fall back to this somewhat slower
method. Further, it also allows to use OIDs as
algorithm names. */
char *tmpname;
tmpname = xtrymalloc (n+1);
if (!tmpname)
algo = 0; /* Out of core - silently give up. */
else
{
memcpy (tmpname, s, n);
tmpname[n] = 0;
algo = _gcry_md_map_name (tmpname);
xfree (tmpname);
}
}
return algo;
}
/* Get the "nbits" parameter from an s-expression of the format:
*
* (algo
* (parameter_name_1 ....)
* ....
* (parameter_name_n ....))
*
* Example:
*
* (rsa
* (nbits 4:2048))
*
* On success the value for nbits is stored at R_NBITS. If no nbits
* parameter is found, the function returns success and stores 0 at
* R_NBITS. For parsing errors the function returns an error code and
* stores 0 at R_NBITS.
*/
gpg_err_code_t
_gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits)
{
char buf[50];
const char *s;
size_t n;
*r_nbits = 0;
list = sexp_find_token (list, "nbits", 0);
if (!list)
return 0; /* No NBITS found. */
s = sexp_nth_data (list, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
/* NBITS given without a cdr. */
sexp_release (list);
return GPG_ERR_INV_OBJ;
}
memcpy (buf, s, n);
buf[n] = 0;
*r_nbits = (unsigned int)strtoul (buf, NULL, 0);
sexp_release (list);
return 0;
}
/* Get the optional "rsa-use-e" parameter from an s-expression of the
* format:
*
* (algo
* (parameter_name_1 ....)
* ....
* (parameter_name_n ....))
*
* Example:
*
* (rsa
* (nbits 4:2048)
* (rsa-use-e 2:41))
*
* On success the value for nbits is stored at R_E. If no rsa-use-e
* parameter is found, the function returns success and stores 65537 at
* R_E. For parsing errors the function returns an error code and
* stores 0 at R_E.
*/
gpg_err_code_t
_gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e)
{
char buf[50];
const char *s;
size_t n;
*r_e = 0;
list = sexp_find_token (list, "rsa-use-e", 0);
if (!list)
{
*r_e = 65537; /* Not given, use the value generated by old versions. */
return 0;
}
s = sexp_nth_data (list, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
/* No value or value too large. */
sexp_release (list);
return GPG_ERR_INV_OBJ;
}
memcpy (buf, s, n);
buf[n] = 0;
*r_e = strtoul (buf, NULL, 0);
sexp_release (list);
return 0;
}
/* Parse a "sig-val" s-expression and store the inner parameter list at
R_PARMS. ALGO_NAMES is used to verify that the algorithm in
"sig-val" is valid. Returns 0 on success and stores a new list at
R_PARMS which must be freed by the caller. On error R_PARMS is set
to NULL and an error code returned. If R_ECCFLAGS is not NULL flag
values are set into it; as of now they are only used with ecc
algorithms. */
gpg_err_code_t
_gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names,
gcry_sexp_t *r_parms, int *r_eccflags)
{
gpg_err_code_t rc;
gcry_sexp_t l1 = NULL;
gcry_sexp_t l2 = NULL;
char *name = NULL;
int i;
*r_parms = NULL;
if (r_eccflags)
*r_eccflags = 0;
/* Extract the signature value. */
l1 = sexp_find_token (s_sig, "sig-val", 0);
if (!l1)
{
rc = GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
goto leave;
}
l2 = sexp_nth (l1, 1);
if (!l2)
{
rc = GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
goto leave;
}
name = sexp_nth_string (l2, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
else if (!strcmp (name, "flags"))
{
/* Skip a "flags" parameter and look again for the algorithm
name. This is not used but here just for the sake of
consistent S-expressions we need to handle it. */
sexp_release (l2);
l2 = sexp_nth (l1, 2);
if (!l2)
{
rc = GPG_ERR_INV_OBJ;
goto leave;
}
xfree (name);
name = sexp_nth_string (l2, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
}
for (i=0; algo_names[i]; i++)
if (!stricmp (name, algo_names[i]))
break;
if (!algo_names[i])
{
rc = GPG_ERR_CONFLICT; /* "sig-val" uses an unexpected algo. */
goto leave;
}
if (r_eccflags)
{
if (!strcmp (name, "eddsa"))
*r_eccflags = PUBKEY_FLAG_EDDSA;
if (!strcmp (name, "gost"))
*r_eccflags = PUBKEY_FLAG_GOST;
if (!strcmp (name, "sm2"))
*r_eccflags = PUBKEY_FLAG_SM2;
}
*r_parms = l2;
l2 = NULL;
rc = 0;
leave:
xfree (name);
sexp_release (l2);
sexp_release (l1);
return rc;
}
/* Parse a "enc-val" s-expression and store the inner parameter list
at R_PARMS. ALGO_NAMES is used to verify that the algorithm in
"enc-val" is valid. Returns 0 on success and stores a new list at
R_PARMS which must be freed by the caller. On error R_PARMS is set
to NULL and an error code returned. If R_ECCFLAGS is not NULL flag
values are set into it; as of now they are only used with ecc
algorithms.
(enc-val
[(flags [raw, pkcs1, oaep, no-blinding])]
[(hash-algo )]
[(label )]
(
( )
...
( )))
HASH-ALGO and LABEL are specific to OAEP. CTX will be updated with
encoding information. */
gpg_err_code_t
_gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names,
gcry_sexp_t *r_parms,
struct pk_encoding_ctx *ctx)
{
gcry_err_code_t rc = 0;
gcry_sexp_t l1 = NULL;
gcry_sexp_t l2 = NULL;
char *name = NULL;
size_t n;
int parsed_flags = 0;
int i;
*r_parms = NULL;
/* Check that the first element is valid. */
l1 = sexp_find_token (sexp, "enc-val" , 0);
if (!l1)
{
rc = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */
goto leave;
}
l2 = sexp_nth (l1, 1);
if (!l2)
{
rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */
goto leave;
}
/* Extract identifier of sublist. */
name = sexp_nth_string (l2, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
if (!strcmp (name, "flags"))
{
const char *s;
/* There is a flags element - process it. */
rc = _gcry_pk_util_parse_flaglist (l2, &parsed_flags, &ctx->encoding);
if (rc)
goto leave;
if (ctx->encoding == PUBKEY_ENC_PSS)
{
rc = GPG_ERR_CONFLICT;
goto leave;
}
/* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
if (ctx->encoding == PUBKEY_ENC_OAEP)
{
/* Get HASH-ALGO. */
sexp_release (l2);
l2 = sexp_find_token (l1, "hash-algo", 0);
if (l2)
{
s = sexp_nth_data (l2, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
if (rc)
goto leave;
}
/* Get LABEL. */
sexp_release (l2);
l2 = sexp_find_token (l1, "label", 0);
if (l2)
{
s = sexp_nth_data (l2, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = xtrymalloc (n);
if (!ctx->label)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
if (rc)
goto leave;
}
}
/* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
for (i = 2; (sexp_release (l2), l2 = sexp_nth (l1, i)); i++)
{
s = sexp_nth_data (l2, 0, &n);
if (!(n == 9 && !memcmp (s, "hash-algo", 9))
&& !(n == 5 && !memcmp (s, "label", 5))
&& !(n == 15 && !memcmp (s, "random-override", 15)))
break;
}
if (!l2)
{
rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */
goto leave;
}
/* Extract sublist identifier. */
xfree (name);
name = sexp_nth_string (l2, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
}
else /* No flags - flag as legacy structure. */
parsed_flags |= PUBKEY_FLAG_LEGACYRESULT;
for (i=0; algo_names[i]; i++)
if (!stricmp (name, algo_names[i]))
break;
if (!algo_names[i])
{
rc = GPG_ERR_CONFLICT; /* "enc-val" uses an unexpected algo. */
goto leave;
}
*r_parms = l2;
l2 = NULL;
ctx->flags |= parsed_flags;
rc = 0;
leave:
xfree (name);
sexp_release (l2);
sexp_release (l1);
return rc;
}
/* Initialize an encoding context. */
void
_gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx,
enum pk_operation op,
unsigned int nbits)
{
ctx->op = op;
ctx->nbits = nbits;
ctx->encoding = PUBKEY_ENC_UNKNOWN;
ctx->flags = 0;
if (fips_mode ())
{
ctx->hash_algo = GCRY_MD_SHA256;
}
else
{
ctx->hash_algo = GCRY_MD_SHA1;
}
ctx->label = NULL;
ctx->labellen = 0;
ctx->saltlen = 20;
ctx->verify_cmp = NULL;
ctx->verify_arg = NULL;
}
/* Free a context initialzied by _gcry_pk_util_init_encoding_ctx. */
void
_gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx)
{
xfree (ctx->label);
}
/* Take the hash value and convert into an MPI, suitable for
passing to the low level functions. We currently support the
old style way of passing just a MPI and the modern interface which
allows to pass flags so that we can choose between raw and pkcs1
padding - may be more padding options later.
()
or
(data
[(flags [raw, direct, pkcs1, oaep, pss,
no-blinding, rfc6979, eddsa, prehash])]
[(hash )]
[(value )]
[(hash-algo )]
[(label )]
[(salt-length )]
[(random-override )]
)
Either the VALUE or the HASH element must be present for use
with signatures. VALUE is used for encryption.
HASH-ALGO is specific to OAEP, PSS and EDDSA.
LABEL is specific to OAEP.
SALT-LENGTH is for PSS, it is limited to 16384 bytes.
RANDOM-OVERRIDE is used to replace random nonces for regression
testing. */
gcry_err_code_t
_gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
struct pk_encoding_ctx *ctx)
{
gcry_err_code_t rc = 0;
gcry_sexp_t ldata, lhash, lvalue;
size_t n;
const char *s;
int unknown_flag = 0;
int parsed_flags = 0;
*ret_mpi = NULL;
ldata = sexp_find_token (input, "data", 0);
if (!ldata)
{ /* assume old style */
int mpifmt = (ctx->flags & PUBKEY_FLAG_RAW_FLAG) ?
GCRYMPI_FMT_OPAQUE : GCRYMPI_FMT_STD;
*ret_mpi = sexp_nth_mpi (input, 0, mpifmt);
return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
}
/* See whether there is a flags list. */
{
gcry_sexp_t lflags = sexp_find_token (ldata, "flags", 0);
if (lflags)
{
if (_gcry_pk_util_parse_flaglist (lflags,
&parsed_flags, &ctx->encoding))
unknown_flag = 1;
sexp_release (lflags);
}
}
if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */
/* Get HASH or MPI */
lhash = sexp_find_token (ldata, "hash", 0);
lvalue = lhash? NULL : sexp_find_token (ldata, "value", 0);
if (!(!lhash ^ !lvalue))
rc = GPG_ERR_INV_OBJ; /* none or both given */
else if (unknown_flag)
rc = GPG_ERR_INV_FLAG;
else if (ctx->encoding == PUBKEY_ENC_RAW
&& ((parsed_flags & PUBKEY_FLAG_EDDSA)
|| (ctx->flags & PUBKEY_FLAG_EDDSA)))
{
/* Prepare for EdDSA. */
gcry_sexp_t list;
void *value;
size_t valuelen;
if (!lvalue)
{
rc = GPG_ERR_INV_OBJ;
goto leave;
}
/* Hash algo is determined by curve. No hash-algo is OK. */
/* Get HASH-ALGO. */
list = sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
sexp_release (list);
}
if (rc)
goto leave;
/* Get LABEL. */
list = sexp_find_token (ldata, "label", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = xtrymalloc (n);
if (!ctx->label)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
sexp_release (list);
if (rc)
goto leave;
}
/* Get VALUE. */
value = sexp_nth_buffer (lvalue, 1, &valuelen);
if (!value)
{
/* We assume that a zero length message is meant by
"(value)". This is commonly used by test vectors. Note
that S-expression do not allow zero length items. */
valuelen = 0;
value = xtrymalloc (1);
if (!value)
rc = gpg_err_code_from_syserror ();
}
else if ((valuelen * 8) < valuelen)
{
xfree (value);
rc = GPG_ERR_TOO_LARGE;
}
if (rc)
goto leave;
/* Note that mpi_set_opaque takes ownership of VALUE. */
*ret_mpi = mpi_set_opaque (NULL, value, valuelen*8);
}
else if (ctx->encoding == PUBKEY_ENC_RAW
&& (lhash || (lvalue && (parsed_flags & PUBKEY_FLAG_PREHASH)))
&& ((parsed_flags & PUBKEY_FLAG_RAW_FLAG)
|| (parsed_flags & PUBKEY_FLAG_RFC6979)))
{
void * value;
size_t valuelen;
gcry_sexp_t list;
/* Raw encoding along with a hash element. This is commonly
used for DSA. For better backward error compatibility we
allow this only if either the rfc6979 flag has been given or
the raw flags was explicitly given. */
if (lvalue && (parsed_flags & PUBKEY_FLAG_PREHASH))
{
/* Get HASH-ALGO. */
list = sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
sexp_release (list);
if (rc)
goto leave;
}
if ( !(value=sexp_nth_buffer (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else if ((valuelen * 8) < valuelen)
{
xfree (value);
rc = GPG_ERR_TOO_LARGE;
}
else
*ret_mpi = mpi_set_opaque (NULL, value, valuelen*8);
}
else if (lhash)
{
if (sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=sexp_nth_buffer (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else if ((valuelen * 8) < valuelen)
{
xfree (value);
rc = GPG_ERR_TOO_LARGE;
}
else
*ret_mpi = mpi_set_opaque (NULL, value, valuelen*8);
}
}
else
rc = GPG_ERR_CONFLICT;
if (rc)
goto leave;
}
else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
{
/* RFC6979 may only be used with the a hash value and not the
MPI based value. */
if (parsed_flags & PUBKEY_FLAG_RFC6979)
{
rc = GPG_ERR_CONFLICT;
goto leave;
}
/* Get the value */
*ret_mpi = sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
&& ctx->op == PUBKEY_OP_ENCRYPT)
{
const void * value;
size_t valuelen;
gcry_sexp_t list;
void *random_override = NULL;
size_t random_override_len = 0;
if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
/* Get optional RANDOM-OVERRIDE. */
list = sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = xtrymalloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
sexp_release (list);
if (rc)
goto leave;
}
rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits,
value, valuelen,
random_override,
random_override_len);
xfree (random_override);
}
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1
&& (lhash || (lvalue && (parsed_flags & PUBKEY_FLAG_PREHASH)))
&& (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
{
if (lvalue && (parsed_flags & PUBKEY_FLAG_PREHASH))
{
void * value;
size_t valuelen;
gcry_sexp_t list;
/* Get HASH-ALGO. */
list = sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
sexp_release (list);
if (rc)
goto leave;
}
if ( !(value=sexp_nth_buffer (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else if ((valuelen * 8) < valuelen)
{
xfree (value);
rc = GPG_ERR_TOO_LARGE;
}
else
{
void *hash;
n = _gcry_md_get_algo_dlen (ctx->hash_algo);
hash = xtrymalloc (n);
if (!hash)
rc = gpg_err_code_from_syserror ();
else
{
_gcry_md_hash_buffer (ctx->hash_algo, hash, value, valuelen);
rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
hash, n, ctx->hash_algo);
xfree (hash);
}
}
}
else if (lhash)
{
if (sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
const void * value;
size_t valuelen;
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=sexp_nth_data (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else
rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
value, valuelen,
ctx->hash_algo);
}
}
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1_RAW && lvalue
&& (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
{
const void * value;
size_t valuelen;
if (sexp_length (lvalue) != 2)
rc = GPG_ERR_INV_OBJ;
else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else
rc = _gcry_rsa_pkcs1_encode_raw_for_sig (ret_mpi, ctx->nbits,
value, valuelen);
}
else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
&& ctx->op == PUBKEY_OP_ENCRYPT)
{
const void * value;
size_t valuelen;
if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
gcry_sexp_t list;
void *random_override = NULL;
size_t random_override_len = 0;
/* Get HASH-ALGO. */
list = sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
sexp_release (list);
if (rc)
goto leave;
}
/* Get LABEL. */
list = sexp_find_token (ldata, "label", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = xtrymalloc (n);
if (!ctx->label)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
sexp_release (list);
if (rc)
goto leave;
}
/* Get optional RANDOM-OVERRIDE. */
list = sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = xtrymalloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
sexp_release (list);
if (rc)
goto leave;
}
rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
value, valuelen,
ctx->label, ctx->labellen,
random_override, random_override_len);
xfree (random_override);
}
}
else if (ctx->encoding == PUBKEY_ENC_PSS && ctx->op == PUBKEY_OP_SIGN)
{
const void * value;
size_t valuelen;
gcry_sexp_t list;
void *random_override = NULL;
if (lvalue)
{
/* Get HASH-ALGO. */
list = sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
sexp_release (list);
if (rc)
goto leave;
}
if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
ctx->flags |= PUBKEY_FLAG_PREHASH;
}
else if (lhash)
{
if (sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=sexp_nth_data (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
}
}
else
rc = GPG_ERR_CONFLICT;
if (rc)
goto leave;
/* Get SALT-LENGTH. */
list = sexp_find_token (ldata, "salt-length", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
sexp_release (list);
}
/* Get optional RANDOM-OVERRIDE. */
list = sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n == ctx->saltlen)
{
random_override = xtrymalloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
memcpy (random_override, s, n);
}
else
rc = GPG_ERR_INV_ARG;
sexp_release (list);
if (rc)
goto leave;
}
/* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */
rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1,
ctx->hash_algo, ctx->saltlen,
!(ctx->flags & PUBKEY_FLAG_PREHASH),
value, valuelen,
random_override);
xfree (random_override);
}
else if (ctx->encoding == PUBKEY_ENC_PSS && ctx->op == PUBKEY_OP_VERIFY)
{
gcry_sexp_t list;
if (lvalue)
{
/* Get HASH-ALGO. */
list = sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
sexp_release (list);
if (rc)
goto leave;
}
*ret_mpi = sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_OPAQUE);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
ctx->flags |= PUBKEY_FLAG_PREHASH;
}
else if (lhash)
{
if (sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else
{
*ret_mpi = sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_OPAQUE);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
}
}
}
else
rc = GPG_ERR_CONFLICT;
if (rc)
goto leave;
/* Get SALT-LENGTH. */
list = sexp_find_token (ldata, "salt-length", 0);
if (list)
{
s = sexp_nth_data (list, 1, &n);
if (!s)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
if (ctx->saltlen > 16384)
rc = GPG_ERR_TOO_LARGE;
sexp_release (list);
if (rc)
goto leave;
}
ctx->verify_cmp = pss_verify_cmp;
ctx->verify_arg = *ret_mpi;
}
else
rc = GPG_ERR_CONFLICT;
leave:
sexp_release (ldata);
sexp_release (lhash);
sexp_release (lvalue);
if (!rc)
ctx->flags |= parsed_flags;
else
{
xfree (ctx->label);
ctx->label = NULL;
}
return rc;
}
diff --git a/cipher/sha512.c b/cipher/sha512.c
index 6859cf52..45291567 100644
--- a/cipher/sha512.c
+++ b/cipher/sha512.c
@@ -1,1274 +1,1284 @@
/* sha512.c - SHA384 and SHA512 hash functions
* Copyright (C) 2003, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
*/
/* Test vectors from FIPS-180-2:
*
* "abc"
* 384:
* CB00753F 45A35E8B B5A03D69 9AC65007 272C32AB 0EDED163
* 1A8B605A 43FF5BED 8086072B A1E7CC23 58BAECA1 34C825A7
* 512:
* DDAF35A1 93617ABA CC417349 AE204131 12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A
* 2192992A 274FC1A8 36BA3C23 A3FEEBBD 454D4423 643CE80E 2A9AC94F A54CA49F
*
* "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
* 384:
* 09330C33 F71147E8 3D192FC7 82CD1B47 53111B17 3B3B05D2
* 2FA08086 E3B0F712 FCC7C71A 557E2DB9 66C3E9FA 91746039
* 512:
* 8E959B75 DAE313DA 8CF4F728 14FC143F 8F7779C6 EB9F7FA1 7299AEAD B6889018
* 501D289E 4900F7E4 331B99DE C4B5433A C7D329EE B6DD2654 5E96E55B 874BE909
*
* "a" x 1000000
* 384:
* 9D0E1809 716474CB 086E834E 310A4A1C ED149E9C 00F24852
* 7972CEC5 704C2A5B 07B8B3DC 38ECC4EB AE97DDD8 7F3D8985
* 512:
* E718483D 0CE76964 4E2E42C7 BC15B463 8E1F98B1 3B204428 5632A803 AFA973EB
* DE0FF244 877EA60A 4CB0432C E577C31B EB009C5C 2C49AA2E 4EADB217 AD8CC09B
*/
#include
#include
#include "g10lib.h"
#include "bithelp.h"
#include "bufhelp.h"
#include "cipher.h"
#include "hash-common.h"
/* USE_ARM_NEON_ASM indicates whether to enable ARM NEON assembly code. */
#undef USE_ARM_NEON_ASM
#ifdef ENABLE_NEON_SUPPORT
# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \
&& defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \
&& defined(HAVE_GCC_INLINE_ASM_NEON)
# define USE_ARM_NEON_ASM 1
# endif
#endif /*ENABLE_NEON_SUPPORT*/
/* USE_ARM_ASM indicates whether to enable ARM assembly code. */
#undef USE_ARM_ASM
#if defined(__ARMEL__) && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS)
# define USE_ARM_ASM 1
#endif
/* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */
#undef USE_SSSE3
#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_SSSE3) && \
defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) && \
(defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
# define USE_SSSE3 1
#endif
/* USE_AVX indicates whether to compile with Intel AVX code. */
#undef USE_AVX
#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_AVX) && \
defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) && \
(defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
# define USE_AVX 1
#endif
/* USE_AVX2 indicates whether to compile with Intel AVX2/rorx code. */
#undef USE_AVX2
#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_AVX2) && \
defined(HAVE_GCC_INLINE_ASM_BMI2) && \
defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) && \
(defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
# define USE_AVX2 1
#endif
/* USE_SSSE3_I386 indicates whether to compile with Intel SSSE3/i386 code. */
#undef USE_SSSE3_I386
#if defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4 && __GNUC__ >= 4 && \
defined(HAVE_GCC_INLINE_ASM_SSSE3)
# define USE_SSSE3_I386 1
#endif
/* USE_PPC_CRYPTO indicates whether to enable PowerPC vector crypto
* accelerated code. */
#undef USE_PPC_CRYPTO
#ifdef ENABLE_PPC_CRYPTO_SUPPORT
# if defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \
defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC)
# if __GNUC__ >= 4
# define USE_PPC_CRYPTO 1
# endif
# endif
#endif
/* USE_S390X_CRYPTO indicates whether to enable zSeries code. */
#undef USE_S390X_CRYPTO
#if defined(HAVE_GCC_INLINE_ASM_S390X)
# define USE_S390X_CRYPTO 1
#endif /* USE_S390X_CRYPTO */
typedef struct
{
u64 h0, h1, h2, h3, h4, h5, h6, h7;
} SHA512_STATE;
typedef struct
{
gcry_md_block_ctx_t bctx;
SHA512_STATE state;
#ifdef USE_S390X_CRYPTO
u64 final_len_msb, final_len_lsb; /* needs to be right after state.h7. */
int use_s390x_crypto;
#endif
} SHA512_CONTEXT;
static const u64 k[] =
{
U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd),
U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc),
U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019),
U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118),
U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe),
U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2),
U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1),
U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694),
U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3),
U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65),
U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483),
U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5),
U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210),
U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4),
U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725),
U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70),
U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926),
U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df),
U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8),
U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b),
U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001),
U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30),
U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910),
U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8),
U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53),
U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8),
U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb),
U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3),
U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60),
U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec),
U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9),
U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b),
U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207),
U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178),
U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6),
U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b),
U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493),
U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c),
U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a),
U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817)
};
/* AMD64 assembly implementations use SystemV ABI, ABI conversion and additional
* stack to store XMM6-XMM15 needed on Win64. */
#undef ASM_FUNC_ABI
#undef ASM_EXTRA_STACK
#if defined(USE_SSSE3) || defined(USE_AVX) || defined(USE_AVX2)
# ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS
# define ASM_FUNC_ABI __attribute__((sysv_abi))
# define ASM_EXTRA_STACK (10 * 16 + 4 * sizeof(void *))
# else
# define ASM_FUNC_ABI
# define ASM_EXTRA_STACK 0
# endif
#endif
#ifdef USE_ARM_NEON_ASM
unsigned int _gcry_sha512_transform_armv7_neon (SHA512_STATE *hd,
const unsigned char *data,
const u64 k[], size_t num_blks);
static unsigned int
do_sha512_transform_armv7_neon(void *ctx, const unsigned char *data,
size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_armv7_neon (&hd->state, data, k, nblks);
}
#endif
#ifdef USE_SSSE3
unsigned int _gcry_sha512_transform_amd64_ssse3(const void *input_data,
void *state,
size_t num_blks) ASM_FUNC_ABI;
static unsigned int
do_sha512_transform_amd64_ssse3(void *ctx, const unsigned char *data,
size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_amd64_ssse3 (data, &hd->state, nblks)
+ ASM_EXTRA_STACK;
}
#endif
#ifdef USE_AVX
unsigned int _gcry_sha512_transform_amd64_avx(const void *input_data,
void *state,
size_t num_blks) ASM_FUNC_ABI;
static unsigned int
do_sha512_transform_amd64_avx(void *ctx, const unsigned char *data,
size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_amd64_avx (data, &hd->state, nblks)
+ ASM_EXTRA_STACK;
}
#endif
#ifdef USE_AVX2
unsigned int _gcry_sha512_transform_amd64_avx2(const void *input_data,
void *state,
size_t num_blks) ASM_FUNC_ABI;
static unsigned int
do_sha512_transform_amd64_avx2(void *ctx, const unsigned char *data,
size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_amd64_avx2 (data, &hd->state, nblks)
+ ASM_EXTRA_STACK;
}
#endif
#ifdef USE_SSSE3_I386
unsigned int _gcry_sha512_transform_i386_ssse3(u64 state[8],
const unsigned char *input_data,
size_t num_blks);
static unsigned int
do_sha512_transform_i386_ssse3(void *ctx, const unsigned char *data,
size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_i386_ssse3 (&hd->state.h0, data, nblks);
}
#endif
#ifdef USE_ARM_ASM
unsigned int _gcry_sha512_transform_arm (SHA512_STATE *hd,
const unsigned char *data,
const u64 k[], size_t num_blks);
static unsigned int
do_transform_generic (void *context, const unsigned char *data, size_t nblks)
{
SHA512_CONTEXT *hd = context;
return _gcry_sha512_transform_arm (&hd->state, data, k, nblks);
}
#else
static unsigned int
do_transform_generic (void *context, const unsigned char *data, size_t nblks);
#endif
#ifdef USE_PPC_CRYPTO
unsigned int _gcry_sha512_transform_ppc8(u64 state[8],
const unsigned char *input_data,
size_t num_blks);
unsigned int _gcry_sha512_transform_ppc9(u64 state[8],
const unsigned char *input_data,
size_t num_blks);
static unsigned int
do_sha512_transform_ppc8(void *ctx, const unsigned char *data, size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_ppc8 (&hd->state.h0, data, nblks);
}
static unsigned int
do_sha512_transform_ppc9(void *ctx, const unsigned char *data, size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
return _gcry_sha512_transform_ppc9 (&hd->state.h0, data, nblks);
}
#endif
#ifdef USE_S390X_CRYPTO
#include "asm-inline-s390x.h"
static unsigned int
do_sha512_transform_s390x (void *ctx, const unsigned char *data, size_t nblks)
{
SHA512_CONTEXT *hd = ctx;
kimd_execute (KMID_FUNCTION_SHA512, &hd->state.h0, data, nblks * 128);
return 0;
}
static unsigned int
do_sha512_final_s390x (void *ctx, const unsigned char *data, size_t datalen,
u64 len_msb, u64 len_lsb)
{
SHA512_CONTEXT *hd = ctx;
/* Make sure that 'final_len' is positioned at correct offset relative
* to 'state.h0'. This is because we are passing 'state.h0' pointer as start of
* parameter block to 'klmd' instruction. */
gcry_assert (offsetof (SHA512_CONTEXT, final_len_msb)
- offsetof (SHA512_CONTEXT, state.h0) == 8 * sizeof(u64));
gcry_assert (offsetof (SHA512_CONTEXT, final_len_lsb)
- offsetof (SHA512_CONTEXT, final_len_msb) == 1 * sizeof(u64));
hd->final_len_msb = len_msb;
hd->final_len_lsb = len_lsb;
klmd_execute (KMID_FUNCTION_SHA512, &hd->state.h0, data, datalen);
return 0;
}
#endif
static void
sha512_init_common (SHA512_CONTEXT *ctx, unsigned int flags)
{
unsigned int features = _gcry_get_hw_features ();
(void)flags;
(void)k;
ctx->bctx.nblocks = 0;
ctx->bctx.nblocks_high = 0;
ctx->bctx.count = 0;
ctx->bctx.blocksize_shift = _gcry_ctz(128);
/* Order of feature checks is important here; last match will be
* selected. Keep slower implementations at the top and faster at
* the bottom. */
ctx->bctx.bwrite = do_transform_generic;
#ifdef USE_ARM_NEON_ASM
if ((features & HWF_ARM_NEON) != 0)
ctx->bctx.bwrite = do_sha512_transform_armv7_neon;
#endif
#ifdef USE_SSSE3
if ((features & HWF_INTEL_SSSE3) != 0)
ctx->bctx.bwrite = do_sha512_transform_amd64_ssse3;
#endif
#ifdef USE_AVX
if ((features & HWF_INTEL_AVX) && (features & HWF_INTEL_FAST_SHLD))
ctx->bctx.bwrite = do_sha512_transform_amd64_avx;
#endif
#ifdef USE_AVX2
if ((features & HWF_INTEL_AVX2) && (features & HWF_INTEL_BMI2))
ctx->bctx.bwrite = do_sha512_transform_amd64_avx2;
#endif
#ifdef USE_PPC_CRYPTO
if ((features & HWF_PPC_VCRYPTO) != 0)
ctx->bctx.bwrite = do_sha512_transform_ppc8;
if ((features & HWF_PPC_VCRYPTO) != 0 && (features & HWF_PPC_ARCH_3_00) != 0)
ctx->bctx.bwrite = do_sha512_transform_ppc9;
#endif
#ifdef USE_SSSE3_I386
if ((features & HWF_INTEL_SSSE3) != 0)
ctx->bctx.bwrite = do_sha512_transform_i386_ssse3;
#endif
#ifdef USE_S390X_CRYPTO
ctx->use_s390x_crypto = 0;
if ((features & HWF_S390X_MSA) != 0)
{
if ((kimd_query () & km_function_to_mask (KMID_FUNCTION_SHA512)) &&
(klmd_query () & km_function_to_mask (KMID_FUNCTION_SHA512)))
{
ctx->bctx.bwrite = do_sha512_transform_s390x;
ctx->use_s390x_crypto = 1;
}
}
#endif
(void)features;
}
static void
sha512_init (void *context, unsigned int flags)
{
SHA512_CONTEXT *ctx = context;
SHA512_STATE *hd = &ctx->state;
hd->h0 = U64_C(0x6a09e667f3bcc908);
hd->h1 = U64_C(0xbb67ae8584caa73b);
hd->h2 = U64_C(0x3c6ef372fe94f82b);
hd->h3 = U64_C(0xa54ff53a5f1d36f1);
hd->h4 = U64_C(0x510e527fade682d1);
hd->h5 = U64_C(0x9b05688c2b3e6c1f);
hd->h6 = U64_C(0x1f83d9abfb41bd6b);
hd->h7 = U64_C(0x5be0cd19137e2179);
sha512_init_common (ctx, flags);
}
static void
sha384_init (void *context, unsigned int flags)
{
SHA512_CONTEXT *ctx = context;
SHA512_STATE *hd = &ctx->state;
hd->h0 = U64_C(0xcbbb9d5dc1059ed8);
hd->h1 = U64_C(0x629a292a367cd507);
hd->h2 = U64_C(0x9159015a3070dd17);
hd->h3 = U64_C(0x152fecd8f70e5939);
hd->h4 = U64_C(0x67332667ffc00b31);
hd->h5 = U64_C(0x8eb44a8768581511);
hd->h6 = U64_C(0xdb0c2e0d64f98fa7);
hd->h7 = U64_C(0x47b5481dbefa4fa4);
sha512_init_common (ctx, flags);
}
static void
sha512_256_init (void *context, unsigned int flags)
{
SHA512_CONTEXT *ctx = context;
SHA512_STATE *hd = &ctx->state;
hd->h0 = U64_C(0x22312194fc2bf72c);
hd->h1 = U64_C(0x9f555fa3c84c64c2);
hd->h2 = U64_C(0x2393b86b6f53b151);
hd->h3 = U64_C(0x963877195940eabd);
hd->h4 = U64_C(0x96283ee2a88effe3);
hd->h5 = U64_C(0xbe5e1e2553863992);
hd->h6 = U64_C(0x2b0199fc2c85b8aa);
hd->h7 = U64_C(0x0eb72ddc81c52ca2);
sha512_init_common (ctx, flags);
}
static void
sha512_224_init (void *context, unsigned int flags)
{
SHA512_CONTEXT *ctx = context;
SHA512_STATE *hd = &ctx->state;
hd->h0 = U64_C(0x8c3d37c819544da2);
hd->h1 = U64_C(0x73e1996689dcd4d6);
hd->h2 = U64_C(0x1dfab7ae32ff9c82);
hd->h3 = U64_C(0x679dd514582f9fcf);
hd->h4 = U64_C(0x0f6d2b697bd44da8);
hd->h5 = U64_C(0x77e36f7304c48942);
hd->h6 = U64_C(0x3f9d85a86a1d36c8);
hd->h7 = U64_C(0x1112e6ad91d692a1);
sha512_init_common (ctx, flags);
}
#ifndef USE_ARM_ASM
static inline u64
ROTR (u64 x, u64 n)
{
return ((x >> n) | (x << (64 - n)));
}
static inline u64
Ch (u64 x, u64 y, u64 z)
{
return ((x & y) ^ ( ~x & z));
}
static inline u64
Maj (u64 x, u64 y, u64 z)
{
return ((x & y) ^ (x & z) ^ (y & z));
}
static inline u64
Sum0 (u64 x)
{
return (ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39));
}
static inline u64
Sum1 (u64 x)
{
return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41));
}
/****************
* Transform the message W which consists of 16 64-bit-words
*/
static unsigned int
do_transform_generic (void *context, const unsigned char *data, size_t nblks)
{
SHA512_CONTEXT *ctx = context;
SHA512_STATE *hd = &ctx->state;
do
{
u64 a, b, c, d, e, f, g, h;
u64 w[16];
int t;
/* get values from the chaining vars */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
f = hd->h5;
g = hd->h6;
h = hd->h7;
for ( t = 0; t < 16; t++ )
w[t] = buf_get_be64(data + t * 8);
#define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
#define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
for (t = 0; t < 80 - 16; )
{
u64 t1, t2;
t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[0];
w[0] += S1 (w[14]) + w[9] + S0 (w[1]);
t2 = Sum0 (a) + Maj (a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[1];
w[1] += S1 (w[15]) + w[10] + S0 (w[2]);
t2 = Sum0 (h) + Maj (h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[2];
w[2] += S1 (w[0]) + w[11] + S0 (w[3]);
t2 = Sum0 (g) + Maj (g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[3];
w[3] += S1 (w[1]) + w[12] + S0 (w[4]);
t2 = Sum0 (f) + Maj (f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[4];
w[4] += S1 (w[2]) + w[13] + S0 (w[5]);
t2 = Sum0 (e) + Maj (e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[5];
w[5] += S1 (w[3]) + w[14] + S0 (w[6]);
t2 = Sum0 (d) + Maj (d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[6];
w[6] += S1 (w[4]) + w[15] + S0 (w[7]);
t2 = Sum0 (c) + Maj (c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[7];
w[7] += S1 (w[5]) + w[0] + S0 (w[8]);
t2 = Sum0 (b) + Maj (b, c, d);
e += t1;
a = t1 + t2;
t1 = h + Sum1 (e) + Ch (e, f, g) + k[t+8] + w[8];
w[8] += S1 (w[6]) + w[1] + S0 (w[9]);
t2 = Sum0 (a) + Maj (a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+9] + w[9];
w[9] += S1 (w[7]) + w[2] + S0 (w[10]);
t2 = Sum0 (h) + Maj (h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+10] + w[10];
w[10] += S1 (w[8]) + w[3] + S0 (w[11]);
t2 = Sum0 (g) + Maj (g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+11] + w[11];
w[11] += S1 (w[9]) + w[4] + S0 (w[12]);
t2 = Sum0 (f) + Maj (f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+12] + w[12];
w[12] += S1 (w[10]) + w[5] + S0 (w[13]);
t2 = Sum0 (e) + Maj (e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+13] + w[13];
w[13] += S1 (w[11]) + w[6] + S0 (w[14]);
t2 = Sum0 (d) + Maj (d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+14] + w[14];
w[14] += S1 (w[12]) + w[7] + S0 (w[15]);
t2 = Sum0 (c) + Maj (c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+15] + w[15];
w[15] += S1 (w[13]) + w[8] + S0 (w[0]);
t2 = Sum0 (b) + Maj (b, c, d);
e += t1;
a = t1 + t2;
t += 16;
}
for (; t < 80; )
{
u64 t1, t2;
t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[0];
t2 = Sum0 (a) + Maj (a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[1];
t2 = Sum0 (h) + Maj (h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[2];
t2 = Sum0 (g) + Maj (g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[3];
t2 = Sum0 (f) + Maj (f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[4];
t2 = Sum0 (e) + Maj (e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[5];
t2 = Sum0 (d) + Maj (d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[6];
t2 = Sum0 (c) + Maj (c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[7];
t2 = Sum0 (b) + Maj (b, c, d);
e += t1;
a = t1 + t2;
t1 = h + Sum1 (e) + Ch (e, f, g) + k[t+8] + w[8];
t2 = Sum0 (a) + Maj (a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+9] + w[9];
t2 = Sum0 (h) + Maj (h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+10] + w[10];
t2 = Sum0 (g) + Maj (g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+11] + w[11];
t2 = Sum0 (f) + Maj (f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+12] + w[12];
t2 = Sum0 (e) + Maj (e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+13] + w[13];
t2 = Sum0 (d) + Maj (d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+14] + w[14];
t2 = Sum0 (c) + Maj (c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+15] + w[15];
t2 = Sum0 (b) + Maj (b, c, d);
e += t1;
a = t1 + t2;
t += 16;
}
/* Update chaining vars. */
hd->h0 += a;
hd->h1 += b;
hd->h2 += c;
hd->h3 += d;
hd->h4 += e;
hd->h5 += f;
hd->h6 += g;
hd->h7 += h;
data += 128;
}
while (--nblks);
return (8 + 16) * sizeof(u64) + sizeof(u32) + 3 * sizeof(void*);
}
#endif /*!USE_ARM_ASM*/
/* The routine final terminates the computation and
* returns the digest.
* The handle is prepared for a new cycle, but adding bytes to the
* handle will the destroy the returned buffer.
* Returns: 64 bytes representing the digest. When used for sha384,
* we take the leftmost 48 of those bytes.
*/
static void
sha512_final (void *context)
{
SHA512_CONTEXT *hd = context;
unsigned int burn;
u64 t, th, msb, lsb;
byte *p;
t = hd->bctx.nblocks;
/* if (sizeof t == sizeof hd->bctx.nblocks) */
th = hd->bctx.nblocks_high;
/* else */
/* th = hd->bctx.nblocks >> 64; In case we ever use u128 */
/* multiply by 128 to make a byte count */
lsb = t << 7;
msb = (th << 7) | (t >> 57);
/* add the count */
t = lsb;
if ((lsb += hd->bctx.count) < t)
msb++;
/* multiply by 8 to make a bit count */
t = lsb;
lsb <<= 3;
msb <<= 3;
msb |= t >> 61;
if (0)
{ }
#ifdef USE_S390X_CRYPTO
else if (hd->use_s390x_crypto)
{
burn = do_sha512_final_s390x (hd, hd->bctx.buf, hd->bctx.count, msb, lsb);
}
#endif
else
{
if (hd->bctx.count < 112)
{
/* enough room */
hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */
if (hd->bctx.count < 112)
memset (&hd->bctx.buf[hd->bctx.count], 0, 112 - hd->bctx.count);
}
else
{
/* need one extra block */
hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */
if (hd->bctx.count < 128)
memset (&hd->bctx.buf[hd->bctx.count], 0, 128 - hd->bctx.count);
hd->bctx.count = 128;
_gcry_md_block_write (context, NULL, 0); /* flush */
memset (hd->bctx.buf, 0, 112); /* fill next block with zeroes */
}
/* append the 128 bit count */
buf_put_be64(hd->bctx.buf + 112, msb);
buf_put_be64(hd->bctx.buf + 120, lsb);
burn = (*hd->bctx.bwrite) (hd, hd->bctx.buf, 1);
}
p = hd->bctx.buf;
#define X(a) do { buf_put_be64(p, hd->state.h##a); p += 8; } while (0)
X (0);
X (1);
X (2);
X (3);
X (4);
X (5);
/* Note that these last two chunks are included even for SHA384.
We just ignore them. */
X (6);
X (7);
#undef X
hd->bctx.count = 0;
_gcry_burn_stack (burn);
}
static byte *
sha512_read (void *context)
{
SHA512_CONTEXT *hd = (SHA512_CONTEXT *) context;
return hd->bctx.buf;
}
/* Shortcut functions which puts the hash value of the supplied buffer iov
* into outbuf which must have a size of 64 bytes. */
static void
_gcry_sha512_hash_buffers (void *outbuf, size_t nbytes,
const gcry_buffer_t *iov, int iovcnt)
{
SHA512_CONTEXT hd;
(void)nbytes;
sha512_init (&hd, 0);
for (;iovcnt > 0; iov++, iovcnt--)
_gcry_md_block_write (&hd,
(const char*)iov[0].data + iov[0].off, iov[0].len);
sha512_final (&hd);
memcpy (outbuf, hd.bctx.buf, 64);
}
/* Shortcut functions which puts the hash value of the supplied buffer iov
* into outbuf which must have a size of 48 bytes. */
static void
_gcry_sha384_hash_buffers (void *outbuf, size_t nbytes,
const gcry_buffer_t *iov, int iovcnt)
{
SHA512_CONTEXT hd;
(void)nbytes;
sha384_init (&hd, 0);
for (;iovcnt > 0; iov++, iovcnt--)
_gcry_md_block_write (&hd,
(const char*)iov[0].data + iov[0].off, iov[0].len);
sha512_final (&hd);
memcpy (outbuf, hd.bctx.buf, 48);
}
/* Shortcut functions which puts the hash value of the supplied buffer iov
* into outbuf which must have a size of 32 bytes. */
static void
_gcry_sha512_256_hash_buffers (void *outbuf, size_t nbytes,
const gcry_buffer_t *iov, int iovcnt)
{
SHA512_CONTEXT hd;
(void)nbytes;
sha512_256_init (&hd, 0);
for (;iovcnt > 0; iov++, iovcnt--)
_gcry_md_block_write (&hd,
(const char*)iov[0].data + iov[0].off, iov[0].len);
sha512_final (&hd);
memcpy (outbuf, hd.bctx.buf, 32);
}
/* Shortcut functions which puts the hash value of the supplied buffer iov
* into outbuf which must have a size of 28 bytes. */
static void
_gcry_sha512_224_hash_buffers (void *outbuf, size_t nbytes,
const gcry_buffer_t *iov, int iovcnt)
{
SHA512_CONTEXT hd;
(void)nbytes;
sha512_224_init (&hd, 0);
for (;iovcnt > 0; iov++, iovcnt--)
_gcry_md_block_write (&hd,
(const char*)iov[0].data + iov[0].off, iov[0].len);
sha512_final (&hd);
memcpy (outbuf, hd.bctx.buf, 28);
}
/*
Self-test section.
*/
static gpg_err_code_t
selftests_sha384 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
what = "short string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA384, 0,
"abc", 3,
"\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07"
"\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed"
"\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7", 48);
if (errtxt)
goto failed;
if (extended)
{
what = "long string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA384, 0,
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112,
"\x09\x33\x0C\x33\xF7\x11\x47\xE8\x3D\x19\x2F\xC7\x82\xCD\x1B\x47"
"\x53\x11\x1B\x17\x3B\x3B\x05\xD2\x2F\xA0\x80\x86\xE3\xB0\xF7\x12"
"\xFC\xC7\xC7\x1A\x55\x7E\x2D\xB9\x66\xC3\xE9\xFA\x91\x74\x60\x39",
48);
if (errtxt)
goto failed;
what = "one million \"a\"";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA384, 1,
NULL, 0,
"\x9D\x0E\x18\x09\x71\x64\x74\xCB\x08\x6E\x83\x4E\x31\x0A\x4A\x1C"
"\xED\x14\x9E\x9C\x00\xF2\x48\x52\x79\x72\xCE\xC5\x70\x4C\x2A\x5B"
"\x07\xB8\xB3\xDC\x38\xEC\xC4\xEB\xAE\x97\xDD\xD8\x7F\x3D\x89\x85",
48);
if (errtxt)
goto failed;
}
return 0; /* Succeeded. */
failed:
if (report)
report ("digest", GCRY_MD_SHA384, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
static gpg_err_code_t
selftests_sha512 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
what = "short string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512, 0,
"abc", 3,
"\xDD\xAF\x35\xA1\x93\x61\x7A\xBA\xCC\x41\x73\x49\xAE\x20\x41\x31"
"\x12\xE6\xFA\x4E\x89\xA9\x7E\xA2\x0A\x9E\xEE\xE6\x4B\x55\xD3\x9A"
"\x21\x92\x99\x2A\x27\x4F\xC1\xA8\x36\xBA\x3C\x23\xA3\xFE\xEB\xBD"
"\x45\x4D\x44\x23\x64\x3C\xE8\x0E\x2A\x9A\xC9\x4F\xA5\x4C\xA4\x9F", 64);
if (errtxt)
goto failed;
if (extended)
{
what = "long string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512, 0,
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112,
"\x8E\x95\x9B\x75\xDA\xE3\x13\xDA\x8C\xF4\xF7\x28\x14\xFC\x14\x3F"
"\x8F\x77\x79\xC6\xEB\x9F\x7F\xA1\x72\x99\xAE\xAD\xB6\x88\x90\x18"
"\x50\x1D\x28\x9E\x49\x00\xF7\xE4\x33\x1B\x99\xDE\xC4\xB5\x43\x3A"
"\xC7\xD3\x29\xEE\xB6\xDD\x26\x54\x5E\x96\xE5\x5B\x87\x4B\xE9\x09",
64);
if (errtxt)
goto failed;
what = "one million \"a\"";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512, 1,
NULL, 0,
"\xE7\x18\x48\x3D\x0C\xE7\x69\x64\x4E\x2E\x42\xC7\xBC\x15\xB4\x63"
"\x8E\x1F\x98\xB1\x3B\x20\x44\x28\x56\x32\xA8\x03\xAF\xA9\x73\xEB"
"\xDE\x0F\xF2\x44\x87\x7E\xA6\x0A\x4C\xB0\x43\x2C\xE5\x77\xC3\x1B"
"\xEB\x00\x9C\x5C\x2C\x49\xAA\x2E\x4E\xAD\xB2\x17\xAD\x8C\xC0\x9B",
64);
if (errtxt)
goto failed;
}
return 0; /* Succeeded. */
failed:
if (report)
report ("digest", GCRY_MD_SHA512, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
static gpg_err_code_t
selftests_sha512_224 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
what = "short string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512_224, 0,
"abc", 3,
"\x46\x34\x27\x0F\x70\x7B\x6A\x54\xDA\xAE\x75\x30\x46\x08\x42\xE2"
"\x0E\x37\xED\x26\x5C\xEE\xE9\xA4\x3E\x89\x24\xAA",
28);
if (errtxt)
goto failed;
if (extended)
{
what = "long string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512_224, 0,
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112,
"\x23\xFE\xC5\xBB\x94\xD6\x0B\x23\x30\x81\x92\x64\x0B\x0C\x45\x33"
"\x35\xD6\x64\x73\x4F\xE4\x0E\x72\x68\x67\x4A\xF9",
28);
if (errtxt)
goto failed;
what = "one million \"a\"";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512_224, 1,
NULL, 0,
"\x37\xab\x33\x1d\x76\xf0\xd3\x6d\xe4\x22\xbd\x0e\xde\xb2\x2a\x28"
"\xac\xcd\x48\x7b\x7a\x84\x53\xae\x96\x5d\xd2\x87",
28);
if (errtxt)
goto failed;
}
return 0; /* Succeeded. */
failed:
if (report)
report ("digest", GCRY_MD_SHA512_224, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
static gpg_err_code_t
selftests_sha512_256 (int extended, selftest_report_func_t report)
{
const char *what;
const char *errtxt;
what = "short string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512_256, 0,
"abc", 3,
"\x53\x04\x8E\x26\x81\x94\x1E\xF9\x9B\x2E\x29\xB7\x6B\x4C\x7D\xAB"
"\xE4\xC2\xD0\xC6\x34\xFC\x6D\x46\xE0\xE2\xF1\x31\x07\xE7\xAF\x23",
32);
if (errtxt)
goto failed;
if (extended)
{
what = "long string";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512_256, 0,
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112,
"\x39\x28\xE1\x84\xFB\x86\x90\xF8\x40\xDA\x39\x88\x12\x1D\x31\xBE"
"\x65\xCB\x9D\x3E\xF8\x3E\xE6\x14\x6F\xEA\xC8\x61\xE1\x9B\x56\x3A",
32);
if (errtxt)
goto failed;
what = "one million \"a\"";
errtxt = _gcry_hash_selftest_check_one
(GCRY_MD_SHA512_256, 1,
NULL, 0,
"\x9a\x59\xa0\x52\x93\x01\x87\xa9\x70\x38\xca\xe6\x92\xf3\x07\x08"
"\xaa\x64\x91\x92\x3e\xf5\x19\x43\x94\xdc\x68\xd5\x6c\x74\xfb\x21",
32);
if (errtxt)
goto failed;
}
return 0; /* Succeeded. */
failed:
if (report)
report ("digest", GCRY_MD_SHA512_256, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
run_selftests (int algo, int extended, selftest_report_func_t report)
{
gpg_err_code_t ec;
switch (algo)
{
case GCRY_MD_SHA384:
ec = selftests_sha384 (extended, report);
break;
case GCRY_MD_SHA512:
ec = selftests_sha512 (extended, report);
break;
case GCRY_MD_SHA512_224:
ec = selftests_sha512_224 (extended, report);
break;
case GCRY_MD_SHA512_256:
ec = selftests_sha512_256 (extended, report);
break;
default:
ec = GPG_ERR_DIGEST_ALGO;
break;
}
return ec;
}
static byte sha512_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */
{
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40
};
static gcry_md_oid_spec_t oid_spec_sha512[] =
{
{ "2.16.840.1.101.3.4.2.3" },
/* PKCS#1 sha512WithRSAEncryption */
{ "1.2.840.113549.1.1.13" },
{ NULL }
};
gcry_md_spec_t _gcry_digest_spec_sha512 =
{
GCRY_MD_SHA512, {0, 1},
"SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64,
sha512_init, _gcry_md_block_write, sha512_final, sha512_read, NULL,
_gcry_sha512_hash_buffers,
sizeof (SHA512_CONTEXT),
run_selftests
};
static byte sha384_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */
{
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
0x00, 0x04, 0x30
};
static gcry_md_oid_spec_t oid_spec_sha384[] =
{
{ "2.16.840.1.101.3.4.2.2" },
/* PKCS#1 sha384WithRSAEncryption */
{ "1.2.840.113549.1.1.12" },
/* SHA384WithECDSA: RFC 7427 (A.3.3.) */
{ "1.2.840.10045.4.3.3" },
{ NULL },
};
gcry_md_spec_t _gcry_digest_spec_sha384 =
{
GCRY_MD_SHA384, {0, 1},
"SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48,
sha384_init, _gcry_md_block_write, sha512_final, sha512_read, NULL,
_gcry_sha384_hash_buffers,
sizeof (SHA512_CONTEXT),
run_selftests
};
-static byte sha512_256_asn[] = { 0x30 };
+static byte sha512_256_asn[] =
+ {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05,
+ 0x00, 0x04, 0x20
+ };
static gcry_md_oid_spec_t oid_spec_sha512_256[] =
{
{ "2.16.840.1.101.3.4.2.6" },
{ NULL },
};
gcry_md_spec_t _gcry_digest_spec_sha512_256 =
{
GCRY_MD_SHA512_256, {0, 1},
"SHA512_256", sha512_256_asn, DIM (sha512_256_asn), oid_spec_sha512_256, 32,
sha512_256_init, _gcry_md_block_write, sha512_final, sha512_read, NULL,
_gcry_sha512_256_hash_buffers,
sizeof (SHA512_CONTEXT),
run_selftests
};
-static byte sha512_224_asn[] = { 0x30 };
+static byte sha512_224_asn[] =
+ {
+ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x05,
+ 0x00, 0x04, 0x1c
+ };
static gcry_md_oid_spec_t oid_spec_sha512_224[] =
{
{ "2.16.840.1.101.3.4.2.5" },
{ NULL },
};
gcry_md_spec_t _gcry_digest_spec_sha512_224 =
{
GCRY_MD_SHA512_224, {0, 1},
"SHA512_224", sha512_224_asn, DIM (sha512_224_asn), oid_spec_sha512_224, 28,
sha512_224_init, _gcry_md_block_write, sha512_final, sha512_read, NULL,
_gcry_sha512_224_hash_buffers,
sizeof (SHA512_CONTEXT),
run_selftests
};