mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 01:18:00 +00:00
Merge 0.81 branch.
This commit is contained in:
commit
f0f058ccb4
2
Buildscr
2
Buildscr
@ -35,7 +35,7 @@ module putty
|
||||
ifeq "$(RELEASE)" "" set Ndate $(!builddate)
|
||||
ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -pe 's/(....)(..)(..)/$$1-$$2-$$3/' > date
|
||||
ifneq "$(Ndate)" "" read Date date
|
||||
set Epoch 18707 # update this at every release
|
||||
set Epoch 18819 # update this at every release
|
||||
ifneq "$(Ndate)" "" in . do echo $(Ndate) | perl -ne 'use Time::Local; /(....)(..)(..)/ and print timegm(0,0,0,$$3,$$2-1,$$1) / 86400 - $(Epoch)' > days
|
||||
ifneq "$(Ndate)" "" read Days days
|
||||
|
||||
|
@ -112,7 +112,7 @@ Making a release candidate build
|
||||
- Make a preliminary gpg signature, but don't run the full release-
|
||||
signing procedure. (We use the presence of a full set of GPG
|
||||
signatures to distinguish _abandoned_ release candidates from the
|
||||
one that ended up being the release.) In the 'build.X.YZ-rcN.out'
|
||||
one that ended up being the release.) In the 'build-X.YZ-rcN.out'
|
||||
directory, run
|
||||
sh sign.sh -r -p putty
|
||||
which will generate a clearsigned file called
|
||||
|
@ -1 +1 @@
|
||||
0.80
|
||||
0.81
|
||||
|
@ -108,6 +108,14 @@ include_directories(
|
||||
${platform}
|
||||
${extra_dirs})
|
||||
|
||||
check_c_source_compiles("
|
||||
#define _ISOC11_SOURCE
|
||||
#include <stdlib.h>
|
||||
int main(int argc, char **argv) {
|
||||
void *p = aligned_alloc(128, 12345);
|
||||
free(p);
|
||||
}" HAVE_ALIGNED_ALLOC)
|
||||
|
||||
if(PUTTY_DEBUG)
|
||||
add_compile_definitions(DEBUG)
|
||||
endif()
|
||||
|
@ -30,6 +30,7 @@ add_sources_from_current_dir(crypto
|
||||
pubkey-pem.c
|
||||
pubkey-ppk.c
|
||||
pubkey-ssh1.c
|
||||
rfc6979.c
|
||||
rsa.c
|
||||
sha256-common.c
|
||||
sha256-select.c
|
||||
|
116
crypto/dsa.c
116
crypto/dsa.c
@ -340,117 +340,6 @@ static int dsa_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mp_int *dsa_gen_k(const char *id_string, mp_int *modulus,
|
||||
mp_int *private_key,
|
||||
unsigned char *digest, int digest_len)
|
||||
{
|
||||
/*
|
||||
* The basic DSA signing algorithm is:
|
||||
*
|
||||
* - invent a random k between 1 and q-1 (exclusive).
|
||||
* - Compute r = (g^k mod p) mod q.
|
||||
* - Compute s = k^-1 * (hash + x*r) mod q.
|
||||
*
|
||||
* This has the dangerous properties that:
|
||||
*
|
||||
* - if an attacker in possession of the public key _and_ the
|
||||
* signature (for example, the host you just authenticated
|
||||
* to) can guess your k, he can reverse the computation of s
|
||||
* and work out x = r^-1 * (s*k - hash) mod q. That is, he
|
||||
* can deduce the private half of your key, and masquerade
|
||||
* as you for as long as the key is still valid.
|
||||
*
|
||||
* - since r is a function purely of k and the public key, if
|
||||
* the attacker only has a _range of possibilities_ for k
|
||||
* it's easy for him to work through them all and check each
|
||||
* one against r; he'll never be unsure of whether he's got
|
||||
* the right one.
|
||||
*
|
||||
* - if you ever sign two different hashes with the same k, it
|
||||
* will be immediately obvious because the two signatures
|
||||
* will have the same r, and moreover an attacker in
|
||||
* possession of both signatures (and the public key of
|
||||
* course) can compute k = (hash1-hash2) * (s1-s2)^-1 mod q,
|
||||
* and from there deduce x as before.
|
||||
*
|
||||
* - the Bleichenbacher attack on DSA makes use of methods of
|
||||
* generating k which are significantly non-uniformly
|
||||
* distributed; in particular, generating a 160-bit random
|
||||
* number and reducing it mod q is right out.
|
||||
*
|
||||
* For this reason we must be pretty careful about how we
|
||||
* generate our k. Since this code runs on Windows, with no
|
||||
* particularly good system entropy sources, we can't trust our
|
||||
* RNG itself to produce properly unpredictable data. Hence, we
|
||||
* use a totally different scheme instead.
|
||||
*
|
||||
* What we do is to take a SHA-512 (_big_) hash of the private
|
||||
* key x, and then feed this into another SHA-512 hash that
|
||||
* also includes the message hash being signed. That is:
|
||||
*
|
||||
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
|
||||
*
|
||||
* This number is 512 bits long, so reducing it mod q won't be
|
||||
* noticeably non-uniform. So
|
||||
*
|
||||
* k = proto_k mod q
|
||||
*
|
||||
* This has the interesting property that it's _deterministic_:
|
||||
* signing the same hash twice with the same key yields the
|
||||
* same signature.
|
||||
*
|
||||
* Despite this determinism, it's still not predictable to an
|
||||
* attacker, because in order to repeat the SHA-512
|
||||
* construction that created it, the attacker would have to
|
||||
* know the private key value x - and by assumption he doesn't,
|
||||
* because if he knew that he wouldn't be attacking k!
|
||||
*
|
||||
* (This trick doesn't, _per se_, protect against reuse of k.
|
||||
* Reuse of k is left to chance; all it does is prevent
|
||||
* _excessively high_ chances of reuse of k due to entropy
|
||||
* problems.)
|
||||
*
|
||||
* Thanks to Colin Plumb for the general idea of using x to
|
||||
* ensure k is hard to guess, and to the Cambridge University
|
||||
* Computer Security Group for helping to argue out all the
|
||||
* fine details.
|
||||
*/
|
||||
ssh_hash *h;
|
||||
unsigned char digest512[64];
|
||||
|
||||
/*
|
||||
* Hash some identifying text plus x.
|
||||
*/
|
||||
h = ssh_hash_new(&ssh_sha512);
|
||||
put_asciz(h, id_string);
|
||||
put_mp_ssh2(h, private_key);
|
||||
ssh_hash_digest(h, digest512);
|
||||
|
||||
/*
|
||||
* Now hash that digest plus the message hash.
|
||||
*/
|
||||
ssh_hash_reset(h);
|
||||
put_data(h, digest512, sizeof(digest512));
|
||||
put_data(h, digest, digest_len);
|
||||
ssh_hash_final(h, digest512);
|
||||
|
||||
/*
|
||||
* Now convert the result into a bignum, and coerce it to the
|
||||
* range [2,q), which we do by reducing it mod q-2 and adding 2.
|
||||
*/
|
||||
mp_int *modminus2 = mp_copy(modulus);
|
||||
mp_sub_integer_into(modminus2, modminus2, 2);
|
||||
mp_int *proto_k = mp_from_bytes_be(make_ptrlen(digest512, 64));
|
||||
mp_int *k = mp_mod(proto_k, modminus2);
|
||||
mp_free(proto_k);
|
||||
mp_free(modminus2);
|
||||
mp_add_integer_into(k, k, 2);
|
||||
|
||||
smemclr(digest512, sizeof(digest512));
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
static void dsa_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
|
||||
{
|
||||
struct dsa_key *dsa = container_of(key, struct dsa_key, sshk);
|
||||
@ -459,8 +348,9 @@ static void dsa_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
|
||||
|
||||
hash_simple(&ssh_sha1, data, digest);
|
||||
|
||||
mp_int *k = dsa_gen_k("DSA deterministic k generator", dsa->q, dsa->x,
|
||||
digest, sizeof(digest));
|
||||
/* Generate any valid exponent k, using the RFC 6979 deterministic
|
||||
* procedure. */
|
||||
mp_int *k = rfc6979(&ssh_sha1, dsa->q, dsa->x, data);
|
||||
mp_int *kinv = mp_invert(k, dsa->q); /* k^-1 mod q */
|
||||
|
||||
/*
|
||||
|
@ -1119,16 +1119,10 @@ static void ecdsa_sign(ssh_key *key, ptrlen data,
|
||||
|
||||
mp_int *z = ecdsa_signing_exponent_from_data(ek->curve, extra, data);
|
||||
|
||||
/* Generate k between 1 and curve->n, using the same deterministic
|
||||
* k generation system we use for conventional DSA. */
|
||||
mp_int *k;
|
||||
{
|
||||
unsigned char digest[20];
|
||||
hash_simple(&ssh_sha1, data, digest);
|
||||
k = dsa_gen_k(
|
||||
"ECDSA deterministic k generator", ek->curve->w.G_order,
|
||||
ek->privateKey, digest, sizeof(digest));
|
||||
}
|
||||
/* Generate any valid exponent k, using the RFC 6979 deterministic
|
||||
* procedure. */
|
||||
mp_int *k = rfc6979(
|
||||
extra->hash, ek->curve->w.G_order, ek->privateKey, data);
|
||||
|
||||
WeierstrassPoint *kG = ecc_weierstrass_multiply(ek->curve->w.G, k);
|
||||
mp_int *x;
|
||||
|
@ -18,9 +18,10 @@ struct hmac_extra {
|
||||
const char *suffix, *annotation;
|
||||
};
|
||||
|
||||
static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
/* Most of hmac_new(). Takes the actual 'struct hmac' as a parameter,
|
||||
* because sometimes it will have been allocated in a special way. */
|
||||
static ssh2_mac *hmac_new_inner(struct hmac *ctx, const ssh2_macalg *alg)
|
||||
{
|
||||
struct hmac *ctx = snew(struct hmac);
|
||||
const struct hmac_extra *extra = (const struct hmac_extra *)alg->extra;
|
||||
|
||||
ctx->h_outer = ssh_hash_new(extra->hashalg_base);
|
||||
@ -64,6 +65,11 @@ static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
return &ctx->mac;
|
||||
}
|
||||
|
||||
static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||
{
|
||||
return hmac_new_inner(snew(struct hmac), alg); /* cipher isn't needed */
|
||||
}
|
||||
|
||||
static void hmac_free(ssh2_mac *mac)
|
||||
{
|
||||
struct hmac *ctx = container_of(mac, struct hmac, mac);
|
||||
@ -277,3 +283,38 @@ const ssh2_macalg ssh_hmac_sha1_96_buggy = {
|
||||
.keylen = 16,
|
||||
.extra = &ssh_hmac_sha1_96_buggy_extra,
|
||||
};
|
||||
|
||||
ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash)
|
||||
{
|
||||
/*
|
||||
* Construct a custom ssh2_macalg, derived directly from the
|
||||
* provided hash vtable. It's included in the same memory
|
||||
* allocation as the struct hmac, so that it all gets freed
|
||||
* together.
|
||||
*/
|
||||
|
||||
struct alloc {
|
||||
struct hmac hmac;
|
||||
ssh2_macalg alg;
|
||||
struct hmac_extra extra;
|
||||
};
|
||||
|
||||
struct alloc *alloc = snew(struct alloc);
|
||||
alloc->alg.new = hmac_new;
|
||||
alloc->alg.free = hmac_free;
|
||||
alloc->alg.setkey = hmac_key;
|
||||
alloc->alg.start = hmac_start;
|
||||
alloc->alg.genresult = hmac_genresult;
|
||||
alloc->alg.next_message = nullmac_next_message;
|
||||
alloc->alg.text_name = hmac_text_name;
|
||||
alloc->alg.name = NULL;
|
||||
alloc->alg.etm_name = NULL;
|
||||
alloc->alg.len = hash->hlen;
|
||||
alloc->alg.keylen = hash->hlen;
|
||||
alloc->alg.extra = &alloc->extra;
|
||||
alloc->extra.hashalg_base = hash;
|
||||
alloc->extra.suffix = "";
|
||||
alloc->extra.annotation = NULL;
|
||||
|
||||
return hmac_new_inner(&alloc->hmac, &alloc->alg);
|
||||
}
|
||||
|
359
crypto/rfc6979.c
Normal file
359
crypto/rfc6979.c
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Code to generate 'nonce' values for DSA signature algorithms, in a
|
||||
* deterministic way.
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
#include "mpint.h"
|
||||
#include "misc.h"
|
||||
|
||||
/*
|
||||
* All DSA-type signature systems depend on a nonce - a random number
|
||||
* generated during the signing operation.
|
||||
*
|
||||
* This nonce is a weak point of DSA and needs careful protection,
|
||||
* for multiple reasons:
|
||||
*
|
||||
* 1. If an attacker in possession of your public key and a single
|
||||
* signature can find out or guess the nonce you used in that
|
||||
* signature, they can immediately recover your _private key_.
|
||||
*
|
||||
* 2. If you reuse the same nonce in two different signatures, this
|
||||
* will be instantly obvious to the attacker (one of the two
|
||||
* values making up the signature will match), and again, they can
|
||||
* immediately recover the private key as soon as they notice this.
|
||||
*
|
||||
* 3. In at least one system, information about your private key is
|
||||
* leaked merely by generating nonces with a significant bias.
|
||||
*
|
||||
* Attacks #1 and #2 work across all of integer DSA, NIST-style ECDSA,
|
||||
* and EdDSA. The details vary, but the headline effects are the same.
|
||||
*
|
||||
* So we must be very careful with our nonces. They must be generated
|
||||
* with uniform distribution, but also, they must avoid depending on
|
||||
* any random number generator that has the slightest doubt about its
|
||||
* reliability.
|
||||
*
|
||||
* In particular, PuTTY's policy is that for this purpose we don't
|
||||
* _even_ trust the PRNG we use for other cryptography. This is mostly
|
||||
* a concern because of Windows, where system entropy sources are
|
||||
* limited and we have doubts about their trustworthiness
|
||||
* - even CryptGenRandom. PuTTY compensates as best it can with its
|
||||
* own ongoing entropy collection, and we trust that for session keys,
|
||||
* but revealing the private key that goes with a long-term public key
|
||||
* is a far worse outcome than revealing one SSH session key, and for
|
||||
* keeping your private key safe, we don't think the available Windows
|
||||
* entropy gives us enough confidence.
|
||||
*
|
||||
* A common strategy these days (although <hipster>PuTTY was doing it
|
||||
* before it was cool</hipster>) is to avoid using a PRNG based on
|
||||
* system entropy at all. Instead, you use a deterministic PRNG that
|
||||
* starts from a fixed input seed, and in that input seed you include
|
||||
* the message to be signed and the _private key_.
|
||||
*
|
||||
* Including the private key in the seed is counterintuitive, but does
|
||||
* actually make sense. A deterministic nonce generation strategy must
|
||||
* use _some_ piece of input that the attacker doesn't have, or else
|
||||
* they'd be able to repeat the entire computation and construct the
|
||||
* same nonce you did. And the one thing they don't know is the
|
||||
* private key! So we include that in the seed data (under enough
|
||||
* layers of overcautious hashing to protect it against exposure), and
|
||||
* then they _can't_ repeat the same construction. Moreover, if they
|
||||
* _could_, they'd already know the private key, so they wouldn't need
|
||||
* to perform an attack of this kind at all!
|
||||
*
|
||||
* (This trick doesn't, _per se_, protect against reuse of nonces.
|
||||
* That is left to chance, which is enough, because the space of
|
||||
* nonces is large enough to make it adequately unlikely. But it
|
||||
* avoids escalating the reuse risk due to inadequate entropy.)
|
||||
*
|
||||
* For integer DSA and ECDSA, the system we use for deterministic
|
||||
* generation of k is exactly the one specified in RFC 6979. We
|
||||
* switched to this from the old system that PuTTY used to use before
|
||||
* that RFC came out. The old system had a critical bug: it did not
|
||||
* always generate _enough_ data to get uniform distribution, because
|
||||
* its output was a single SHA-512 hash. We could have fixed that
|
||||
* minimally, by concatenating multiple hashes, but it seemed more
|
||||
* sensible to switch to a system that comes with test vectors.
|
||||
*
|
||||
* One downside of RFC 6979 is that it's based on rejection sampling
|
||||
* (that is, you generate a random number and keep retrying until it's
|
||||
* in range). This makes it play badly with our side-channel test
|
||||
* system, which wants every execution trace of a supposedly
|
||||
* constant-time operation to be the same. To work around this
|
||||
* awkwardness, we break up the algorithm further, into a setup phase
|
||||
* and an 'attempt to generate an output' phase, each of which is
|
||||
* individually constant-time.
|
||||
*/
|
||||
|
||||
struct RFC6979 {
|
||||
/*
|
||||
* Size of the cyclic group over which we're doing DSA.
|
||||
* Equivalently, the multiplicative order of g (for integer DSA)
|
||||
* or the curve's base point (for ECDSA). For integer DSA this is
|
||||
* also the same thing as the small prime q from the key
|
||||
* parameters.
|
||||
*
|
||||
* This pointer is not owned. Freeing this structure will not free
|
||||
* it, and freeing the pointed-to integer before freeing this
|
||||
* structure will make this structure dangerous to use.
|
||||
*/
|
||||
mp_int *q;
|
||||
|
||||
/*
|
||||
* The private key integer, which is always the discrete log of
|
||||
* the public key with respect to the group generator.
|
||||
*
|
||||
* This pointer is not owned. Freeing this structure will not free
|
||||
* it, and freeing the pointed-to integer before freeing this
|
||||
* structure will make this structure dangerous to use.
|
||||
*/
|
||||
mp_int *x;
|
||||
|
||||
/*
|
||||
* Cached values derived from q: its length in bits, and in bytes.
|
||||
*/
|
||||
size_t qbits, qbytes;
|
||||
|
||||
/*
|
||||
* Reusable hash and MAC objects.
|
||||
*/
|
||||
ssh_hash *hash;
|
||||
ssh2_mac *mac;
|
||||
|
||||
/*
|
||||
* Cached value: the output length of the hash.
|
||||
*/
|
||||
size_t hlen;
|
||||
|
||||
/*
|
||||
* The byte string V used in the algorithm.
|
||||
*/
|
||||
unsigned char V[MAX_HASH_LEN];
|
||||
|
||||
/*
|
||||
* The string T to use during each attempt, and how many
|
||||
* hash-sized blocks to fill it with.
|
||||
*/
|
||||
size_t T_nblocks;
|
||||
unsigned char *T;
|
||||
};
|
||||
|
||||
static mp_int *bits2int(ptrlen b, RFC6979 *s)
|
||||
{
|
||||
if (b.len > s->qbytes)
|
||||
b.len = s->qbytes;
|
||||
mp_int *x = mp_from_bytes_be(b);
|
||||
|
||||
/*
|
||||
* Rationale for using mp_rshift_fixed_into and not
|
||||
* mp_rshift_safe_into: the shift count is derived from the
|
||||
* difference between the length of the modulus q, and the length
|
||||
* of the input bit string, i.e. between the _sizes_ of things
|
||||
* involved in the protocol. But the sizes aren't secret. Only the
|
||||
* actual values of integers and bit strings of those sizes are
|
||||
* secret. So it's OK for the shift count to be known to an
|
||||
* attacker - they'd know it anyway just from which DSA algorithm
|
||||
* we were using.
|
||||
*/
|
||||
if (b.len * 8 > s->qbits)
|
||||
mp_rshift_fixed_into(x, x, b.len * 8 - s->qbits);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void BinarySink_put_int2octets(BinarySink *bs, mp_int *x, RFC6979 *s)
|
||||
{
|
||||
mp_int *x_mod_q = mp_mod(x, s->q);
|
||||
for (size_t i = s->qbytes; i-- > 0 ;)
|
||||
put_byte(bs, mp_get_byte(x_mod_q, i));
|
||||
mp_free(x_mod_q);
|
||||
}
|
||||
|
||||
static void BinarySink_put_bits2octets(BinarySink *bs, ptrlen b, RFC6979 *s)
|
||||
{
|
||||
mp_int *x = bits2int(b, s);
|
||||
BinarySink_put_int2octets(bs, x, s);
|
||||
mp_free(x);
|
||||
}
|
||||
|
||||
#define put_int2octets(bs, x, s) \
|
||||
BinarySink_put_int2octets(BinarySink_UPCAST(bs), x, s)
|
||||
#define put_bits2octets(bs, b, s) \
|
||||
BinarySink_put_bits2octets(BinarySink_UPCAST(bs), b, s)
|
||||
|
||||
RFC6979 *rfc6979_new(const ssh_hashalg *hashalg, mp_int *q, mp_int *x)
|
||||
{
|
||||
/* Make the state structure. */
|
||||
RFC6979 *s = snew(RFC6979);
|
||||
s->q = q;
|
||||
s->x = x;
|
||||
s->qbits = mp_get_nbits(q);
|
||||
s->qbytes = (s->qbits + 7) >> 3;
|
||||
s->hash = ssh_hash_new(hashalg);
|
||||
s->mac = hmac_new_from_hash(hashalg);
|
||||
s->hlen = hashalg->hlen;
|
||||
|
||||
/* In each attempt, we concatenate enough hash blocks to be
|
||||
* greater than qbits in size. */
|
||||
size_t hbits = 8 * s->hlen;
|
||||
s->T_nblocks = (s->qbits + hbits - 1) / hbits;
|
||||
s->T = snewn(s->T_nblocks * s->hlen, unsigned char);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void rfc6979_setup(RFC6979 *s, ptrlen message)
|
||||
{
|
||||
unsigned char h1[MAX_HASH_LEN];
|
||||
unsigned char K[MAX_HASH_LEN];
|
||||
|
||||
/* 3.2 (a): hash the message to get h1. */
|
||||
ssh_hash_reset(s->hash);
|
||||
put_datapl(s->hash, message);
|
||||
ssh_hash_digest(s->hash, h1);
|
||||
|
||||
/* 3.2 (b): set V to a sequence of 0x01 bytes the same size as the
|
||||
* hash function's output. */
|
||||
memset(s->V, 1, s->hlen);
|
||||
|
||||
/* 3.2 (c): set the initial HMAC key K to all zeroes, again the
|
||||
* same size as the hash function's output. */
|
||||
memset(K, 0, s->hlen);
|
||||
ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
|
||||
|
||||
/* 3.2 (d): compute the MAC of V, the private key, and h1, with
|
||||
* key K, making a new key to replace K. */
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
put_byte(s->mac, 0);
|
||||
put_int2octets(s->mac, s->x, s);
|
||||
put_bits2octets(s->mac, make_ptrlen(h1, s->hlen), s);
|
||||
ssh2_mac_genresult(s->mac, K);
|
||||
ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
|
||||
|
||||
/* 3.2 (e): replace V with its HMAC using the new K. */
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
ssh2_mac_genresult(s->mac, s->V);
|
||||
|
||||
/* 3.2 (f): repeat step (d), only using the new K in place of the
|
||||
* initial all-zeroes one, and with the extra byte in the middle
|
||||
* of the MAC preimage being 1 rather than 0. */
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
put_byte(s->mac, 1);
|
||||
put_int2octets(s->mac, s->x, s);
|
||||
put_bits2octets(s->mac, make_ptrlen(h1, s->hlen), s);
|
||||
ssh2_mac_genresult(s->mac, K);
|
||||
ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
|
||||
|
||||
/* 3.2 (g): repeat step (e), using the again-replaced K. */
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
ssh2_mac_genresult(s->mac, s->V);
|
||||
|
||||
smemclr(h1, sizeof(h1));
|
||||
smemclr(K, sizeof(K));
|
||||
}
|
||||
|
||||
RFC6979Result rfc6979_attempt(RFC6979 *s)
|
||||
{
|
||||
RFC6979Result result;
|
||||
|
||||
/* 3.2 (h) 1: set T to the empty string */
|
||||
/* 3.2 (h) 2: make lots of output by concatenating MACs of V */
|
||||
for (size_t i = 0; i < s->T_nblocks; i++) {
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
ssh2_mac_genresult(s->mac, s->V);
|
||||
memcpy(s->T + i * s->hlen, s->V, s->hlen);
|
||||
}
|
||||
|
||||
/* 3.2 (h) 3: if we have a number in [1, q-1], return it ... */
|
||||
result.k = bits2int(make_ptrlen(s->T, s->T_nblocks * s->hlen), s);
|
||||
result.ok = mp_hs_integer(result.k, 1) & ~mp_cmp_hs(result.k, s->q);
|
||||
|
||||
/*
|
||||
* Perturb K and regenerate V ready for the next attempt.
|
||||
*
|
||||
* We do this unconditionally, whether or not the k we just
|
||||
* generated is acceptable. The time cost isn't large compared to
|
||||
* the public-key operation we're going to do next (not to mention
|
||||
* the larger number of these same operations we've already done),
|
||||
* and it makes side-channel testing easier if this function is
|
||||
* constant-time from beginning to end.
|
||||
*
|
||||
* In other rejection-sampling situations, particularly prime
|
||||
* generation, we're not this careful: it's enough to ensure that
|
||||
* _successful_ attempts run in constant time, Failures can do
|
||||
* whatever they like, on the theory that the only information
|
||||
* they _have_ to potentially expose via side channels is
|
||||
* information that was subsequently thrown away without being
|
||||
* used for anything important. (Hence, for example, it's fine to
|
||||
* have multiple different early-exit paths for failures you
|
||||
* detect at different times.)
|
||||
*
|
||||
* But here, the situation is different. Prime generation attempts
|
||||
* are independent of each other. These are not. All our
|
||||
* iterations round this loop use the _same_ secret data set up by
|
||||
* rfc6979_new(), and also, the perturbation step we're about to
|
||||
* compute will be used by the next iteration if there is one. So
|
||||
* it's absolutely _not_ true that a failed iteration deals
|
||||
* exclusively with data that won't contribute to the eventual
|
||||
* output. Hence, we have to be careful about the failures as well
|
||||
* as the successes.
|
||||
*
|
||||
* (Even so, it would be OK to make successes and failures take
|
||||
* different amounts of time, as long as each of those amounts was
|
||||
* consistent. But it's easier for testing to make them the same.)
|
||||
*/
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
put_byte(s->mac, 0);
|
||||
unsigned char K[MAX_HASH_LEN];
|
||||
ssh2_mac_genresult(s->mac, K);
|
||||
ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
|
||||
smemclr(K, sizeof(K));
|
||||
|
||||
ssh2_mac_start(s->mac);
|
||||
put_data(s->mac, s->V, s->hlen);
|
||||
ssh2_mac_genresult(s->mac, s->V);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rfc6979_free(RFC6979 *s)
|
||||
{
|
||||
/* We don't free s->q or s->x: our caller still owns those. */
|
||||
|
||||
ssh_hash_free(s->hash);
|
||||
ssh2_mac_free(s->mac);
|
||||
smemclr(s->T, s->T_nblocks * s->hlen);
|
||||
sfree(s->T);
|
||||
|
||||
/* Clear the whole structure before freeing. Most fields aren't
|
||||
* sensitive (pointers or well-known length values), but V is, and
|
||||
* it's easier to clear the whole lot than fiddle about
|
||||
* identifying the sensitive fields. */
|
||||
smemclr(s, sizeof(*s));
|
||||
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
mp_int *rfc6979(
|
||||
const ssh_hashalg *hashalg, mp_int *q, mp_int *x, ptrlen message)
|
||||
{
|
||||
RFC6979 *s = rfc6979_new(hashalg, q, x);
|
||||
rfc6979_setup(s, message);
|
||||
RFC6979Result result;
|
||||
while (true) {
|
||||
result = rfc6979_attempt(s);
|
||||
if (result.ok)
|
||||
break;
|
||||
else
|
||||
mp_free(result.k);
|
||||
}
|
||||
rfc6979_free(s);
|
||||
return result.k;
|
||||
}
|
2
defs.h
2
defs.h
@ -187,6 +187,8 @@ typedef struct ecdh_key ecdh_key;
|
||||
typedef struct ecdh_keyalg ecdh_keyalg;
|
||||
typedef struct NTRUKeyPair NTRUKeyPair;
|
||||
typedef struct NTRUEncodeSchedule NTRUEncodeSchedule;
|
||||
typedef struct RFC6979 RFC6979;
|
||||
typedef struct RFC6979Result RFC6979Result;
|
||||
|
||||
typedef struct dlgparam dlgparam;
|
||||
typedef struct dlgcontrol dlgcontrol;
|
||||
|
@ -41,7 +41,7 @@ use Plink:
|
||||
|
||||
\c C:\>plink
|
||||
\c Plink: command-line connection utility
|
||||
\c Release 0.80
|
||||
\c Release 0.81
|
||||
\c Usage: plink [options] [user@]host [command]
|
||||
\c ("host" can also be a PuTTY saved session name)
|
||||
\c Options:
|
||||
|
@ -39,7 +39,7 @@ use PSCP:
|
||||
|
||||
\c C:\>pscp
|
||||
\c PuTTY Secure Copy client
|
||||
\c Release 0.80
|
||||
\c Release 0.81
|
||||
\c Usage: pscp [options] [user@]host:source target
|
||||
\c pscp [options] source [source...] [user@]host:target
|
||||
\c pscp [options] -ls [user@]host:filespec
|
||||
|
21
ssh.h
21
ssh.h
@ -629,11 +629,18 @@ mp_int *ssh_rsakex_decrypt(
|
||||
RSAKey *key, const ssh_hashalg *h, ptrlen ciphertext);
|
||||
|
||||
/*
|
||||
* Helper function for k generation in DSA, reused in ECDSA
|
||||
* System for generating k in DSA and ECDSA.
|
||||
*/
|
||||
mp_int *dsa_gen_k(const char *id_string,
|
||||
mp_int *modulus, mp_int *private_key,
|
||||
unsigned char *digest, int digest_len);
|
||||
struct RFC6979Result {
|
||||
mp_int *k;
|
||||
unsigned ok;
|
||||
};
|
||||
RFC6979 *rfc6979_new(const ssh_hashalg *hashalg, mp_int *q, mp_int *x);
|
||||
void rfc6979_setup(RFC6979 *s, ptrlen message);
|
||||
RFC6979Result rfc6979_attempt(RFC6979 *s);
|
||||
void rfc6979_free(RFC6979 *s);
|
||||
mp_int *rfc6979(const ssh_hashalg *hashalg, mp_int *modulus,
|
||||
mp_int *private_key, ptrlen message);
|
||||
|
||||
struct ssh_cipher {
|
||||
const ssh_cipheralg *vt;
|
||||
@ -762,6 +769,11 @@ void nullmac_next_message(ssh2_mac *m);
|
||||
* string with a given key in the most obvious way. */
|
||||
void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output);
|
||||
|
||||
/* Constructor that makes an HMAC object given just a MAC. This object
|
||||
* will have empty 'name' and 'etm_name' fields, so it's not suitable
|
||||
* for use in SSH. It's used as a subroutine in RFC 6979. */
|
||||
ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash);
|
||||
|
||||
struct ssh_hash {
|
||||
const ssh_hashalg *vt;
|
||||
BinarySink_DELEGATE_IMPLEMENTATION;
|
||||
@ -1205,6 +1217,7 @@ extern const ssh2_macalg ssh_hmac_sha1_buggy;
|
||||
extern const ssh2_macalg ssh_hmac_sha1_96;
|
||||
extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
|
||||
extern const ssh2_macalg ssh_hmac_sha256;
|
||||
extern const ssh2_macalg ssh_hmac_sha384;
|
||||
extern const ssh2_macalg ssh_hmac_sha512;
|
||||
extern const ssh2_macalg ssh2_poly1305;
|
||||
extern const ssh2_macalg ssh2_aesgcm_mac;
|
||||
|
@ -90,6 +90,9 @@ def le_integer(x, nbits):
|
||||
assert nbits % 8 == 0
|
||||
return bytes([0xFF & (x >> (8*n)) for n in range(nbits//8)])
|
||||
|
||||
def be_integer(x, nbits):
|
||||
return bytes(reversed(le_integer(x, nbits)))
|
||||
|
||||
@contextlib.contextmanager
|
||||
def queued_random_data(nbytes, seed):
|
||||
hashsize = 512 // 8
|
||||
@ -2075,6 +2078,244 @@ culpa qui officia deserunt mollit anim id est laborum.
|
||||
self.assertFalse(ssh_key_verify(pubkey, badsig0, "hello, again"))
|
||||
self.assertFalse(ssh_key_verify(pubkey, badsigq, "hello, again"))
|
||||
|
||||
def testRFC6979(self):
|
||||
# The test case described in detail in RFC 6979 section A.1.
|
||||
# We can't actually do the _signature_ for this, because it's
|
||||
# based on ECDSA over a finite field of characteristic 2, and
|
||||
# we only support prime-order fields. But we don't need to do
|
||||
# full ECDSA, only generate the same deterministic nonce that
|
||||
# the test case expects.
|
||||
k = rfc6979('sha256',
|
||||
0x4000000000000000000020108A2E0CC0D99F8A5EF,
|
||||
0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F, "sample")
|
||||
self.assertEqual(int(k), 0x23AF4074C90A02B3FE61D286D5C87F425E6BDD81B)
|
||||
|
||||
# Selected test cases from the rest of Appendix A.
|
||||
#
|
||||
# We can only use test cases for which we have the appropriate
|
||||
# hash function, so I've left out the test cases based on
|
||||
# SHA-224. (We could easily implement that, but I don't think
|
||||
# it's worth it just for adding further tests of this one
|
||||
# function.) Similarly, I've omitted test cases relating to
|
||||
# ECDSA curves we don't implement: P192, P224, and all the
|
||||
# curves over power-of-2 finite fields.
|
||||
#
|
||||
# Where possible, we also test the actual signature algorithm,
|
||||
# to make sure it delivers the same entire signature as the
|
||||
# test case. This demonstrates that the rfc6979() function is
|
||||
# being called in the right way and the results are being used
|
||||
# as they should be. Here I've had to cut down the test cases
|
||||
# even further, because the RFC specifies test cases with a
|
||||
# cross product of DSA group and hash function, whereas we
|
||||
# have a fixed hash (specified by SSH) for each signature
|
||||
# algorithm. And the RFC is clear that you use the same hash
|
||||
# for nonce generation and actual signing.
|
||||
|
||||
# A.2.1: 1024-bit DSA
|
||||
q = 0x996F967F6C8E388D9E28D01E205FBA957A5698B1
|
||||
x = 0x411602CB19A6CCC34494D79D98EF1E7ED5AF25F7
|
||||
k = rfc6979('sha1', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B)
|
||||
k = rfc6979('sha256', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x519BA0546D0C39202A7D34D7DFA5E760B318BCFB)
|
||||
k = rfc6979('sha384', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x95897CD7BBB944AA932DBC579C1C09EB6FCFC595)
|
||||
k = rfc6979('sha512', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B)
|
||||
k = rfc6979('sha1', q, x, "test")
|
||||
self.assertEqual(int(k), 0x5C842DF4F9E344EE09F056838B42C7A17F4A6433)
|
||||
k = rfc6979('sha256', q, x, "test")
|
||||
self.assertEqual(int(k), 0x5A67592E8128E03A417B0484410FB72C0B630E1A)
|
||||
k = rfc6979('sha384', q, x, "test")
|
||||
self.assertEqual(int(k), 0x220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89)
|
||||
k = rfc6979('sha512', q, x, "test")
|
||||
self.assertEqual(int(k), 0x65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C)
|
||||
# The rest of the public key, for signature testing
|
||||
p = 0x86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED8873ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779
|
||||
g = 0x07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA417BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD
|
||||
y = 0x5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F65392195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E682F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B
|
||||
pubblob = ssh_string(b"ssh-dss") + b"".join(map(ssh2_mpint, [p,q,g,y]))
|
||||
privblob = ssh2_mpint(x)
|
||||
pubkey = ssh_key_new_pub('dsa', pubblob)
|
||||
privkey = ssh_key_new_priv('dsa', pubblob, privblob)
|
||||
sig = ssh_key_sign(privkey, b"sample", 0)
|
||||
# Expected output using SHA-1 as the hash in nonce
|
||||
# construction.
|
||||
r = 0x2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
||||
s = 0x29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
||||
ref_sig = ssh_string(b"ssh-dss") + ssh_string(
|
||||
be_integer(r, 160) + be_integer(s, 160))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
# And the other test string.
|
||||
sig = ssh_key_sign(privkey, b"test", 0)
|
||||
r = 0x42AB2052FD43E123F0607F115052A67DCD9C5C77
|
||||
s = 0x183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
||||
ref_sig = ssh_string(b"ssh-dss") + ssh_string(
|
||||
be_integer(r, 160) + be_integer(s, 160))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
|
||||
# A.2.2: 2048-bit DSA
|
||||
q = 0xF2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F
|
||||
x = 0x69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC
|
||||
k = rfc6979('sha1', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E)
|
||||
k = rfc6979('sha256', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52)
|
||||
k = rfc6979('sha384', q, x, "sample")
|
||||
self.assertEqual(int(k), 0xC345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920)
|
||||
k = rfc6979('sha512', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC)
|
||||
k = rfc6979('sha1', q, x, "test")
|
||||
self.assertEqual(int(k), 0x6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F)
|
||||
k = rfc6979('sha256', q, x, "test")
|
||||
self.assertEqual(int(k), 0x1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7)
|
||||
k = rfc6979('sha384', q, x, "test")
|
||||
self.assertEqual(int(k), 0x206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C)
|
||||
k = rfc6979('sha512', q, x, "test")
|
||||
self.assertEqual(int(k), 0xAFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA)
|
||||
# The rest of the public key, for signature testing
|
||||
p = 0x9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B
|
||||
g = 0x5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7
|
||||
y = 0x667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF
|
||||
pubblob = ssh_string(b"ssh-dss") + b"".join(map(ssh2_mpint, [p,q,g,y]))
|
||||
privblob = ssh2_mpint(x)
|
||||
pubkey = ssh_key_new_pub('dsa', pubblob)
|
||||
privkey = ssh_key_new_priv('dsa', pubblob, privblob)
|
||||
sig = ssh_key_sign(privkey, b"sample", 0)
|
||||
# Expected output using SHA-1 as the hash in nonce
|
||||
# construction, which is how SSH does things. RFC6979 lists
|
||||
# the following 256-bit values for r and s, but we end up only
|
||||
# using the low 160 bits of each.
|
||||
r = 0x3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
||||
s = 0xD26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
||||
ref_sig = ssh_string(b"ssh-dss") + ssh_string(
|
||||
be_integer(r, 160) + be_integer(s, 160))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
# And the other test string.
|
||||
sig = ssh_key_sign(privkey, b"test", 0)
|
||||
r = 0xC18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
||||
s = 0x414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
||||
ref_sig = ssh_string(b"ssh-dss") + ssh_string(
|
||||
be_integer(r, 160) + be_integer(s, 160))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
|
||||
# A.2.5: ECDSA with NIST P256
|
||||
q = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
|
||||
x = 0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721
|
||||
k = rfc6979('sha1', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4)
|
||||
k = rfc6979('sha256', q, x, "sample")
|
||||
self.assertEqual(int(k), 0xA6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60)
|
||||
k = rfc6979('sha384', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4)
|
||||
k = rfc6979('sha512', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5)
|
||||
k = rfc6979('sha1', q, x, "test")
|
||||
self.assertEqual(int(k), 0x8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E)
|
||||
k = rfc6979('sha256', q, x, "test")
|
||||
self.assertEqual(int(k), 0xD16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0)
|
||||
k = rfc6979('sha384', q, x, "test")
|
||||
self.assertEqual(int(k), 0x16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8)
|
||||
k = rfc6979('sha512', q, x, "test")
|
||||
self.assertEqual(int(k), 0x6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F)
|
||||
# The public key, for signature testing
|
||||
Ux = 0x60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6
|
||||
Uy = 0x7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299
|
||||
pubblob = ssh_string(b"ecdsa-sha2-nistp256") + ssh_string(b"nistp256") + ssh_string(b'\x04' + be_integer(Ux, 256) + be_integer(Uy, 256))
|
||||
privblob = ssh2_mpint(x)
|
||||
pubkey = ssh_key_new_pub('p256', pubblob)
|
||||
privkey = ssh_key_new_priv('p256', pubblob, privblob)
|
||||
sig = ssh_key_sign(privkey, b"sample", 0)
|
||||
# Expected output using SHA-256
|
||||
r = 0xEFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716
|
||||
s = 0xF7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8
|
||||
ref_sig = ssh_string(b"ecdsa-sha2-nistp256") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
# And the other test string
|
||||
sig = ssh_key_sign(privkey, b"test", 0)
|
||||
r = 0xF1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367
|
||||
s = 0x019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083
|
||||
ref_sig = ssh_string(b"ecdsa-sha2-nistp256") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
|
||||
# A.2.5: ECDSA with NIST P384
|
||||
q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973
|
||||
x = 0x6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5
|
||||
k = rfc6979('sha1', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7)
|
||||
k = rfc6979('sha256', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60)
|
||||
k = rfc6979('sha384', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9)
|
||||
k = rfc6979('sha512', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3)
|
||||
k = rfc6979('sha1', q, x, "test")
|
||||
self.assertEqual(int(k), 0x66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497)
|
||||
k = rfc6979('sha256', q, x, "test")
|
||||
self.assertEqual(int(k), 0x0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7)
|
||||
k = rfc6979('sha384', q, x, "test")
|
||||
self.assertEqual(int(k), 0x015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA)
|
||||
k = rfc6979('sha512', q, x, "test")
|
||||
self.assertEqual(int(k), 0x3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C)
|
||||
# The public key, for signature testing
|
||||
Ux = 0xEC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13
|
||||
Uy = 0x8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720
|
||||
pubblob = ssh_string(b"ecdsa-sha2-nistp384") + ssh_string(b"nistp384") + ssh_string(b'\x04' + be_integer(Ux, 384) + be_integer(Uy, 384))
|
||||
privblob = ssh2_mpint(x)
|
||||
pubkey = ssh_key_new_pub('p384', pubblob)
|
||||
privkey = ssh_key_new_priv('p384', pubblob, privblob)
|
||||
sig = ssh_key_sign(privkey, b"sample", 0)
|
||||
# Expected output using SHA-384
|
||||
r = 0x94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46
|
||||
s = 0x99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8
|
||||
ref_sig = ssh_string(b"ecdsa-sha2-nistp384") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
# And the other test string
|
||||
sig = ssh_key_sign(privkey, b"test", 0)
|
||||
r = 0x8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB
|
||||
s = 0xDDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5
|
||||
ref_sig = ssh_string(b"ecdsa-sha2-nistp384") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
|
||||
# A.2.6: ECDSA with NIST P521
|
||||
q = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409
|
||||
x = 0x0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538
|
||||
k = rfc6979('sha1', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9)
|
||||
k = rfc6979('sha256', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x0EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0)
|
||||
k = rfc6979('sha384', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x1546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211)
|
||||
k = rfc6979('sha512', q, x, "sample")
|
||||
self.assertEqual(int(k), 0x1DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3)
|
||||
k = rfc6979('sha1', q, x, "test")
|
||||
self.assertEqual(int(k), 0x0BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222)
|
||||
k = rfc6979('sha256', q, x, "test")
|
||||
self.assertEqual(int(k), 0x01DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258)
|
||||
k = rfc6979('sha384', q, x, "test")
|
||||
self.assertEqual(int(k), 0x1F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88)
|
||||
k = rfc6979('sha512', q, x, "test")
|
||||
self.assertEqual(int(k), 0x16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D)
|
||||
# The public key, for signature testing
|
||||
Ux = 0x1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4
|
||||
Uy = 0x0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5
|
||||
pubblob = ssh_string(b"ecdsa-sha2-nistp521") + ssh_string(b"nistp521") + ssh_string(b'\x04' + be_integer(Ux, 528) + be_integer(Uy, 528))
|
||||
privblob = ssh2_mpint(x)
|
||||
pubkey = ssh_key_new_pub('p521', pubblob)
|
||||
privkey = ssh_key_new_priv('p521', pubblob, privblob)
|
||||
sig = ssh_key_sign(privkey, b"sample", 0)
|
||||
# Expected output using SHA-512
|
||||
r = 0x0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA
|
||||
s = 0x0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A
|
||||
ref_sig = ssh_string(b"ecdsa-sha2-nistp521") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
# And the other test string
|
||||
sig = ssh_key_sign(privkey, b"test", 0)
|
||||
r = 0x13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D
|
||||
s = 0x1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3
|
||||
ref_sig = ssh_string(b"ecdsa-sha2-nistp521") + ssh_string(ssh2_mpint(r) + ssh2_mpint(s))
|
||||
self.assertEqual(sig, ref_sig)
|
||||
|
||||
def testBLAKE2b(self):
|
||||
# The standard test vectors for BLAKE2b (in the separate class
|
||||
# below) don't satisfy me because they only test one hash
|
||||
@ -2381,10 +2622,10 @@ culpa qui officia deserunt mollit anim id est laborum.
|
||||
test_keys = [
|
||||
('ed25519', 'AAAAC3NzaC1lZDI1NTE5AAAAIM7jupzef6CD0ps2JYxJp9IlwY49oorOseV5z5JFDFKn', 'AAAAIAf4/WRtypofgdNF2vbZOUFE1h4hvjw4tkGJZyOzI7c3', 255, b'0xf4d6e7f6f4479c23f0764ef43cea1711dbfe02aa2b5a32ff925c7c1fbf0f0db,0x27520c4592cf79e5b1ce8aa23d8ec125d2a7498c25369bd283a07fde9cbae3ce', [(0, 'AAAAC3NzaC1lZDI1NTE5AAAAQN73EqfyA4WneqDhgZ98TlRj9V5Wg8zCrMxTLJN1UtyfAnPUJDtfG/U0vOsP8PrnQxd41DDDnxrAXuqJz8rOagc=')]),
|
||||
('ed448', 'AAAACXNzaC1lZDQ0OAAAADnRI0CQDym5IqUidLNDcSdHe54bYEwqjpjBlab8uKGoe6FRqqejha7+5U/VAHy7BmE23+ju26O9XgA=', 'AAAAObP9klqyiJSJsdFJf+xwZQdkbZGUqXE07K6e5plfRTGjYYkyWJFUNFH4jzIn9xH1TX9z9EGycPaXAA==', 448, b'0x4bf4a2b6586c60d8cdb52c2b45b897f6d2224bc37987489c0d70febb449e8c82964ed5785827be808e44d31dd31e6ff7c99f43e49f419928,0x5ebda3dbeee8df366106bb7c00d54fe5feae85a3a7aa51a17ba8a1b8fca695c1988e2a4c601b9e7b47277143b37422a522b9290f904023d1', [(0, 'AAAACXNzaC1lZDQ0OAAAAHLkSVioGMvLesZp3Tn+Z/sSK0Hl7RHsHP4q9flLzTpZG5h6JDH3VmZBEjTJ6iOLaa0v4FoNt0ng4wAB53WrlQC4h3iAusoGXnPMAKJLmqzplKOCi8HKXk8Xl8fsXbaoyhatv1OZpwJcffmh1x+x+LSgNQA=')]),
|
||||
('p256', 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q=', 'AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q==', 256, b'nistp256,0x7918434b10a2ae4b6c923554c5a1c376d5e374d2622dd6569a8880a70128af75,0x4dc14594031981c78e1d0d3100561c49ccc8b6d2ef16efb191c2d7ad177837b4', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABIAAAAIAryzHDGi/TcCnbdxZkIYR5EGR6SNYXr/HlQRF8le+/IAAAAIERfzn6eHuBbqWIop2qL8S7DWRB3lenN1iyL10xYQPKw')]),
|
||||
('p384', 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg==', 'AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg==', 384, b'nistp384,0xc60af0f52d7c0949c0a6814c8184b82cc7d2fa8e31ae146dc8eb05b4db9065525277e8fa7b82f34342763f4924cb358e,0xf7c5f06cca2dce73f07de767233be35fc15058d5eeb107b101437a4e0ac96bca90480a89395989dd7d56e90da35ab61e', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAABpAAAAMDmHrtXCADzLvkkWG/duBAHlf6B1mVvdt6F0uzXfsf8Yub8WXNUNVnYq6ovrWPzLggAAADEA9izzwoUuFcXYRJeKcRLZEGMmSDDPzUZb7oZR0UgD1jsMQXs8UfpO31Qur/FDSCRK')]),
|
||||
('p521', 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg==', 'AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw==', 521, b'nistp521,0x16b1ad86528cd79dafbb61a193e47b88ef7f33a7be8537a1359ebe141c287f81cf90f076fc71d78f9fb0e729d6c94ad6897e53236ae2b89108ac912b7111f92e094,0xe72435f6c38cab299fb00c74b3f65c21f69d85f81e51f79d9eb3a817dd125190603eaa12a92aea7c80ac7bf1131b95e5fcc2046d22efb860c52729bd5e75112246', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAACMAAAAQgCLgvftvwM3CUaigrW0yzmCHoYjC6GLtO+6S91itqpgMEtWPNlaTZH6QQqkgscijWdXx98dDkQao/gcAKVmOZKPXgAAAEIB1PIrsDF1y6poJ/czqujB7NSUWt31v+c2t6UA8m2gTA1ARuVJ9XBGLMdceOTB00Hi9psC2RYFLpaWREOGCeDa6ow=')]),
|
||||
('dsa', 'AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI=', 'AAAAFGx3ft7G8AQzFsjhle7PWardUXh3', 768, b'0x9c966738d575d19dc9ce493eefd63eb0b4eef29102696a3ba4d48b8f5a87dea245c33bfc3d5a44c54075805ea50da67f57ec4139afa02f4a8106bbf67377907873d2fa1004a3ae288d5902875f54e8293f8c66717823680ef7563cf6da7e277b,0xea5effbc8bde6a2037dd862ff9229c28b41a03c7,0x6c4adcf102f0fd60f3ee6855459ad4fbdc774dfb3af23dde5be07f77b473d590aa3180e4eebfc5f1d94175095886942f86e481833a056b4faa3ef492c4f9aeb606fde3036a8479552146fd64e24d96836bda55e23cffff5aee754f15c012f000,0x9c43d9ae7d7b596b94727f04f836e2e2bddb2274fe074682d77659e9a5f1406cd75b87113452cf1666df9aff8e376f02a76318227fc760c6fe5444e9d64e7816bb48db247a5a0dc4dcf654724de49489964adf5dacfd297ba83937fc3bbb4542', [(0, 'AAAAB3NzaC1kc3MAAAAo0T2t6dr8Qr5DK2B0ETwUa3BhxMLPjLY0ZtlOACmP/kUt3JgByLv+3g==')]),
|
||||
('p256', 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q=', 'AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q==', 256, b'nistp256,0x7918434b10a2ae4b6c923554c5a1c376d5e374d2622dd6569a8880a70128af75,0x4dc14594031981c78e1d0d3100561c49ccc8b6d2ef16efb191c2d7ad177837b4', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABIAAAAIFrd1bjr4GHfWsM9RNJ+y4Z0eVwpRRv3IvNE2moaA1x3AAAAIFWcwwCE69kS4oybMFEUP4r7qFAY8tSb1o8ItSFcSe2+')]),
|
||||
('p384', 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg==', 'AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg==', 384, b'nistp384,0xc60af0f52d7c0949c0a6814c8184b82cc7d2fa8e31ae146dc8eb05b4db9065525277e8fa7b82f34342763f4924cb358e,0xf7c5f06cca2dce73f07de767233be35fc15058d5eeb107b101437a4e0ac96bca90480a89395989dd7d56e90da35ab61e', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAABoAAAAMFqCJ+gBP4GGc7yCy9F5e4EjkDlvYBYsYWMYFg3Md/ml7Md8pIrN7I0+8bFb99rZjQAAADAsM2kI+QOcgK+oVDaP0qkLRRbWDO1dSU5I2YfETyHVLYFNdRmgdWo6002XTO9jAsk=')]),
|
||||
('p521', 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg==', 'AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw==', 521, b'nistp521,0x16b1ad86528cd79dafbb61a193e47b88ef7f33a7be8537a1359ebe141c287f81cf90f076fc71d78f9fb0e729d6c94ad6897e53236ae2b89108ac912b7111f92e094,0xe72435f6c38cab299fb00c74b3f65c21f69d85f81e51f79d9eb3a817dd125190603eaa12a92aea7c80ac7bf1131b95e5fcc2046d22efb860c52729bd5e75112246', [(0, 'AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAACLAAAAQVBkbaCKivgvc+68CULCdPayjzRUYZdj1G2pLyiPWTdmJKVKF/W1oDAtjMZlP53tqCpGxDdrLoJH2A39k6g5MgNjAAAAQgGrNcesPBw/HMopBQ1JqOG1cSlAzjiFT34FvM68ZhdIjbQ0eHFuYs97RekQ8dpxmkuM88e63ATbZy4yDX06pKgmuQ==')]),
|
||||
('dsa', 'AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI=', 'AAAAFGx3ft7G8AQzFsjhle7PWardUXh3', 768, b'0x9c966738d575d19dc9ce493eefd63eb0b4eef29102696a3ba4d48b8f5a87dea245c33bfc3d5a44c54075805ea50da67f57ec4139afa02f4a8106bbf67377907873d2fa1004a3ae288d5902875f54e8293f8c66717823680ef7563cf6da7e277b,0xea5effbc8bde6a2037dd862ff9229c28b41a03c7,0x6c4adcf102f0fd60f3ee6855459ad4fbdc774dfb3af23dde5be07f77b473d590aa3180e4eebfc5f1d94175095886942f86e481833a056b4faa3ef492c4f9aeb606fde3036a8479552146fd64e24d96836bda55e23cffff5aee754f15c012f000,0x9c43d9ae7d7b596b94727f04f836e2e2bddb2274fe074682d77659e9a5f1406cd75b87113452cf1666df9aff8e376f02a76318227fc760c6fe5444e9d64e7816bb48db247a5a0dc4dcf654724de49489964adf5dacfd297ba83937fc3bbb4542', [(0, 'AAAAB3NzaC1kc3MAAAAoyCVHLG2QqdMx7NiCWaThx6tDA5mf7UGl+8By0IzmSldBujsGKNs20g==')]),
|
||||
('rsa', 'AAAAB3NzaC1yc2EAAAABJQAAAGEA2ChX9+mQD/NULFkBrxLDI8d1PHgrInC2u11U4Grqu4oVzKvnFROo6DZeCu6sKhFJE5CnIL7evAthQ9hkXVHDhQ7xGVauzqyHGdIU4/pHRScAYWBv/PZOlNMrSoP/PP91', 'AAAAYCMNdgyGvWpez2EjMLSbQj0nQ3GW8jzvru3zdYwtA3hblNUU9QpWNxDmOMOApkwCzUgsdIPsBxctIeWT2h+v8sVOH+d66LCaNmNR0lp+dQ+iXM67hcGNuxJwRdMupD9ZbQAAADEA7XMrMAb4WuHaFafoTfGrf6Jhdy9Ozjqi1fStuld7Nj9JkoZluiL2dCwIrxqOjwU5AAAAMQDpC1gYiGVSPeDRILr2oxREtXWOsW+/ZZTfZNX7lvoufnp+qvwZPqvZnXQFHyZ8qB0AAAAwQE0wx8TPgcvRVEVv8Wt+o1NFlkJZayWD5hqpe/8AqUMZbqfg/aiso5mvecDLFgfV', 768, b'0x25,0xd82857f7e9900ff3542c5901af12c323c7753c782b2270b6bb5d54e06aeabb8a15ccabe71513a8e8365e0aeeac2a11491390a720bedebc0b6143d8645d51c3850ef11956aeceac8719d214e3fa4745270061606ffcf64e94d32b4a83ff3cff75', [(0, 'AAAAB3NzaC1yc2EAAABgrLSC4635RCsH1b3en58NqLsrH7PKRZyb3YmRasOyr8xIZMSlKZyxNg+kkn9OgBzbH9vChafzarfHyVwtJE2IMt3uwxTIWjwgwH19tc16k8YmNfDzujmB6OFOArmzKJgJ'), (2, 'AAAADHJzYS1zaGEyLTI1NgAAAGAJszr04BZlVBEdRLGOv1rTJwPiid/0I6/MycSH+noahvUH2wjrRhqDuv51F4nKYF5J9vBsEotTSrSF/cnLsliCdvVkEfmvhdcn/jx2LWF2OfjqETiYSc69Dde9UFmAPds='), (4, 'AAAADHJzYS1zaGEyLTUxMgAAAGBxfZ2m+WjvZ5YV5RFm0+w84CgHQ95EPndoAha0PCMc93AUHBmoHnezsJvEGuLovUm35w/0POmUNHI7HzM9PECwXrV0rO6N/HL/oFxJuDYmeqCpjMVmN8QXka+yxs2GEtA=')]),
|
||||
]
|
||||
|
||||
|
142
test/dsa_nonce_recover.py
Executable file
142
test/dsa_nonce_recover.py
Executable file
@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
'''
|
||||
Recover the nonce value k used in integer DSA or NIST-style ECDSA,
|
||||
starting from the private key and the signature.
|
||||
|
||||
_Without_ the private key, recovering the nonce is equivalent to
|
||||
recovering the private key itself. But with it, it's a trivial piece
|
||||
of modular arithmetic.
|
||||
|
||||
This script generates a load of test signatures from various keys,
|
||||
recovers the nonces used, and prints them. This allows an eyeball
|
||||
check of whether they're evenly distributed.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
|
||||
from base64 import b64decode as b64
|
||||
|
||||
from eccref import *
|
||||
from testcrypt import *
|
||||
from ssh import *
|
||||
from agenttest import agent_query
|
||||
|
||||
def recover_nonce(order, hashalg, privint, transform_hash, r, s, message):
|
||||
w = int(mp_invert(s, order))
|
||||
|
||||
h = ssh_hash_new(hashalg)
|
||||
ssh_hash_update(h, message)
|
||||
z = int(mp_from_bytes_be(ssh_hash_final(h)))
|
||||
z = int(transform_hash(z))
|
||||
|
||||
return w * (z + r * privint) % order
|
||||
|
||||
def dsa_decode_sig(signature):
|
||||
_, signature = ssh_decode_string(signature, return_rest=True)
|
||||
signature = ssh_decode_string(signature)
|
||||
assert len(signature) == 40
|
||||
r = int(mp_from_bytes_be(signature[:20]))
|
||||
s = int(mp_from_bytes_be(signature[20:]))
|
||||
return r, s
|
||||
|
||||
def ecdsa_decode_sig(signature):
|
||||
_, signature = ssh_decode_string(signature, return_rest=True)
|
||||
signature = ssh_decode_string(signature)
|
||||
r, signature = ssh_decode_string(signature, return_rest=True)
|
||||
s, signature = ssh_decode_string(signature, return_rest=True)
|
||||
r = int(mp_from_bytes_be(r))
|
||||
s = int(mp_from_bytes_be(s))
|
||||
return r, s
|
||||
|
||||
class SignerBase:
|
||||
def test(self, privkey, decode_sig, transform_hash, order, hashalg,
|
||||
algid, obits):
|
||||
print("----", algid)
|
||||
print("k=0x{{:0{}b}}".format(obits).format(order))
|
||||
privblob = ssh_key_private_blob(privkey)
|
||||
privint = int(mp_from_bytes_be(ssh_decode_string(privblob)))
|
||||
self.setup_key(privkey)
|
||||
for message in (f"msg{i}".encode('ASCII') for i in range(100)):
|
||||
signature = self.sign(privkey, message)
|
||||
r, s = decode_sig(signature)
|
||||
nonce = recover_nonce(order, hashalg, privint, transform_hash,
|
||||
r, s, message)
|
||||
print("k=0x{{:0{}b}}".format(obits).format(nonce))
|
||||
self.cleanup_key(privkey)
|
||||
|
||||
def test_dsa(self, pubblob, privblob):
|
||||
privkey = ssh_key_new_priv('dsa', pubblob, privblob)
|
||||
_, buf = ssh_decode_string(pubblob, return_rest=True)
|
||||
p, buf = ssh_decode_string(buf, return_rest=True)
|
||||
q, buf = ssh_decode_string(buf, return_rest=True)
|
||||
g, buf = ssh_decode_string(buf, return_rest=True)
|
||||
p = int(mp_from_bytes_be(p))
|
||||
q = int(mp_from_bytes_be(q))
|
||||
g = int(mp_from_bytes_be(g))
|
||||
transform_hash = lambda h: h
|
||||
self.test(privkey, dsa_decode_sig, transform_hash, q, 'sha1', 'dsa',
|
||||
160)
|
||||
|
||||
def test_ecdsa(self, algid, curve, hashalg, pubblob, privblob):
|
||||
privkey = ssh_key_new_priv(algid, pubblob, privblob)
|
||||
obits = int(mp_get_nbits(curve.G_order))
|
||||
def transform_hash(z):
|
||||
shift = max(0, mp_get_nbits(z) - obits)
|
||||
return mp_rshift_safe(z, shift)
|
||||
self.test(privkey, ecdsa_decode_sig, transform_hash, curve.G_order,
|
||||
hashalg, algid, obits)
|
||||
|
||||
class TestcryptSigner(SignerBase):
|
||||
def setup_key(self, key):
|
||||
pass
|
||||
def cleanup_key(self, key):
|
||||
pass
|
||||
def sign(self, key, message):
|
||||
return ssh_key_sign(key, message, 0)
|
||||
|
||||
class AgentSigner(SignerBase):
|
||||
def setup_key(self, key):
|
||||
alg = ssh_decode_string(key.public_blob())
|
||||
msg = (ssh_byte(SSH2_AGENTC_ADD_IDENTITY) +
|
||||
ssh_string(alg) +
|
||||
key.openssh_blob() +
|
||||
ssh_string(b"dsa_nonce_recover test key"))
|
||||
result = agent_query(msg)
|
||||
assert result == ssh_byte(SSH_AGENT_SUCCESS)
|
||||
|
||||
def cleanup_key(self, key):
|
||||
msg = (ssh_byte(SSH2_AGENTC_REMOVE_IDENTITY) +
|
||||
ssh_string(key.public_blob()))
|
||||
result = agent_query(msg)
|
||||
assert result == ssh_byte(SSH_AGENT_SUCCESS)
|
||||
|
||||
def sign(self, key, message):
|
||||
msg = (ssh_byte(SSH2_AGENTC_SIGN_REQUEST) +
|
||||
ssh_string(key.public_blob()) +
|
||||
ssh_string(message))
|
||||
rsp = agent_query(msg)
|
||||
t, rsp = ssh_decode_byte(rsp, True)
|
||||
assert t == SSH2_AGENT_SIGN_RESPONSE
|
||||
sig, rsp = ssh_decode_string(rsp, True)
|
||||
assert len(rsp) == 0
|
||||
return sig
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument("--agent", action="store_true",
|
||||
help="Test an SSH agent instead of testcrypt. "
|
||||
"(Still needs testcrypt.)")
|
||||
args = parser.parse_args()
|
||||
|
||||
signer = AgentSigner() if args.agent else TestcryptSigner()
|
||||
|
||||
signer.test_dsa(b64('AAAAB3NzaC1kc3MAAABhAJyWZzjVddGdyc5JPu/WPrC07vKRAmlqO6TUi49ah96iRcM7/D1aRMVAdYBepQ2mf1fsQTmvoC9KgQa79nN3kHhz0voQBKOuKI1ZAodfVOgpP4xmcXgjaA73Vjz22n4newAAABUA6l7/vIveaiA33YYv+SKcKLQaA8cAAABgbErc8QLw/WDz7mhVRZrU+9x3Tfs68j3eW+B/d7Rz1ZCqMYDk7r/F8dlBdQlYhpQvhuSBgzoFa0+qPvSSxPmutgb94wNqhHlVIUb9ZOJNloNr2lXiPP//Wu51TxXAEvAAAAAAYQCcQ9mufXtZa5RyfwT4NuLivdsidP4HRoLXdlnppfFAbNdbhxE0Us8WZt+a/443bwKnYxgif8dgxv5UROnWTngWu0jbJHpaDcTc9lRyTeSUiZZK312s/Sl7qDk3/Du7RUI='), b64('AAAAFGx3ft7G8AQzFsjhle7PWardUXh3'))
|
||||
signer.test_ecdsa('p256', p256, 'sha256', b64('AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHkYQ0sQoq5LbJI1VMWhw3bV43TSYi3WVpqIgKcBKK91TcFFlAMZgceOHQ0xAFYcSczIttLvFu+xkcLXrRd4N7Q='), b64('AAAAIQCV/1VqiCsHZm/n+bq7lHEHlyy7KFgZBEbzqYaWtbx48Q=='))
|
||||
signer.test_ecdsa('p384', p384, 'sha384', b64('AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMYK8PUtfAlJwKaBTIGEuCzH0vqOMa4UbcjrBbTbkGVSUnfo+nuC80NCdj9JJMs1jvfF8GzKLc5z8H3nZyM741/BUFjV7rEHsQFDek4KyWvKkEgKiTlZid19VukNo1q2Hg=='), b64('AAAAMGsfTmdB4zHdbiQ2euTSdzM6UKEOnrVjMAWwHEYvmG5qUOcBnn62fJDRJy67L+QGdg=='))
|
||||
signer.test_ecdsa('p521', p521, 'sha512', b64('AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAFrGthlKM152vu2Ghk+R7iO9/M6e+hTehNZ6+FBwof4HPkPB2/HHXj5+w5ynWyUrWiX5TI2riuJEIrJErcRH5LglADnJDX2w4yrKZ+wDHSz9lwh9p2F+B5R952es6gX3RJRkGA+qhKpKup8gKx78RMbleX8wgRtIu+4YMUnKb1edREiRg=='), b64('AAAAQgFh7VNJFUljWhhyAEiL0z+UPs/QggcMTd3Vv2aKDeBdCRl5di8r+BMm39L7bRzxRMEtW5NSKlDtE8MFEGdIE9khsw=='))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -214,6 +214,14 @@ static void wrap_malloc_pre(void *wrapctx, void **user_data)
|
||||
*user_data = drwrap_get_arg(wrapctx, 0);
|
||||
dr_fprintf(outfile, "malloc %"PRIuMAX"\n", (uintmax_t)*user_data);
|
||||
}
|
||||
static void wrap_aligned_alloc_pre(void *wrapctx, void **user_data)
|
||||
{
|
||||
logging_paused++;
|
||||
size_t align = (size_t) drwrap_get_arg(wrapctx, 0);
|
||||
*user_data = drwrap_get_arg(wrapctx, 1);
|
||||
dr_fprintf(outfile, "aligned_alloc align=%zu size=%"PRIuMAX"\n",
|
||||
align, (uintmax_t)*user_data);
|
||||
}
|
||||
static void wrap_free_pre(void *wrapctx, void **user_data)
|
||||
{
|
||||
logging_paused++;
|
||||
@ -239,71 +247,7 @@ static void wrap_alloc_post(void *wrapctx, void *user_data)
|
||||
}
|
||||
|
||||
/*
|
||||
* We wrap the C library function memset, because I've noticed that at
|
||||
* least one optimised implementation of it diverges control flow
|
||||
* internally based on what appears to be the _alignment_ of the input
|
||||
* pointer - and that alignment check can vary depending on the
|
||||
* addresses of allocated blocks. So I can't guarantee no divergence
|
||||
* of control flow inside memset if malloc doesn't return the same
|
||||
* values, and instead I just have to trust that memset isn't reading
|
||||
* the contents of the block and basing control flow decisions on that.
|
||||
*/
|
||||
static void wrap_memset_pre(void *wrapctx, void **user_data)
|
||||
{
|
||||
uint was_already_paused = logging_paused++;
|
||||
|
||||
if (outfile == INVALID_FILE || was_already_paused)
|
||||
return;
|
||||
|
||||
const void *addr = drwrap_get_arg(wrapctx, 0);
|
||||
size_t size = (size_t)drwrap_get_arg(wrapctx, 2);
|
||||
|
||||
struct allocation *alloc = find_allocation(addr);
|
||||
if (!alloc) {
|
||||
dr_fprintf(outfile, "memset %"PRIuMAX" @ %"PRIxMAX"\n",
|
||||
(uintmax_t)size, (uintmax_t)addr);
|
||||
} else {
|
||||
dr_fprintf(outfile, "memset %"PRIuMAX" @ allocations[%"PRIuPTR"]"
|
||||
" + %"PRIxMAX"\n", (uintmax_t)size, alloc->index,
|
||||
(uintmax_t)(addr - alloc->start));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Similarly to the above, wrap some versions of memmove.
|
||||
*/
|
||||
static void wrap_memmove_pre(void *wrapctx, void **user_data)
|
||||
{
|
||||
uint was_already_paused = logging_paused++;
|
||||
|
||||
if (outfile == INVALID_FILE || was_already_paused)
|
||||
return;
|
||||
|
||||
const void *daddr = drwrap_get_arg(wrapctx, 0);
|
||||
const void *saddr = drwrap_get_arg(wrapctx, 1);
|
||||
size_t size = (size_t)drwrap_get_arg(wrapctx, 2);
|
||||
|
||||
|
||||
struct allocation *alloc;
|
||||
|
||||
dr_fprintf(outfile, "memmove %"PRIuMAX" ", (uintmax_t)size);
|
||||
if (!(alloc = find_allocation(daddr))) {
|
||||
dr_fprintf(outfile, "to %"PRIxMAX" ", (uintmax_t)daddr);
|
||||
} else {
|
||||
dr_fprintf(outfile, "to allocations[%"PRIuPTR"] + %"PRIxMAX" ",
|
||||
alloc->index, (uintmax_t)(daddr - alloc->start));
|
||||
}
|
||||
if (!(alloc = find_allocation(saddr))) {
|
||||
dr_fprintf(outfile, "from %"PRIxMAX"\n", (uintmax_t)saddr);
|
||||
} else {
|
||||
dr_fprintf(outfile, "from allocations[%"PRIuPTR"] + %"PRIxMAX"\n",
|
||||
alloc->index, (uintmax_t)(saddr - alloc->start));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Common post-wrapper function for memset and free, whose entire
|
||||
* function is to unpause the logging.
|
||||
* Common post-wrapper function to unpause the logging.
|
||||
*/
|
||||
static void unpause_post(void *wrapctx, void *user_data)
|
||||
{
|
||||
@ -594,10 +538,9 @@ static void load_module(
|
||||
TRY_WRAP("dry_run_real", NULL, wrap_dryrun);
|
||||
if (libc) {
|
||||
TRY_WRAP("malloc", wrap_malloc_pre, wrap_alloc_post);
|
||||
TRY_WRAP("aligned_alloc", wrap_aligned_alloc_pre, wrap_alloc_post);
|
||||
TRY_WRAP("realloc", wrap_realloc_pre, wrap_alloc_post);
|
||||
TRY_WRAP("free", wrap_free_pre, unpause_post);
|
||||
TRY_WRAP("memset", wrap_memset_pre, unpause_post);
|
||||
TRY_WRAP("memmove", wrap_memmove_pre, unpause_post);
|
||||
|
||||
/*
|
||||
* More strangely named versions of standard C library
|
||||
@ -616,10 +559,6 @@ static void load_module(
|
||||
TRY_WRAP("__libc_malloc", wrap_malloc_pre, wrap_alloc_post);
|
||||
TRY_WRAP("__GI___libc_realloc", wrap_realloc_pre, wrap_alloc_post);
|
||||
TRY_WRAP("__GI___libc_free", wrap_free_pre, unpause_post);
|
||||
TRY_WRAP("__memset_sse2_unaligned", wrap_memset_pre, unpause_post);
|
||||
TRY_WRAP("__memset_sse2", wrap_memset_pre, unpause_post);
|
||||
TRY_WRAP("__memmove_avx_unaligned_erms", wrap_memmove_pre,
|
||||
unpause_post);
|
||||
TRY_WRAP("cfree", wrap_free_pre, unpause_post);
|
||||
}
|
||||
}
|
||||
|
@ -327,6 +327,12 @@ FUNC(opt_val_string, key_components_nth_str,
|
||||
FUNC(opt_val_mpint, key_components_nth_mp, ARG(val_keycomponents, kc),
|
||||
ARG(uint, n))
|
||||
|
||||
/*
|
||||
* DSA nonce generation.
|
||||
*/
|
||||
FUNC(opt_val_mpint, rfc6979, ARG(hashalg, hash), ARG(val_mpint, modulus),
|
||||
ARG(val_mpint, private_key), ARG(val_string_ptrlen, message))
|
||||
|
||||
/*
|
||||
* The ssh_cipher abstraction. The in-place encrypt and decrypt
|
||||
* functions are wrapped to replace them with versions that take one
|
||||
|
@ -431,6 +431,8 @@ VOLATILE_WRAPPED_DEFN(static, size_t, looplimit, (size_t x))
|
||||
X(argon2) \
|
||||
X(primegen_probabilistic) \
|
||||
X(ntru) \
|
||||
X(rfc6979_setup) \
|
||||
X(rfc6979_attempt) \
|
||||
/* end of list */
|
||||
|
||||
static void test_mp_get_nbits(void)
|
||||
@ -1565,6 +1567,7 @@ static void test_hash(const ssh_hashalg *halg)
|
||||
test_skipped = true;
|
||||
return;
|
||||
}
|
||||
ssh_hash_free(h);
|
||||
|
||||
size_t datalen = 256;
|
||||
uint8_t *data = snewn(datalen, uint8_t);
|
||||
@ -1574,16 +1577,14 @@ static void test_hash(const ssh_hashalg *halg)
|
||||
random_read(data, datalen);
|
||||
|
||||
log_start();
|
||||
h = ssh_hash_new(halg);
|
||||
put_data(h, data, datalen);
|
||||
ssh_hash_final(h, hash);
|
||||
log_end();
|
||||
|
||||
h = ssh_hash_new(halg);
|
||||
}
|
||||
|
||||
sfree(data);
|
||||
sfree(hash);
|
||||
ssh_hash_free(h);
|
||||
}
|
||||
|
||||
#define HASH_TESTFN(Y_unused, hash) \
|
||||
@ -1744,6 +1745,63 @@ static void test_ntru(void)
|
||||
strbuf_free(buffer);
|
||||
}
|
||||
|
||||
static void test_rfc6979_setup(void)
|
||||
{
|
||||
mp_int *q = mp_new(512);
|
||||
mp_int *x = mp_new(512);
|
||||
|
||||
strbuf *message = strbuf_new();
|
||||
strbuf_append(message, 123);
|
||||
|
||||
RFC6979 *s = rfc6979_new(&ssh_sha256, q, x);
|
||||
|
||||
for (size_t i = 0; i < looplimit(20); i++) {
|
||||
random_read(message->u, message->len);
|
||||
mp_random_fill(q);
|
||||
mp_random_fill(x);
|
||||
|
||||
log_start();
|
||||
rfc6979_setup(s, ptrlen_from_strbuf(message));
|
||||
log_end();
|
||||
}
|
||||
|
||||
rfc6979_free(s);
|
||||
mp_free(q);
|
||||
mp_free(x);
|
||||
strbuf_free(message);
|
||||
}
|
||||
|
||||
static void test_rfc6979_attempt(void)
|
||||
{
|
||||
mp_int *q = mp_new(512);
|
||||
mp_int *x = mp_new(512);
|
||||
|
||||
strbuf *message = strbuf_new();
|
||||
strbuf_append(message, 123);
|
||||
|
||||
RFC6979 *s = rfc6979_new(&ssh_sha256, q, x);
|
||||
|
||||
for (size_t i = 0; i < looplimit(5); i++) {
|
||||
random_read(message->u, message->len);
|
||||
mp_random_fill(q);
|
||||
mp_random_fill(x);
|
||||
|
||||
rfc6979_setup(s, ptrlen_from_strbuf(message));
|
||||
|
||||
for (size_t j = 0; j < looplimit(10); j++) {
|
||||
log_start();
|
||||
RFC6979Result result = rfc6979_attempt(s);
|
||||
mp_free(result.k);
|
||||
log_end();
|
||||
}
|
||||
}
|
||||
|
||||
rfc6979_free(s);
|
||||
mp_free(q);
|
||||
mp_free(x);
|
||||
strbuf_free(message);
|
||||
}
|
||||
|
||||
static const struct test tests[] = {
|
||||
#define STRUCT_TEST(X) { #X, test_##X },
|
||||
TESTLIST(STRUCT_TEST)
|
||||
|
@ -100,9 +100,15 @@ add_executable(cgtest
|
||||
$<TARGET_OBJECTS:puttygen-common>)
|
||||
target_link_libraries(cgtest keygen console crypto utils)
|
||||
|
||||
add_executable(testsc
|
||||
${CMAKE_SOURCE_DIR}/test/testsc.c)
|
||||
target_link_libraries(testsc keygen crypto utils)
|
||||
if(HAVE_ALIGNED_ALLOC)
|
||||
add_library(overaligned_alloc OBJECT
|
||||
${CMAKE_SOURCE_DIR}/utils/memory.c)
|
||||
target_compile_definitions(overaligned_alloc PRIVATE ALLOCATION_ALIGNMENT=128)
|
||||
add_executable(testsc
|
||||
${CMAKE_SOURCE_DIR}/test/testsc.c
|
||||
$<TARGET_OBJECTS:overaligned_alloc>)
|
||||
target_link_libraries(testsc keygen crypto utils)
|
||||
endif()
|
||||
|
||||
add_executable(testzlib
|
||||
${CMAKE_SOURCE_DIR}/test/testzlib.c
|
||||
|
@ -2,6 +2,12 @@
|
||||
* PuTTY's memory allocation wrappers.
|
||||
*/
|
||||
|
||||
#ifdef ALLOCATION_ALIGNMENT
|
||||
/* Before we include standard headers, define _ISOC11_SOURCE so that
|
||||
* we get the declaration of aligned_alloc(). */
|
||||
#define _ISOC11_SOURCE
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
@ -28,6 +34,8 @@ void *safemalloc(size_t factor1, size_t factor2, size_t addend)
|
||||
void *p;
|
||||
#ifdef MINEFIELD
|
||||
p = minefield_c_malloc(size);
|
||||
#elif defined ALLOCATION_ALIGNMENT
|
||||
p = aligned_alloc(ALLOCATION_ALIGNMENT, size);
|
||||
#else
|
||||
p = malloc(size);
|
||||
#endif
|
||||
@ -52,6 +60,8 @@ void *saferealloc(void *ptr, size_t n, size_t size)
|
||||
if (!ptr) {
|
||||
#ifdef MINEFIELD
|
||||
p = minefield_c_malloc(size);
|
||||
#elif defined ALLOCATION_ALIGNMENT
|
||||
p = aligned_alloc(ALLOCATION_ALIGNMENT, size);
|
||||
#else
|
||||
p = malloc(size);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user