Changeset View
Changeset View
Standalone View
Standalone View
cipher/ecc-eddsa.c
Context not available. | |||||
malloced buffer with the encoded point is stored at R_BUFFER; the | malloced buffer with the encoded point is stored at R_BUFFER; the | ||||
length of this buffer is stored at R_BUFLEN. */ | length of this buffer is stored at R_BUFLEN. */ | ||||
static gpg_err_code_t | static gpg_err_code_t | ||||
eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen, | eddsa_encodempi (gcry_mpi_t mpi, unsigned int nbits, | ||||
unsigned char **r_buffer, unsigned int *r_buflen) | unsigned char **r_buffer, unsigned int *r_buflen) | ||||
{ | { | ||||
unsigned char *rawmpi; | unsigned char *rawmpi; | ||||
unsigned int rawmpilen; | unsigned int rawmpilen; | ||||
unsigned int minlen = (nbits%8) == 0 ? (nbits/8 + 1): (nbits+7)/8; | |||||
rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL); | rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL); | ||||
if (!rawmpi) | if (!rawmpi) | ||||
Context not available. | |||||
} | } | ||||
/* Encode (X,Y) using the EdDSA scheme. MINLEN is the required length | /* Encode (X,Y) using the EdDSA scheme. NBITS is the number of bits | ||||
in bytes for the result. If WITH_PREFIX is set the returned buffer | of the field of the curve. If WITH_PREFIX is set the returned | ||||
is prefixed with a 0x40 byte. On success 0 is returned and a | buffer is prefixed with a 0x40 byte. On success 0 is returned and | ||||
malloced buffer with the encoded point is stored at R_BUFFER; the | a malloced buffer with the encoded point is stored at R_BUFFER; the | ||||
length of this buffer is stored at R_BUFLEN. */ | length of this buffer is stored at R_BUFLEN. */ | ||||
static gpg_err_code_t | static gpg_err_code_t | ||||
eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen, | eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int nbits, | ||||
int with_prefix, | int with_prefix, | ||||
unsigned char **r_buffer, unsigned int *r_buflen) | unsigned char **r_buffer, unsigned int *r_buflen) | ||||
{ | { | ||||
unsigned char *rawmpi; | unsigned char *rawmpi; | ||||
unsigned int rawmpilen; | unsigned int rawmpilen; | ||||
int off = with_prefix? 1:0; | int off = with_prefix? 1:0; | ||||
unsigned int minlen = (nbits%8) == 0 ? (nbits/8 + 1): (nbits+7)/8; | |||||
rawmpi = _gcry_mpi_get_buffer_extra (y, minlen, off?-1:0, &rawmpilen, NULL); | rawmpi = _gcry_mpi_get_buffer_extra (y, minlen, off?-1:0, &rawmpilen, NULL); | ||||
if (!rawmpi) | if (!rawmpi) | ||||
Context not available. | |||||
rc = GPG_ERR_INTERNAL; | rc = GPG_ERR_INTERNAL; | ||||
} | } | ||||
else | else | ||||
rc = eddsa_encode_x_y (x, y, (ec->nbits+7)/8, with_prefix, r_buffer, r_buflen); | rc = eddsa_encode_x_y (x, y, ec->nbits, with_prefix, r_buffer, r_buflen); | ||||
if (!x_in) | if (!x_in) | ||||
mpi_free (x); | mpi_free (x); | ||||
Context not available. | |||||
return rc; | return rc; | ||||
} | } | ||||
rc = eddsa_encode_x_y (x, y, (nbits+7)/8, 0, &enc, &enclen); | rc = eddsa_encode_x_y (x, y, nbits, 0, &enc, &enclen); | ||||
mpi_free (x); | mpi_free (x); | ||||
mpi_free (y); | mpi_free (y); | ||||
if (rc) | if (rc) | ||||
Context not available. | |||||
} | } | ||||
static gpg_err_code_t | |||||
ecc_ed448_recover_x (gcry_mpi_t x, gcry_mpi_t y, int x_0, mpi_ec_t ec) | |||||
{ | |||||
gpg_err_code_t rc = 0; | |||||
gcry_mpi_t u, v, u3, v3, t; | |||||
static gcry_mpi_t p34; /* Hard coded (P-3)/4 */ | |||||
if (mpi_cmp (y, ec->p) >= 0) | |||||
rc = GPG_ERR_INV_OBJ; | |||||
if (!p34) | |||||
p34 = scanval ("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" | |||||
"BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); | |||||
u = mpi_new (0); | |||||
v = mpi_new (0); | |||||
u3 = mpi_new (0); | |||||
v3 = mpi_new (0); | |||||
t = mpi_new (0); | |||||
/* Compute u and v */ | |||||
/* u = y^2 */ | |||||
mpi_mulm (u, y, y, ec->p); | |||||
/* v = b*y^2 */ | |||||
mpi_mulm (v, ec->b, u, ec->p); | |||||
/* u = y^2-1 */ | |||||
mpi_sub_ui (u, u, 1); | |||||
/* v = b*y^2-1 */ | |||||
mpi_sub_ui (v, v, 1); | |||||
/* Compute sqrt(u/v) */ | |||||
/* u3 = u^3 */ | |||||
mpi_powm (u3, u, mpi_const (MPI_C_THREE), ec->p); | |||||
mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); | |||||
/* t = u^4 * u * v3 = u^5 * v^3 */ | |||||
mpi_powm (t, u, mpi_const (MPI_C_FOUR), ec->p); | |||||
mpi_mulm (t, t, u, ec->p); | |||||
mpi_mulm (t, t, v3, ec->p); | |||||
/* t = t^((p-3)/4) = (u^5 * v^3)^((p-3)/4) */ | |||||
mpi_powm (t, t, p34, ec->p); | |||||
/* x = t * u^3 * v = (u^3 * v) * (u^5 * v^3)^((p-3)/4) */ | |||||
mpi_mulm (t, t, u3, ec->p); | |||||
mpi_mulm (x, t, v, ec->p); | |||||
/* t = v * x^2 */ | |||||
mpi_mulm (t, x, x, ec->p); | |||||
mpi_mulm (t, t, v, ec->p); | |||||
if (mpi_cmp (t, u) != 0) | |||||
rc = GPG_ERR_INV_OBJ; | |||||
else | |||||
{ | |||||
if (!mpi_cmp_ui (x, 0) && x_0) | |||||
rc = GPG_ERR_INV_OBJ; | |||||
/* Choose the desired square root according to parity */ | |||||
if (mpi_test_bit (x, 0) != !!x_0) | |||||
mpi_sub (x, ec->p, x); | |||||
} | |||||
mpi_free (t); | |||||
mpi_free (u3); | |||||
mpi_free (v3); | |||||
mpi_free (v); | |||||
mpi_free (u); | |||||
return rc; | |||||
} | |||||
/* Recover X from Y and SIGN (which actually is a parity bit). */ | /* Recover X from Y and SIGN (which actually is a parity bit). */ | ||||
gpg_err_code_t | gpg_err_code_t | ||||
_gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) | _gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) | ||||
Context not available. | |||||
gcry_mpi_t u, v, v3, t; | gcry_mpi_t u, v, v3, t; | ||||
static gcry_mpi_t p58, seven; | static gcry_mpi_t p58, seven; | ||||
/* | |||||
* This routine is actually curve specific. Now, only supports | |||||
* Ed25519 and Ed448. | |||||
*/ | |||||
if (ec->dialect != ECC_DIALECT_ED25519) | if (ec->dialect != ECC_DIALECT_ED25519) | ||||
return GPG_ERR_NOT_IMPLEMENTED; | /* For now, it's only Ed448. */ | ||||
return ecc_ed448_recover_x (x, y, sign, ec); | |||||
/* It's Ed25519. */ | |||||
if (!p58) | if (!p58) | ||||
p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" | p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" | ||||
Context not available. | |||||
if (mpi_is_opaque (pk)) | if (mpi_is_opaque (pk)) | ||||
{ | { | ||||
const unsigned char *buf; | const unsigned char *buf; | ||||
unsigned int len; | |||||
len = (ctx->nbits%8) == 0 ? (ctx->nbits/8 + 1): (ctx->nbits+7)/8; | |||||
buf = mpi_get_opaque (pk, &rawmpilen); | buf = mpi_get_opaque (pk, &rawmpilen); | ||||
if (!buf) | if (!buf) | ||||
return GPG_ERR_INV_OBJ; | return GPG_ERR_INV_OBJ; | ||||
rawmpilen = (rawmpilen + 7)/8; | rawmpilen = (rawmpilen + 7)/8; | ||||
if (!(rawmpilen == (ctx->nbits+7)/8 | if (!(rawmpilen == len | ||||
|| rawmpilen == (ctx->nbits+7)/8 + 1 | || rawmpilen == len + 1 | ||||
|| rawmpilen == (ctx->nbits+7)/8 * 2 + 1)) | || rawmpilen == len * 2 + 1)) | ||||
return GPG_ERR_INV_OBJ; | return GPG_ERR_INV_OBJ; | ||||
/* Handle compression prefixes. The size of the buffer will be | /* Handle compression prefixes. The size of the buffer will be | ||||
odd in this case. */ | odd in this case. */ | ||||
if (rawmpilen > 1 && (rawmpilen%2)) | if (rawmpilen > 1 && (rawmpilen == len + 1 || rawmpilen == len * 2 + 1)) | ||||
{ | { | ||||
/* First check whether the public key has been given in | /* First check whether the public key has been given in | ||||
standard uncompressed format (SEC1). No need to recover | standard uncompressed format (SEC1). No need to recover | ||||
Context not available. | |||||
if (r_encpk) | if (r_encpk) | ||||
{ | { | ||||
rc = eddsa_encode_x_y (x, y, (ctx->nbits+7)/8, 0, | rc = eddsa_encode_x_y (x, y, ctx->nbits, 0, | ||||
r_encpk, r_encpklen); | r_encpk, r_encpklen); | ||||
if (rc) | if (rc) | ||||
{ | { | ||||
Context not available. | |||||
unsigned char *rawmpi = NULL; | unsigned char *rawmpi = NULL; | ||||
unsigned int rawmpilen; | unsigned int rawmpilen; | ||||
unsigned char *digest; | unsigned char *digest; | ||||
gcry_buffer_t hvec[2]; | |||||
int hashalgo, b; | int hashalgo, b; | ||||
*r_digest = NULL; | *r_digest = NULL; | ||||
hashalgo = GCRY_MD_SHA512; | |||||
if (hashalgo != GCRY_MD_SHA512) | |||||
return GPG_ERR_DIGEST_ALGO; | |||||
b = (ec->nbits+7)/8; | b = (ec->nbits+7)/8; | ||||
if (b != 256/8) | |||||
return GPG_ERR_INTERNAL; /* We only support 256 bit. */ | /* | ||||
* Choice of hashalgo is curve specific. | |||||
* For now, it's determine by the bit size of the field. | |||||
*/ | |||||
if (ec->nbits == 255) | |||||
hashalgo = GCRY_MD_SHA512; | |||||
else if (ec->nbits == 448) | |||||
{ | |||||
b++; | |||||
hashalgo = GCRY_MD_SHAKE256; | |||||
} | |||||
else | |||||
return GPG_ERR_NOT_IMPLEMENTED; | |||||
/* Note that we clear DIGEST so we can use it as input to left pad | /* Note that we clear DIGEST so we can use it as input to left pad | ||||
the key with zeroes for hashing. */ | the key with zeroes for hashing. */ | ||||
Context not available. | |||||
if (!digest) | if (!digest) | ||||
return gpg_err_code_from_syserror (); | return gpg_err_code_from_syserror (); | ||||
memset (hvec, 0, sizeof hvec); | |||||
rawmpi = _gcry_mpi_get_buffer (ec->d, 0, &rawmpilen, NULL); | rawmpi = _gcry_mpi_get_buffer (ec->d, 0, &rawmpilen, NULL); | ||||
if (!rawmpi) | if (!rawmpi) | ||||
{ | { | ||||
Context not available. | |||||
return gpg_err_code_from_syserror (); | return gpg_err_code_from_syserror (); | ||||
} | } | ||||
hvec[0].data = digest; | if (hashalgo == GCRY_MD_SHAKE256) | ||||
hvec[0].off = 0; | { | ||||
hvec[0].len = b > rawmpilen? b - rawmpilen : 0; | gcry_error_t err; | ||||
hvec[1].data = rawmpi; | gcry_md_hd_t hd; | ||||
hvec[1].off = 0; | |||||
hvec[1].len = rawmpilen; | err = _gcry_md_open (&hd, hashalgo, 0); | ||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); | if (err) | ||||
rc = gcry_err_code (err); | |||||
else | |||||
{ | |||||
_gcry_md_write (hd, rawmpi, rawmpilen); | |||||
_gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); | |||||
_gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); | |||||
_gcry_md_close (hd); | |||||
rc = 0; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
gcry_buffer_t hvec[2]; | |||||
memset (hvec, 0, sizeof hvec); | |||||
hvec[0].data = digest; | |||||
hvec[0].off = 0; | |||||
hvec[0].len = b > rawmpilen? b - rawmpilen : 0; | |||||
hvec[1].data = rawmpi; | |||||
hvec[1].off = 0; | |||||
hvec[1].len = rawmpilen; | |||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); | |||||
} | |||||
xfree (rawmpi); | xfree (rawmpi); | ||||
if (rc) | if (rc) | ||||
{ | { | ||||
Context not available. | |||||
} | } | ||||
/* Compute the A value. */ | /* Compute the A value. */ | ||||
reverse_buffer (digest, 32); /* Only the first half of the hash. */ | reverse_buffer (digest, b); /* Only the first half of the hash. */ | ||||
digest[0] = (digest[0] & 0x7f) | 0x40; | |||||
digest[31] &= 0xf8; | /* Field specific handling of clearing/setting bits. */ | ||||
if (ec->nbits == 255) | |||||
{ | |||||
digest[0] = (digest[0] & 0x7f) | 0x40; | |||||
digest[31] &= 0xf8; | |||||
} | |||||
else | |||||
{ | |||||
digest[0] = 0; | |||||
digest[1] |= 0x80; | |||||
digest[56] &= 0xfc; | |||||
} | |||||
*r_digest = digest; | *r_digest = digest; | ||||
return 0; | return 0; | ||||
Context not available. | |||||
gpg_err_code_t | gpg_err_code_t | ||||
_gcry_ecc_eddsa_genkey (mpi_ec_t ec, int flags) | _gcry_ecc_eddsa_genkey (mpi_ec_t ec, int flags) | ||||
{ | { | ||||
gpg_err_code_t rc; | int b; | ||||
int b = 256/8; /* The only size we currently support. */ | |||||
gcry_mpi_t a, x, y; | gcry_mpi_t a, x, y; | ||||
mpi_point_struct Q; | mpi_point_struct Q; | ||||
gcry_random_level_t random_level; | gcry_random_level_t random_level; | ||||
char *dbuf; | char *dbuf; | ||||
size_t dlen; | size_t dlen; | ||||
gcry_buffer_t hvec[1]; | |||||
unsigned char *hash_d = NULL; | unsigned char *hash_d = NULL; | ||||
point_init (&Q); | point_init (&Q); | ||||
memset (hvec, 0, sizeof hvec); | |||||
if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) | if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) | ||||
random_level = GCRY_STRONG_RANDOM; | random_level = GCRY_STRONG_RANDOM; | ||||
else | else | ||||
random_level = GCRY_VERY_STRONG_RANDOM; | random_level = GCRY_VERY_STRONG_RANDOM; | ||||
b = (ec->nbits+7)/8; | |||||
if (ec->nbits == 255) | |||||
; | |||||
else if (ec->nbits == 448) | |||||
b++; | |||||
else | |||||
return GPG_ERR_NOT_IMPLEMENTED; | |||||
dlen = b; | |||||
a = mpi_snew (0); | a = mpi_snew (0); | ||||
x = mpi_new (0); | x = mpi_new (0); | ||||
y = mpi_new (0); | y = mpi_new (0); | ||||
/* Generate a secret. */ | /* Generate a secret. */ | ||||
hash_d = xtrymalloc_secure (2*b); | |||||
if (!hash_d) | |||||
{ | |||||
rc = gpg_err_code_from_syserror (); | |||||
goto leave; | |||||
} | |||||
dlen = b; | |||||
dbuf = _gcry_random_bytes_secure (dlen, random_level); | dbuf = _gcry_random_bytes_secure (dlen, random_level); | ||||
/* Compute the A value. */ | |||||
hvec[0].data = dbuf; | |||||
hvec[0].len = dlen; | |||||
rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1); | |||||
if (rc) | |||||
goto leave; | |||||
ec->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8); | ec->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8); | ||||
dbuf = NULL; | _gcry_ecc_eddsa_compute_h_d (&hash_d, ec); | ||||
reverse_buffer (hash_d, 32); /* Only the first half of the hash. */ | _gcry_mpi_set_buffer (a, hash_d, b, 0); | ||||
hash_d[0] = (hash_d[0] & 0x7f) | 0x40; | xfree (hash_d); | ||||
hash_d[31] &= 0xf8; | |||||
_gcry_mpi_set_buffer (a, hash_d, 32, 0); | |||||
xfree (hash_d); hash_d = NULL; | |||||
/* log_printmpi ("ecgen a", a); */ | /* log_printmpi ("ecgen a", a); */ | ||||
/* Compute Q. */ | /* Compute Q. */ | ||||
Context not available. | |||||
Q.y = NULL; | Q.y = NULL; | ||||
Q.x = NULL; | Q.x = NULL; | ||||
leave: | |||||
_gcry_mpi_release (a); | _gcry_mpi_release (a); | ||||
_gcry_mpi_release (x); | _gcry_mpi_release (x); | ||||
_gcry_mpi_release (y); | _gcry_mpi_release (y); | ||||
xfree (hash_d); | return 0; | ||||
return rc; | |||||
} | } | ||||
Context not available. | |||||
* | * | ||||
* Despite that this function requires the specification of a hash | * Despite that this function requires the specification of a hash | ||||
* algorithm, we only support what has been specified by the paper. | * algorithm, we only support what has been specified by the paper. | ||||
* This may change in the future. Note that we don't check the used | * This may change in the future. | ||||
* curve; the user is responsible to use Ed25519. | |||||
* | * | ||||
* Return the signature struct (r,s) from the message hash. The caller | * Return the signature struct (r,s) from the message hash. The caller | ||||
* must have allocated R_R and S. | * must have allocated R_R and S. | ||||
*/ | */ | ||||
/* String to be used with Ed448 */ | |||||
#define DOM4_0_NONE "SigEd448\0\0" | |||||
#define DOM4_0_NONE_LEN 10 | |||||
gpg_err_code_t | gpg_err_code_t | ||||
_gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, | _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, | ||||
gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo) | gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo) | ||||
{ | { | ||||
int rc; | int rc; | ||||
int b; | |||||
unsigned int tmp; | unsigned int tmp; | ||||
unsigned char *digest = NULL; | unsigned char *digest = NULL; | ||||
gcry_buffer_t hvec[3]; | |||||
const void *mbuf; | const void *mbuf; | ||||
size_t mlen; | size_t mlen; | ||||
unsigned char *rawmpi = NULL; | unsigned char *rawmpi = NULL; | ||||
Context not available. | |||||
unsigned int encpklen; | unsigned int encpklen; | ||||
mpi_point_struct I; /* Intermediate value. */ | mpi_point_struct I; /* Intermediate value. */ | ||||
gcry_mpi_t a, x, y, r; | gcry_mpi_t a, x, y, r; | ||||
int b; | |||||
memset (hvec, 0, sizeof hvec); | b = (ec->nbits+7)/8; | ||||
if (ec->nbits == 255) | |||||
; | |||||
else if (ec->nbits == 448) | |||||
b++; | |||||
else | |||||
return GPG_ERR_NOT_IMPLEMENTED; | |||||
if (!mpi_is_opaque (input)) | if (!mpi_is_opaque (input)) | ||||
return GPG_ERR_INV_DATA; | return GPG_ERR_INV_DATA; | ||||
Context not available. | |||||
y = mpi_new (0); | y = mpi_new (0); | ||||
r = mpi_snew (0); | r = mpi_snew (0); | ||||
b = (ec->nbits+7)/8; | |||||
if (b != 256/8) | |||||
{ | |||||
rc = GPG_ERR_INTERNAL; /* We only support 256 bit. */ | |||||
goto leave; | |||||
} | |||||
rc = _gcry_ecc_eddsa_compute_h_d (&digest, ec); | rc = _gcry_ecc_eddsa_compute_h_d (&digest, ec); | ||||
if (rc) | if (rc) | ||||
goto leave; | goto leave; | ||||
_gcry_mpi_set_buffer (a, digest, 32, 0); | _gcry_mpi_set_buffer (a, digest, b, 0); | ||||
/* Compute the public key if it's not available (only secret part). */ | /* Compute the public key if it's not available (only secret part). */ | ||||
if (ec->Q == NULL) | if (ec->Q == NULL) | ||||
Context not available. | |||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
log_printhex (" m", mbuf, mlen); | log_printhex (" m", mbuf, mlen); | ||||
hvec[0].data = digest; | if (hashalgo == GCRY_MD_SHAKE256) | ||||
hvec[0].off = 32; | { | ||||
hvec[0].len = 32; | gcry_error_t err; | ||||
hvec[1].data = (char*)mbuf; | gcry_md_hd_t hd; | ||||
hvec[1].len = mlen; | |||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); | err = _gcry_md_open (&hd, hashalgo, 0); | ||||
if (err) | |||||
rc = gcry_err_code (err); | |||||
else | |||||
{ | |||||
_gcry_md_write (hd, DOM4_0_NONE, DOM4_0_NONE_LEN); | |||||
_gcry_md_write (hd, digest+b, b); | |||||
_gcry_md_write (hd, mbuf, mlen); | |||||
_gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); | |||||
_gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); | |||||
_gcry_md_close (hd); | |||||
rc = 0; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
gcry_buffer_t hvec[3]; | |||||
memset (hvec, 0, sizeof hvec); | |||||
hvec[0].data = digest; | |||||
hvec[0].off = b; | |||||
hvec[0].len = b; | |||||
hvec[1].data = (char*)mbuf; | |||||
hvec[1].len = mlen; | |||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); | |||||
} | |||||
if (rc) | if (rc) | ||||
goto leave; | goto leave; | ||||
reverse_buffer (digest, 64); | reverse_buffer (digest, 2*b); | ||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
log_printhex (" r", digest, 64); | log_printhex (" r", digest, 2*b); | ||||
_gcry_mpi_set_buffer (r, digest, 64, 0); | _gcry_mpi_set_buffer (r, digest, 2*b, 0); | ||||
mpi_mod (r, r, ec->n); | |||||
_gcry_mpi_ec_mul_point (&I, r, ec->G, ec); | _gcry_mpi_ec_mul_point (&I, r, ec->G, ec); | ||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
log_printpnt (" r", &I, ec); | log_printpnt (" r", &I, ec); | ||||
Context not available. | |||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
log_printhex (" e_r", rawmpi, rawmpilen); | log_printhex (" e_r", rawmpi, rawmpilen); | ||||
/* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */ | if (hashalgo == GCRY_MD_SHAKE256) | ||||
hvec[0].data = rawmpi; /* (this is R) */ | { | ||||
hvec[0].off = 0; | gcry_error_t err; | ||||
hvec[0].len = rawmpilen; | gcry_md_hd_t hd; | ||||
hvec[1].data = encpk; | |||||
hvec[1].off = 0; | err = _gcry_md_open (&hd, hashalgo, 0); | ||||
hvec[1].len = encpklen; | if (err) | ||||
hvec[2].data = (char*)mbuf; | rc = gcry_err_code (err); | ||||
hvec[2].off = 0; | else | ||||
hvec[2].len = mlen; | { | ||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); | _gcry_md_write (hd, DOM4_0_NONE, DOM4_0_NONE_LEN); | ||||
_gcry_md_write (hd, rawmpi, rawmpilen); | |||||
_gcry_md_write (hd, encpk, encpklen); | |||||
_gcry_md_write (hd, mbuf, mlen); | |||||
_gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); | |||||
_gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); | |||||
_gcry_md_close (hd); | |||||
rc = 0; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
gcry_buffer_t hvec[3]; | |||||
memset (hvec, 0, sizeof hvec); | |||||
/* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */ | |||||
hvec[0].data = rawmpi; /* (this is R) */ | |||||
hvec[0].off = 0; | |||||
hvec[0].len = rawmpilen; | |||||
hvec[1].data = encpk; | |||||
hvec[1].off = 0; | |||||
hvec[1].len = encpklen; | |||||
hvec[2].data = (char*)mbuf; | |||||
hvec[2].off = 0; | |||||
hvec[2].len = mlen; | |||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); | |||||
} | |||||
if (rc) | if (rc) | ||||
goto leave; | goto leave; | ||||
Context not available. | |||||
mpi_set_opaque (r_r, rawmpi, rawmpilen*8); | mpi_set_opaque (r_r, rawmpi, rawmpilen*8); | ||||
rawmpi = NULL; | rawmpi = NULL; | ||||
reverse_buffer (digest, 64); | reverse_buffer (digest, 2*b); | ||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
log_printhex (" H(R+)", digest, 64); | log_printhex (" H(R+)", digest, 2*b); | ||||
_gcry_mpi_set_buffer (s, digest, 64, 0); | _gcry_mpi_set_buffer (s, digest, 2*b, 0); | ||||
mpi_mulm (s, s, a, ec->n); | mpi_mulm (s, s, a, ec->n); | ||||
mpi_addm (s, s, r, ec->n); | mpi_addm (s, s, r, ec->n); | ||||
rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen); | rc = eddsa_encodempi (s, ec->nbits, &rawmpi, &rawmpilen); | ||||
if (rc) | if (rc) | ||||
goto leave; | goto leave; | ||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
Context not available. | |||||
unsigned char *tbuf = NULL; | unsigned char *tbuf = NULL; | ||||
size_t mlen, rlen; | size_t mlen, rlen; | ||||
unsigned int tlen; | unsigned int tlen; | ||||
unsigned char digest[64]; | unsigned char digest[114]; | ||||
gcry_buffer_t hvec[3]; | |||||
gcry_mpi_t h, s; | gcry_mpi_t h, s; | ||||
mpi_point_struct Ia, Ib; | mpi_point_struct Ia, Ib; | ||||
if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in)) | if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in)) | ||||
return GPG_ERR_INV_DATA; | return GPG_ERR_INV_DATA; | ||||
if (hashalgo != GCRY_MD_SHA512) | |||||
return GPG_ERR_DIGEST_ALGO; | |||||
point_init (&Ia); | point_init (&Ia); | ||||
point_init (&Ib); | point_init (&Ib); | ||||
Context not available. | |||||
s = mpi_new (0); | s = mpi_new (0); | ||||
b = (ec->nbits+7)/8; | b = (ec->nbits+7)/8; | ||||
if (b != 256/8) | |||||
{ | if (ec->nbits == 255) | ||||
rc = GPG_ERR_INTERNAL; /* We only support 256 bit. */ | ; | ||||
goto leave; | else if (ec->nbits == 448) | ||||
} | b++; | ||||
else | |||||
return GPG_ERR_NOT_IMPLEMENTED; | |||||
/* Encode and check the public key. */ | /* Encode and check the public key. */ | ||||
rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, | rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, | ||||
Context not available. | |||||
goto leave; | goto leave; | ||||
} | } | ||||
/* h = H(encodepoint(R) + encodepoint(pk) + m) */ | if (hashalgo == GCRY_MD_SHAKE256) | ||||
hvec[0].data = (char*)rbuf; | { | ||||
hvec[0].off = 0; | gcry_error_t err; | ||||
hvec[0].len = rlen; | gcry_md_hd_t hd; | ||||
hvec[1].data = encpk; | |||||
hvec[1].off = 0; | err = _gcry_md_open (&hd, hashalgo, 0); | ||||
hvec[1].len = encpklen; | if (err) | ||||
hvec[2].data = (char*)mbuf; | rc = gcry_err_code (err); | ||||
hvec[2].off = 0; | else | ||||
hvec[2].len = mlen; | { | ||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); | _gcry_md_write (hd, DOM4_0_NONE, DOM4_0_NONE_LEN); | ||||
_gcry_md_write (hd, rbuf, rlen); | |||||
_gcry_md_write (hd, encpk, encpklen); | |||||
_gcry_md_write (hd, mbuf, mlen); | |||||
_gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); | |||||
_gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); | |||||
_gcry_md_close (hd); | |||||
rc = 0; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
gcry_buffer_t hvec[3]; | |||||
memset (hvec, 0, sizeof hvec); | |||||
/* h = H(encodepoint(R) + encodepoint(pk) + m) */ | |||||
hvec[0].data = (char*)rbuf; | |||||
hvec[0].off = 0; | |||||
hvec[0].len = rlen; | |||||
hvec[1].data = encpk; | |||||
hvec[1].off = 0; | |||||
hvec[1].len = encpklen; | |||||
hvec[2].data = (char*)mbuf; | |||||
hvec[2].off = 0; | |||||
hvec[2].len = mlen; | |||||
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); | |||||
} | |||||
if (rc) | if (rc) | ||||
goto leave; | goto leave; | ||||
reverse_buffer (digest, 64); | reverse_buffer (digest, 2*b); | ||||
if (DBG_CIPHER) | if (DBG_CIPHER) | ||||
log_printhex (" H(R+)", digest, 64); | log_printhex (" H(R+)", digest, 2*b); | ||||
_gcry_mpi_set_buffer (h, digest, 64, 0); | _gcry_mpi_set_buffer (h, digest, 2*b, 0); | ||||
/* According to the paper the best way for verification is: | /* According to the paper the best way for verification is: | ||||
encodepoint(sG - h·Q) = encodepoint(r) | encodepoint(sG - h·Q) = encodepoint(r) | ||||
Context not available. |