Complete rewrite of PuTTY's bignum library.

The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.

The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.

I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.

I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.

sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.

A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.

In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.

Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
This commit is contained in:
Simon Tatham 2018-12-31 13:53:41 +00:00
Родитель d73a1716f6
Коммит 25b034ee39
38 изменённых файлов: 6283 добавлений и 6109 удалений

13
Recipe
Просмотреть файл

@ -250,10 +250,11 @@ GTKMAIN = gtkmain cmdline
NONSSH = telnet raw rlogin ldisc pinger NONSSH = telnet raw rlogin ldisc pinger
# SSH back end (putty, plink, pscp, psftp). # SSH back end (putty, plink, pscp, psftp).
ARITH = mpint ecc
SSHCOMMON = sshcommon sshrand SSHCOMMON = sshcommon sshrand
+ sshverstring sshcrc sshdes sshmd5 sshrsa sshsha sshblowf + sshverstring sshcrc sshdes sshmd5 sshrsa sshsha sshblowf
+ sshdh sshcrcda sshpubk sshzlib sshdss ssharcf + sshdh sshcrcda sshpubk sshzlib sshdss ssharcf
+ sshaes sshccp sshsh256 sshsh512 sshbn sshmac marshal nullplug + sshaes sshccp sshsh256 sshsh512 ARITH sshmac marshal nullplug
+ sshgssc pgssapi sshecc wildcard ssh1censor ssh2censor ssh2bpp + sshgssc pgssapi sshecc wildcard ssh1censor ssh2censor ssh2bpp
+ ssh2transport ssh2transhk ssh2connection portfwd x11fwd + ssh2transport ssh2transhk ssh2connection portfwd x11fwd
+ ssh1connection ssh1bpp + ssh1connection ssh1bpp
@ -325,11 +326,11 @@ pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
+ psftp.res winnojmp LIBS + psftp.res winnojmp LIBS
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes sshbn sshmd5 version pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256 + tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
+ sshsh512 winutils sshecc winmisc winhelp conf pageant.res LIBS + sshsh512 winutils sshecc winmisc winhelp conf pageant.res LIBS
puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
+ sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc + sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc
+ sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res + sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res
+ tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc + tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc
@ -348,7 +349,7 @@ puttytel : [X] GTKTERM uxmisc misc ldisc settings uxsel U_BE_NOSSH
plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal
+ ux_x11 noterm uxnogtk sessprep cmdline + ux_x11 noterm uxnogtk sessprep cmdline
PUTTYGEN_UNIX = sshrsag sshdssg sshprime sshdes sshbn sshmd5 version PUTTYGEN_UNIX = sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
+ sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc + sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc
+ sshpubk sshaes sshsh256 sshsh512 IMPORT puttygen.res time tree234 + sshpubk sshaes sshsh256 sshsh512 IMPORT puttygen.res time tree234
+ uxgen notiming CONF sshecc sshecdsag uxnogtk + uxgen notiming CONF sshecc sshecdsag uxnogtk
@ -358,7 +359,7 @@ cgtest : [UT] cgtest PUTTYGEN_UNIX
pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk
psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk
pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes sshbn pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes ARITH
+ sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512 + sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512
+ sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons + sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
+ gtkask gtkmisc nullplug logging UXMISC uxagentsock memory + gtkask gtkmisc nullplug logging UXMISC uxagentsock memory
@ -373,8 +374,6 @@ osxlaunch : [UT] osxlaunch
fuzzterm : [UT] UXTERM CHARSET misc version uxmisc uxucs fuzzterm time settings fuzzterm : [UT] UXTERM CHARSET misc version uxmisc uxucs fuzzterm time settings
+ uxstore be_none uxnogtk memory + uxstore be_none uxnogtk memory
testbn : [UT] testbn sshbn MISC version CONF tree234 uxmisc uxnogtk
testbn : [C] testbn sshbn MISC version CONF tree234 winmisc LIBS
testzlib : [UT] testzlib sshzlib memory testzlib : [UT] testzlib sshzlib memory
uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk

Просмотреть файл

@ -704,16 +704,16 @@ int main(int argc, char **argv)
ssh2key->key = &dsskey->sshk; ssh2key->key = &dsskey->sshk;
ssh1key = NULL; ssh1key = NULL;
} else if (keytype == ECDSA) { } else if (keytype == ECDSA) {
struct ec_key *ec = snew(struct ec_key); struct ecdsa_key *ek = snew(struct ecdsa_key);
ec_generate(ec, bits, progressfn, &prog); ecdsa_generate(ek, bits, progressfn, &prog);
ssh2key = snew(struct ssh2_userkey); ssh2key = snew(struct ssh2_userkey);
ssh2key->key = &ec->sshk; ssh2key->key = &ek->sshk;
ssh1key = NULL; ssh1key = NULL;
} else if (keytype == ED25519) { } else if (keytype == ED25519) {
struct ec_key *ec = snew(struct ec_key); struct eddsa_key *ek = snew(struct eddsa_key);
ec_edgenerate(ec, bits, progressfn, &prog); eddsa_generate(ek, bits, progressfn, &prog);
ssh2key = snew(struct ssh2_userkey); ssh2key = snew(struct ssh2_userkey);
ssh2key->key = &ec->sshk; ssh2key->key = &ek->sshk;
ssh1key = NULL; ssh1key = NULL;
} else { } else {
struct RSAKey *rsakey = snew(struct RSAKey); struct RSAKey *rsakey = snew(struct RSAKey);

401
contrib/eccref.py Normal file
Просмотреть файл

@ -0,0 +1,401 @@
import numbers
import itertools
def jacobi(n,m):
"""Compute the Jacobi symbol.
The special case of this when m is prime is the Legendre symbol,
which is 0 if n is congruent to 0 mod m; 1 if n is congruent to a
non-zero square number mod m; -1 if n is not congruent to any
square mod m.
"""
assert m & 1
acc = 1
while True:
n %= m
if n == 0:
return 0
while not (n & 1):
n >>= 1
if (m & 7) not in {1,7}:
acc *= -1
if n == 1:
return acc
if (n & 3) == 3 and (m & 3) == 3:
acc *= -1
n, m = m, n
class SqrtModP(object):
"""Class for finding square roots of numbers mod p.
p must be an odd prime (but its primality is not checked)."""
def __init__(self, p):
p = abs(p)
assert p & 1
self.p = p
# Decompose p as 2^e k + 1 for odd k.
self.k = p-1
self.e = 0
while not (self.k & 1):
self.k >>= 1
self.e += 1
# Find a non-square mod p.
for self.z in itertools.count(1):
if jacobi(self.z, self.p) == -1:
break
self.zinv = ModP(self.p, self.z).invert()
def sqrt_recurse(self, a):
ak = pow(a, self.k, self.p)
for i in range(self.e, -1, -1):
if ak == 1:
break
ak = ak*ak % self.p
assert i > 0
if i == self.e:
return pow(a, (self.k+1) // 2, self.p)
r_prime = self.sqrt_recurse(a * pow(self.z, 2**i, self.p))
return r_prime * pow(self.zinv, 2**(i-1), self.p) % self.p
def sqrt(self, a):
j = jacobi(a, self.p)
if j == 0:
return 0
if j < 0:
raise ValueError("{} has no square root mod {}".format(a, self.p))
a %= self.p
r = self.sqrt_recurse(a)
assert r*r % self.p == a
# Normalise to the smaller (or 'positive') one of the two roots.
return min(r, self.p - r)
def __str__(self):
return "{}({})".format(type(self).__name__, self.p)
def __repr__(self):
return self.__str__()
class ModP(object):
"""Class that represents integers mod p as a field.
All the usual arithmetic operations are supported directly,
including division, so you can write formulas in a natural way
without having to keep saying '% p' everywhere or call a
cumbersome modular_inverse() function.
"""
def __init__(self, p, n=0):
self.p = p
if isinstance(n, type(self)):
self.check(n)
n = n.n
self.n = n % p
def check(self, other):
assert isinstance(other, type(self))
assert isinstance(self, type(other))
assert self.p == other.p
def coerce_to(self, other):
if not isinstance(other, type(self)):
other = type(self)(self.p, other)
else:
self.check(other)
return other
def invert(self):
"Internal routine which returns the bare inverse."
if self.n % self.p == 0:
raise ZeroDivisionError("division by {!r}".format(self))
a = self.n, 1, 0
b = self.p, 0, 1
while b[0]:
q = a[0] // b[0]
a = a[0] - q*b[0], a[1] - q*b[1], a[2] - q*b[2]
b, a = a, b
assert abs(a[0]) == 1
return a[1]*a[0]
def __add__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (self.n + rhs.n) % self.p)
def __neg__(self):
return type(self)(self.p, -self.n % self.p)
def __radd__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (self.n + rhs.n) % self.p)
def __sub__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (self.n - rhs.n) % self.p)
def __rsub__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (rhs.n - self.n) % self.p)
def __mul__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (self.n * rhs.n) % self.p)
def __rmul__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (self.n * rhs.n) % self.p)
def __div__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (self.n * rhs.invert()) % self.p)
def __rdiv__(self, rhs):
rhs = self.coerce_to(rhs)
return type(self)(self.p, (rhs.n * self.invert()) % self.p)
def __pow__(self, exponent):
assert exponent >= 0
n, b_to_n = 1, self
total = type(self)(self.p, 1)
while True:
if exponent & n:
exponent -= n
total *= b_to_n
n *= 2
if n > exponent:
break
b_to_n *= b_to_n
return total
def __cmp__(self, rhs):
rhs = self.coerce_to(rhs)
return cmp(self.n, rhs.n)
def __eq__(self, rhs):
rhs = self.coerce_to(rhs)
return self.n == rhs.n
def __ne__(self, rhs):
rhs = self.coerce_to(rhs)
return self.n != rhs.n
def __lt__(self, rhs):
raise ValueError("Elements of a modular ring have no ordering")
def __le__(self, rhs):
raise ValueError("Elements of a modular ring have no ordering")
def __gt__(self, rhs):
raise ValueError("Elements of a modular ring have no ordering")
def __ge__(self, rhs):
raise ValueError("Elements of a modular ring have no ordering")
def __str__(self):
return "0x{:x}".format(self.n)
def __repr__(self):
return "{}(0x{:x},0x{:x})".format(type(self).__name__, self.p, self.n)
class AffinePoint(object):
"""Base class for points on an elliptic curve."""
def __init__(self, curve, *args):
self.curve = curve
if len(args) == 0:
self.infinite = True
self.x = self.y = None
else:
assert len(args) == 2
self.infinite = False
self.x = ModP(self.curve.p, args[0])
self.y = ModP(self.curve.p, args[1])
self.check_equation()
def __neg__(self):
if self.infinite:
return self
return type(self)(self.curve, self.x, -self.y)
def __mul__(self, rhs):
if not isinstance(rhs, numbers.Integral):
raise ValueError("Elliptic curve points can only be multiplied by integers")
P = self
if rhs < 0:
rhs = -rhs
P = -P
toret = self.curve.point()
n = 1
nP = P
while rhs != 0:
if rhs & n:
rhs -= n
toret += nP
n += n
nP += nP
return toret
def __rmul__(self, rhs):
return self * rhs
def __sub__(self, rhs):
return self + (-rhs)
def __rsub__(self, rhs):
return (-self) + rhs
def __str__(self):
if self.infinite:
return "inf"
else:
return "({},{})".format(self.x, self.y)
def __repr__(self):
if self.infinite:
args = ""
else:
args = ", {}, {}".format(self.x, self.y)
return "{}.Point({}{})".format(type(self.curve).__name__,
self.curve, args)
def __eq__(self, rhs):
if self.infinite or rhs.infinite:
return self.infinite and rhs.infinite
return (self.x, self.y) == (rhs.x, rhs.y)
def __ne__(self, rhs):
return not (self == rhs)
def __lt__(self, rhs):
raise ValueError("Elliptic curve points have no ordering")
def __le__(self, rhs):
raise ValueError("Elliptic curve points have no ordering")
def __gt__(self, rhs):
raise ValueError("Elliptic curve points have no ordering")
def __ge__(self, rhs):
raise ValueError("Elliptic curve points have no ordering")
def __hash__(self):
if self.infinite:
return hash((True,))
else:
return hash((False, self.x, self.y))
class CurveBase(object):
def point(self, *args):
return self.Point(self, *args)
class WeierstrassCurve(CurveBase):
class Point(AffinePoint):
def check_equation(self):
assert (self.y*self.y ==
self.x*self.x*self.x +
self.curve.a*self.x + self.curve.b)
def __add__(self, rhs):
if self.infinite:
return rhs
if rhs.infinite:
return self
if self.x == rhs.x and self.y != rhs.y:
return self.curve.point()
x1, x2, y1, y2 = self.x, rhs.x, self.y, rhs.y
xdiff = x2-x1
if xdiff != 0:
slope = (y2-y1) / xdiff
else:
assert y1 == y2
slope = (3*x1*x1 + self.curve.a) / (2*y1)
xp = slope*slope - x1 - x2
yp = -(y1 + slope * (xp-x1))
return self.curve.point(xp, yp)
def __init__(self, p, a, b):
self.p = p
self.a = ModP(p, a)
self.b = ModP(p, b)
def cpoint(self, x, yparity=0):
if not hasattr(self, 'sqrtmodp'):
self.sqrtmodp = SqrtModP(self.p)
rhs = x**3 + self.a.n * x + self.b.n
y = self.sqrtmodp.sqrt(rhs)
if (y - yparity) % 2:
y = -y
return self.point(x, y)
def __repr__(self):
return "{}(0x{:x}, {}, {})".format(
type(self).__name__, self.p, self.a, self.b)
class MontgomeryCurve(CurveBase):
class Point(AffinePoint):
def check_equation(self):
assert (self.curve.b*self.y*self.y ==
self.x*self.x*self.x +
self.curve.a*self.x*self.x + self.x)
def __add__(self, rhs):
if self.infinite:
return rhs
if rhs.infinite:
return self
if self.x == rhs.x and self.y != rhs.y:
return self.curve.point()
x1, x2, y1, y2 = self.x, rhs.x, self.y, rhs.y
xdiff = x2-x1
if xdiff != 0:
slope = (y2-y1) / xdiff
else:
assert y1 == y2
slope = (3*x1*x1 + 2*self.curve.a*x1 + 1) / (2*self.curve.b*y1)
xp = self.curve.b*slope*slope - self.curve.a - x1 - x2
yp = -(y1 + slope * (xp-x1))
return self.curve.point(xp, yp)
def __init__(self, p, a, b):
self.p = p
self.a = ModP(p, a)
self.b = ModP(p, b)
def cpoint(self, x, yparity=0):
if not hasattr(self, 'sqrtmodp'):
self.sqrtmodp = SqrtModP(self.p)
rhs = x**3 + self.a.n * x**2 + self.b.n * x
y = self.sqrtmodp.sqrt(rhs)
if (y - yparity) % 2:
y = -y
return self.point(x, y)
def __repr__(self):
return "{}(0x{:x}, {}, {})".format(
type(self).__name__, self.p, self.a, self.b)
class TwistedEdwardsCurve(CurveBase):
class Point(AffinePoint):
def check_equation(self):
x2, y2 = self.x*self.x, self.y*self.y
assert (self.curve.a*x2 + y2 == 1 + self.curve.d*x2*y2)
def __neg__(self):
return type(self)(self.curve, -self.x, self.y)
def __add__(self, rhs):
x1, x2, y1, y2 = self.x, rhs.x, self.y, rhs.y
x1y2, y1x2, y1y2, x1x2 = x1*y2, y1*x2, y1*y2, x1*x2
dxxyy = self.curve.d*x1x2*y1y2
return self.curve.point((x1y2+y1x2)/(1+dxxyy),
(y1y2-self.curve.a*x1x2)/(1-dxxyy))
def __init__(self, p, d, a):
self.p = p
self.d = ModP(p, d)
self.a = ModP(p, a)
def point(self, *args):
# This curve form represents the identity using finite
# numbers, so it doesn't need the special infinity flag.
# Detect a no-argument call to point() and substitute the pair
# of integers that gives the identity.
if len(args) == 0:
args = [0, 1]
return super(TwistedEdwardsCurve, self).point(*args)
def cpoint(self, y, xparity=0):
if not hasattr(self, 'sqrtmodp'):
self.sqrtmodp = SqrtModP(self.p)
y = ModP(self.p, y)
y2 = y**2
radicand = (y2 - 1) / (self.d * y2 - self.a)
x = self.sqrtmodp.sqrt(radicand.n)
if (x - xparity) % 2:
x = -x
return self.point(x, y)
def __repr__(self):
return "{}(0x{:x}, {}, {})".format(
type(self).__name__, self.p, self.d, self.a)
p256 = WeierstrassCurve(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, -3, 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b)
p256.G = p256.point(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
p256.G_order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
p384 = WeierstrassCurve(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff, -3, 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef)
p384.G = p384.point(0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7, 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f)
p384.G_order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973
p521 = WeierstrassCurve(0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, -3, 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00)
p521.G = p521.point(0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66,0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650)
p521.G_order = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409
curve25519 = MontgomeryCurve(2**255-19, 0x76d06, 1)
curve25519.G = curve25519.cpoint(9)
ed25519 = TwistedEdwardsCurve(2**255-19, 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3, -1)
ed25519.G = ed25519.point(0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a,0x6666666666666666666666666666666666666666666666666666666666666658)
ed25519.G_order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed

Просмотреть файл

@ -2,39 +2,43 @@ import gdb
import re import re
import gdb.printing import gdb.printing
class PuTTYBignumPrettyPrinter(gdb.printing.PrettyPrinter): class PuTTYMpintPrettyPrinter(gdb.printing.PrettyPrinter):
"Pretty-print PuTTY's Bignum type." "Pretty-print PuTTY's mp_int type."
name = "Bignum" name = "mp_int"
def __init__(self, val): def __init__(self, val):
super(PuTTYBignumPrettyPrinter, self).__init__(self.name) super(PuTTYMpintPrettyPrinter, self).__init__(self.name)
self.val = val self.val = val
def to_string(self): def to_string(self):
type_BignumInt = gdb.lookup_type("BignumInt") type_BignumInt = gdb.lookup_type("BignumInt")
type_BignumIntPtr = type_BignumInt.pointer() type_BignumIntPtr = type_BignumInt.pointer()
BIGNUM_INT_BITS = 8 * type_BignumInt.sizeof BIGNUM_INT_BITS = 8 * type_BignumInt.sizeof
array = self.val.cast(type_BignumIntPtr) array = self.val["w"]
aget = lambda i: int(array[i]) & ((1 << BIGNUM_INT_BITS)-1) aget = lambda i: int(array[i]) & ((1 << BIGNUM_INT_BITS)-1)
try: try:
length = aget(0) length = int(self.val["nw"])
value = 0 value = 0
for i in range(length): for i in range(length):
value |= aget(i+1) << (BIGNUM_INT_BITS * i) value |= aget(i) << (BIGNUM_INT_BITS * i)
return "Bignum({:#x})".format(value) return "mp_int({:#x})".format(value)
except gdb.MemoryError: except gdb.MemoryError:
address = int(array) address = int(self.val)
if address == 0: if address == 0:
return "Bignum(NULL)".format(address) return "mp_int(NULL)".format(address)
return "Bignum(invalid @ {:#x})".format(address) return "mp_int(invalid @ {:#x})".format(address)
rcpp = gdb.printing.RegexpCollectionPrettyPrinter("PuTTY") class PuTTYPrinterSelector(gdb.printing.PrettyPrinter):
rcpp.add_printer(PuTTYBignumPrettyPrinter.name, "^Bignum$", def __init__(self):
PuTTYBignumPrettyPrinter) super(PuTTYPrinterSelector, self).__init__("PuTTY")
def __call__(self, val):
if str(val.type) == "mp_int *":
return PuTTYMpintPrettyPrinter(val)
return None
gdb.printing.register_pretty_printer(None, rcpp) gdb.printing.register_pretty_printer(None, PuTTYPrinterSelector())
class MemDumpCommand(gdb.Command): class MemDumpCommand(gdb.Command):
"""Print a hex+ASCII dump of object EXP. """Print a hex+ASCII dump of object EXP.

10
defs.h
Просмотреть файл

@ -63,6 +63,16 @@ typedef struct TermWinVtable TermWinVtable;
typedef struct Ssh Ssh; typedef struct Ssh Ssh;
typedef struct mp_int mp_int;
typedef struct MontyContext MontyContext;
typedef struct WeierstrassCurve WeierstrassCurve;
typedef struct WeierstrassPoint WeierstrassPoint;
typedef struct MontgomeryCurve MontgomeryCurve;
typedef struct MontgomeryPoint MontgomeryPoint;
typedef struct EdwardsCurve EdwardsCurve;
typedef struct EdwardsPoint EdwardsPoint;
typedef struct SftpServer SftpServer; typedef struct SftpServer SftpServer;
typedef struct SftpServerVtable SftpServerVtable; typedef struct SftpServerVtable SftpServerVtable;

1112
ecc.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

233
ecc.h Normal file
Просмотреть файл

@ -0,0 +1,233 @@
#ifndef PUTTY_ECC_H
#define PUTTY_ECC_H
/*
* Arithmetic functions for the various kinds of elliptic curves used
* by PuTTY's public-key cryptography.
*
* All of these elliptic curves are over the finite field whose order
* is a large prime p. (Elliptic curves over a field of order 2^n are
* also known, but PuTTY currently has no need of them.)
*/
/* ----------------------------------------------------------------------
* Weierstrass curves (or rather, 'short form' Weierstrass curves).
*
* A curve in this form is defined by two parameters a,b, and the
* non-identity points on the curve are represented by (x,y) (the
* 'affine coordinates') such that y^2 = x^3 + ax + b.
*
* The identity element of the curve's group is an additional 'point
* at infinity', which is considered to be the third point on the
* intersection of the curve with any vertical line. Hence, the
* inverse of the point (x,y) is (x,-y).
*/
/*
* Create and destroy Weierstrass curve data structures. The mandatory
* parameters to the constructor are the prime modulus p, and the
* curve parameters a,b.
*
* 'nonsquare_mod_p' is an optional extra parameter, only needed by
* ecc_edwards_point_new_from_y which has to take a modular square
* root. You can pass it as NULL if you don't need that function.
*/
WeierstrassCurve *ecc_weierstrass_curve(
mp_int *p, mp_int *a, mp_int *b, mp_int *nonsquare_mod_p);
void ecc_weierstrass_curve_free(WeierstrassCurve *);
/*
* Create points on a Weierstrass curve, given the curve.
*
* point_new_identity returns the special identity point.
* point_new(x,y) returns the non-identity point with the given affine
* coordinates.
*
* point_new_from_x constructs a non-identity point given only the
* x-coordinate, by using the curve equation to work out what y has to
* be. Of course the equation only tells you y^2, so it only
* determines y up to sign; the parameter desired_y_parity controls
* which of the two values of y you get, by saying whether you'd like
* its minimal non-negative residue mod p to be even or odd. (Of
* course, since p itself is odd, exactly one of y and p-y is odd.)
* This function has to take a modular square root, so it will only
* work if you passed in a non-square mod p when constructing the
* curve.
*/
WeierstrassPoint *ecc_weierstrass_point_new_identity(WeierstrassCurve *curve);
WeierstrassPoint *ecc_weierstrass_point_new(
WeierstrassCurve *curve, mp_int *x, mp_int *y);
WeierstrassPoint *ecc_weierstrass_point_new_from_x(
WeierstrassCurve *curve, mp_int *x, unsigned desired_y_parity);
/* Memory management: copy and free points. */
WeierstrassPoint *ecc_weierstrass_point_copy(WeierstrassPoint *wc);
void ecc_weierstrass_point_free(WeierstrassPoint *point);
/* Check whether a point is actually on the curve. */
unsigned ecc_weierstrass_point_valid(WeierstrassPoint *);
/*
* Add two points and return their sum. This function is fully
* general: it should do the right thing if the two inputs are the
* same, or if either (or both) of the input points is the identity,
* or if the two input points are inverses so the output is the
* identity. However, it pays for that generality by being slower than
* the special-purpose functions below..
*/
WeierstrassPoint *ecc_weierstrass_add_general(
WeierstrassPoint *, WeierstrassPoint *);
/*
* Fast but less general arithmetic functions: add two points on the
* condition that they are not equal and neither is the identity, and
* add a point to itself.
*/
WeierstrassPoint *ecc_weierstrass_add(WeierstrassPoint *, WeierstrassPoint *);
WeierstrassPoint *ecc_weierstrass_double(WeierstrassPoint *);
/*
* Compute an integer multiple of a point. Not guaranteed to work
* unless the integer argument is less than the order of the point in
* the group (because it won't cope if an identity element shows up in
* any intermediate product).
*/
WeierstrassPoint *ecc_weierstrass_multiply(WeierstrassPoint *, mp_int *);
/*
* Query functions to get the value of a point back out. is_identity
* tells you whether the point is the identity; if it isn't, then
* get_affine will retrieve one or both of its affine coordinates.
* (You can pass NULL as either output pointer, if you don't need that
* coordinate as output.)
*/
unsigned ecc_weierstrass_is_identity(WeierstrassPoint *wp);
void ecc_weierstrass_get_affine(WeierstrassPoint *wp, mp_int **x, mp_int **y);
/* ----------------------------------------------------------------------
* Montgomery curves.
*
* A curve in this form is defined by two parameters a,b, and the
* curve equation is y^2 = x^3 + ax^2 + bx.
*
* As with Weierstrass curves, there's an additional point at infinity
* that is the identity element, and the inverse of (x,y) is (x,-y).
*
* However, we don't actually work with full (x,y) pairs. We just
* store the x-coordinate (so what we're really representing is not a
* specific point on the curve but a two-point set {P,-P}). This means
* you can't quite do point addition, because if you're given {P,-P}
* and {Q,-Q} as input, you can work out a pair of x-coordinates that
* are those of P-Q and P+Q, but you don't know which is which.
*
* Instead, the basic operation is 'differential addition', in which
* you are given three parameters P, Q and P-Q and you return P+Q. (As
* well as disambiguating which of the possible answers you want, that
* extra input also enables a fast formulae for computing it. This
* fast formula is more or less why Montgomery curves are useful in
* the first place.)
*
* Doubling a point is still possible to do unambiguously, so you can
* still compute an integer multiple of P if you start by making 2P
* and then doing a series of differential additions.
*/
/*
* Create and destroy Montgomery curve data structures.
*/
MontgomeryCurve *ecc_montgomery_curve(mp_int *p, mp_int *a, mp_int *b);
void ecc_montgomery_curve_free(MontgomeryCurve *);
/*
* Create, copy and free points on the curve. We don't need to
* explicitly represent the identity for this application.
*/
MontgomeryPoint *ecc_montgomery_point_new(MontgomeryCurve *mc, mp_int *x);
MontgomeryPoint *ecc_montgomery_point_copy(MontgomeryPoint *orig);
void ecc_montgomery_point_free(MontgomeryPoint *mp);
/*
* Basic arithmetic routines: differential addition and point-
* doubling. Each of these assumes that no special cases come up - no
* input or output point should be the identity, and in diff_add, P
* and Q shouldn't be the same.
*/
MontgomeryPoint *ecc_montgomery_diff_add(
MontgomeryPoint *P, MontgomeryPoint *Q, MontgomeryPoint *PminusQ);
MontgomeryPoint *ecc_montgomery_double(MontgomeryPoint *P);
/*
* Compute an integer multiple of a point.
*/
MontgomeryPoint *ecc_montgomery_multiply(MontgomeryPoint *, mp_int *);
/*
* Return the affine x-coordinate of a point.
*/
void ecc_montgomery_get_affine(MontgomeryPoint *mp, mp_int **x);
/* ----------------------------------------------------------------------
* Twisted Edwards curves.
*
* A curve in this form is defined by two parameters d,a, and the
* curve equation is a x^2 + y^2 = 1 + d x^2 y^2.
*
* Apparently if you ask a proper algebraic geometer they'll tell you
* that this is technically not an actual elliptic curve. Certainly it
* doesn't work quite the same way as the other kinds: in this form,
* there is no need for a point at infinity, because the identity
* element is represented by the affine coordinates (0,1). And you
* invert a point by negating its x rather than y coordinate: the
* inverse of (x,y) is (-x,y).
*
* The usefulness of this representation is that the addition formula
* is 'strongly unified', meaning that the same formula works for any
* input and output points, without needing special cases for the
* identity or for doubling.
*/
/*
* Create and destroy Edwards curve data structures.
*
* Similarly to ecc_weierstrass_curve, you don't have to provide
* nonsquare_mod_p if you don't need ecc_edwards_point_new_from_y.
*/
EdwardsCurve *ecc_edwards_curve(
mp_int *p, mp_int *d, mp_int *a, mp_int *nonsquare_mod_p);
void ecc_edwards_curve_free(EdwardsCurve *);
/*
* Create points.
*
* There's no need to have a separate function to create the identity
* point, because you can just pass x=0 and y=1 to the usual function.
*
* Similarly to the Weierstrass curve, ecc_edwards_point_new_from_y
* creates a point given only its y-coordinate and the desired parity
* of its x-coordinate, and you can only call it if you provided the
* optional nonsquare_mod_p argument when creating the curve.
*/
EdwardsPoint *ecc_edwards_point_new(
EdwardsCurve *curve, mp_int *x, mp_int *y);
EdwardsPoint *ecc_edwards_point_new_from_y(
EdwardsCurve *curve, mp_int *y, unsigned desired_x_parity);
/* Copy and free points. */
EdwardsPoint *ecc_edwards_point_copy(EdwardsPoint *ec);
void ecc_edwards_point_free(EdwardsPoint *point);
/*
* Arithmetic: add two points, and calculate an integer multiple of a
* point.
*/
EdwardsPoint *ecc_edwards_add(EdwardsPoint *, EdwardsPoint *);
EdwardsPoint *ecc_edwards_multiply(EdwardsPoint *, mp_int *);
/*
* Query functions: compare two points for equality, and return the
* affine coordinates of a point.
*/
unsigned ecc_edwards_eq(EdwardsPoint *, EdwardsPoint *);
void ecc_edwards_get_affine(EdwardsPoint *wp, mp_int **x, mp_int **y);
#endif /* PUTTY_ECC_H */

Просмотреть файл

@ -10,6 +10,7 @@
#include "putty.h" #include "putty.h"
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
#include "misc.h" #include "misc.h"
static bool openssh_pem_encrypted(const Filename *file); static bool openssh_pem_encrypted(const Filename *file);
@ -815,7 +816,7 @@ static bool openssh_pem_write(
*/ */
if (ssh_key_alg(key->key) == &ssh_rsa) { if (ssh_key_alg(key->key) == &ssh_rsa) {
ptrlen n, e, d, p, q, iqmp, dmp1, dmq1; ptrlen n, e, d, p, q, iqmp, dmp1, dmq1;
Bignum bd, bp, bq, bdmp1, bdmq1; mp_int *bd, *bp, *bq, *bdmp1, *bdmq1;
/* /*
* These blobs were generated from inside PuTTY, so we needn't * These blobs were generated from inside PuTTY, so we needn't
@ -834,29 +835,29 @@ static bool openssh_pem_write(
assert(!get_err(src)); /* can't go wrong */ assert(!get_err(src)); /* can't go wrong */
/* We also need d mod (p-1) and d mod (q-1). */ /* We also need d mod (p-1) and d mod (q-1). */
bd = bignum_from_bytes(d.ptr, d.len); bd = mp_from_bytes_be(d);
bp = bignum_from_bytes(p.ptr, p.len); bp = mp_from_bytes_be(p);
bq = bignum_from_bytes(q.ptr, q.len); bq = mp_from_bytes_be(q);
decbn(bp); mp_sub_integer_into(bp, bp, 1);
decbn(bq); mp_sub_integer_into(bq, bq, 1);
bdmp1 = bigmod(bd, bp); bdmp1 = mp_mod(bd, bp);
bdmq1 = bigmod(bd, bq); bdmq1 = mp_mod(bd, bq);
freebn(bd); mp_free(bd);
freebn(bp); mp_free(bp);
freebn(bq); mp_free(bq);
dmp1.len = (bignum_bitcount(bdmp1)+8)/8; dmp1.len = (mp_get_nbits(bdmp1)+8)/8;
dmq1.len = (bignum_bitcount(bdmq1)+8)/8; dmq1.len = (mp_get_nbits(bdmq1)+8)/8;
sparelen = dmp1.len + dmq1.len; sparelen = dmp1.len + dmq1.len;
spareblob = snewn(sparelen, unsigned char); spareblob = snewn(sparelen, unsigned char);
dmp1.ptr = spareblob; dmp1.ptr = spareblob;
dmq1.ptr = spareblob + dmp1.len; dmq1.ptr = spareblob + dmp1.len;
for (i = 0; i < dmp1.len; i++) for (i = 0; i < dmp1.len; i++)
spareblob[i] = bignum_byte(bdmp1, dmp1.len-1 - i); spareblob[i] = mp_get_byte(bdmp1, dmp1.len-1 - i);
for (i = 0; i < dmq1.len; i++) for (i = 0; i < dmq1.len; i++)
spareblob[i+dmp1.len] = bignum_byte(bdmq1, dmq1.len-1 - i); spareblob[i+dmp1.len] = mp_get_byte(bdmq1, dmq1.len-1 - i);
freebn(bdmp1); mp_free(bdmp1);
freebn(bdmq1); mp_free(bdmq1);
numbers[0] = make_ptrlen(zero, 1); zero[0] = '\0'; numbers[0] = make_ptrlen(zero, 1); zero[0] = '\0';
numbers[1] = n; numbers[1] = n;
@ -913,7 +914,7 @@ static bool openssh_pem_write(
ssh_key_alg(key->key) == &ssh_ecdsa_nistp384 || ssh_key_alg(key->key) == &ssh_ecdsa_nistp384 ||
ssh_key_alg(key->key) == &ssh_ecdsa_nistp521) { ssh_key_alg(key->key) == &ssh_ecdsa_nistp521) {
const unsigned char *oid; const unsigned char *oid;
struct ec_key *ec = container_of(key->key, struct ec_key, sshk); struct ecdsa_key *ec = container_of(key->key, struct ecdsa_key, sshk);
int oidlen; int oidlen;
int pointlen; int pointlen;
strbuf *seq, *sub; strbuf *seq, *sub;
@ -929,7 +930,7 @@ static bool openssh_pem_write(
* BIT STRING (0x00 public key point) * BIT STRING (0x00 public key point)
*/ */
oid = ec_alg_oid(ssh_key_alg(key->key), &oidlen); oid = ec_alg_oid(ssh_key_alg(key->key), &oidlen);
pointlen = (ec->publicKey.curve->fieldBits + 7) / 8 * 2; pointlen = (ec->curve->fieldBits + 7) / 8 * 2;
seq = strbuf_new(); seq = strbuf_new();

Просмотреть файл

@ -153,6 +153,8 @@ struct strbuf;
void BinarySink_put_stringsb(BinarySink *, struct strbuf *); void BinarySink_put_stringsb(BinarySink *, struct strbuf *);
void BinarySink_put_asciz(BinarySink *, const char *str); void BinarySink_put_asciz(BinarySink *, const char *str);
bool BinarySink_put_pstring(BinarySink *, const char *str); bool BinarySink_put_pstring(BinarySink *, const char *str);
void BinarySink_put_mp_ssh1(BinarySink *bs, mp_int *x);
void BinarySink_put_mp_ssh2(BinarySink *bs, mp_int *x);
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -195,7 +197,7 @@ struct BinarySource {
* types. * types.
* *
* If the usual return value is dynamically allocated (e.g. a * If the usual return value is dynamically allocated (e.g. a
* Bignum, or a normal C 'char *' string), then the error value is * bignum, or a normal C 'char *' string), then the error value is
* also dynamic in the same way. So you have to free exactly the * also dynamic in the same way. So you have to free exactly the
* same set of things whether or not there was a decoding error, * same set of things whether or not there was a decoding error,
* which simplifies exit paths - for example, you could call a big * which simplifies exit paths - for example, you could call a big
@ -281,5 +283,7 @@ uint64_t BinarySource_get_uint64(BinarySource *);
ptrlen BinarySource_get_string(BinarySource *); ptrlen BinarySource_get_string(BinarySource *);
const char *BinarySource_get_asciz(BinarySource *); const char *BinarySource_get_asciz(BinarySource *);
ptrlen BinarySource_get_pstring(BinarySource *); ptrlen BinarySource_get_pstring(BinarySource *);
mp_int *BinarySource_get_mp_ssh1(BinarySource *src);
mp_int *BinarySource_get_mp_ssh2(BinarySource *src);
#endif /* PUTTY_MARSHAL_H */ #endif /* PUTTY_MARSHAL_H */

2340
mpint.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

386
mpint.h Normal file
Просмотреть файл

@ -0,0 +1,386 @@
#ifndef PUTTY_MPINT_H
#define PUTTY_MPINT_H
/*
* PuTTY's multiprecision integer library.
*
* This library is written with the aim of avoiding leaking the input
* numbers via timing and cache side channels. This means avoiding
* making any control flow change, or deciding the address of any
* memory access, based on the value of potentially secret input data.
*
* But in a library that has to handle numbers of arbitrary size, you
* can't avoid your control flow depending on the _size_ of the input!
* So the rule is that an mp_int has a nominal size that need not be
* its mathematical size: i.e. if you call (say) mp_from_bytes_be to
* turn an array of 256 bytes into an integer, and all but the last of
* those bytes is zero, then you get an mp_int which has space for 256
* bytes of data but just happens to store the value 1. So the
* _nominal_ sizes of input data - e.g. the size in bits of some
* public-key modulus - are not considered secret, and control flow is
* allowed to do what it likes based on those sizes. But the same
* function, called with the same _nominally sized_ arguments
* containing different values, should run in the same length of time.
*
* When a function returns an 'mp_int *', it is newly allocated to an
* appropriate nominal size (which, again, depends only on the nominal
* sizes of the inputs). Other functions have 'into' in their name,
* and they instead overwrite the contents of an existing mp_int.
*
* Functions in this API which return values that are logically
* boolean return them as 'unsigned' rather than the C99 bool type.
* That's because C99 bool does an implicit test for non-zero-ness
* when converting any other integer type to it, which compilers might
* well implement using data-dependent control flow.
*/
/*
* Create and destroy mp_ints. A newly created one is initialised to
* zero. mp_clear also resets an existing number to zero.
*/
mp_int *mp_new(size_t maxbits);
void mp_free(mp_int *);
void mp_clear(mp_int *x);
/*
* Create mp_ints from various sources: little- and big-endian binary
* data, an ordinary C unsigned integer type, a decimal or hex string
* (given either as a ptrlen or a C NUL-terminated string), and
* another mp_int.
*
* The decimal and hex conversion functions have running time
* dependent on the length of the input data, of course.
*/
mp_int *mp_from_bytes_le(ptrlen bytes);
mp_int *mp_from_bytes_be(ptrlen bytes);
mp_int *mp_from_integer(uintmax_t n);
mp_int *mp_from_decimal_pl(ptrlen decimal);
mp_int *mp_from_decimal(const char *decimal);
mp_int *mp_from_hex_pl(ptrlen hex);
mp_int *mp_from_hex(const char *hex);
mp_int *mp_copy(mp_int *x);
/*
* A macro for declaring large fixed numbers in source code (such as
* elliptic curve parameters, or standard Diffie-Hellman moduli). The
* idea is that you just write something like
*
* mp_int *value = MP_LITERAL(0x19284376283754638745693467245);
*
* and it newly allocates you an mp_int containing that number.
*
* Internally, the macro argument is stringified and passed to
* mp_from_hex. That's not as fast as it could be if I had instead set
* up some kind of mp_from_array_of_uint64_t() function, but I think
* this system is valuable for the fact that the literal integers
* appear in a very natural syntax that can be pasted directly out
* into, say, Python if you want to cross-check a calculation.
*/
static inline mp_int *mp__from_string_literal(const char *lit)
{
/* Don't call this directly; it's not equipped to deal with
* hostile data. Use only via the MP_LITERAL macro. */
if (lit[0] && (lit[1] == 'x' || lit[1] == 'X'))
return mp_from_hex(lit+2);
else
return mp_from_decimal(lit);
}
#define MP_LITERAL(number) mp__from_string_literal(#number)
/*
* Create an mp_int with the value 2^power.
*/
mp_int *mp_power_2(size_t power);
/*
* Retrieve the value of a particular bit or byte of an mp_int. The
* byte / bit index is not considered to be secret data. Out-of-range
* byte/bit indices are handled cleanly and return zero.
*/
uint8_t mp_get_byte(mp_int *x, size_t byte);
unsigned mp_get_bit(mp_int *x, size_t bit);
/*
* Set an mp_int bit. Again, the bit index is not considered secret.
* Do not pass an out-of-range index, on pain of assertion failure.
*/
void mp_set_bit(mp_int *x, size_t bit, unsigned val);
/*
* Return the nominal size of an mp_int, in terms of the maximum
* number of bytes or bits that can fit in it.
*/
size_t mp_max_bytes(mp_int *x);
size_t mp_max_bits(mp_int *x);
/*
* Return the _mathematical_ bit count of an mp_int (not its nominal
* size), i.e. a value n such that 2^{n-1} <= x < 2^n.
*
* This function is supposed to run in constant time for a given
* nominal input size. Of course it's likely that clients of this
* function will promptly need to use the result as the limit of some
* loop (e.g. marshalling an mp_int into an SSH packet, which doesn't
* permit extra prefix zero bytes). But that's up to the caller to
* decide the safety of.
*/
size_t mp_get_nbits(mp_int *x);
/*
* Return the value of an mp_int as a decimal or hex string. The
* result is dynamically allocated, and the caller is responsible for
* freeing it.
*
* These functions should run in constant time for a given nominal
* input size, even though the exact number of digits returned is
* variable. They always allocate enough space for the largest output
* that might be needed, but they don't always fill it.
*/
char *mp_get_decimal(mp_int *x);
char *mp_get_hex(mp_int *x);
char *mp_get_hex_uppercase(mp_int *x);
/*
* Compare two mp_ints, or compare one mp_int against a C integer. The
* 'eq' functions return 1 if the two inputs are equal, or 0
* otherwise; the 'hs' functions return 1 if the first input is >= the
* second, and 0 otherwise.
*/
unsigned mp_cmp_hs(mp_int *a, mp_int *b);
unsigned mp_cmp_eq(mp_int *a, mp_int *b);
unsigned mp_hs_integer(mp_int *x, uintmax_t n);
unsigned mp_eq_integer(mp_int *x, uintmax_t n);
/*
* Take the minimum of two mp_ints, without using a conditional branch.
*/
void mp_min_into(mp_int *r, mp_int *x, mp_int *y);
mp_int *mp_min(mp_int *x, mp_int *y);
/*
* Diagnostic function. Writes out x in hex to the supplied stdio
* stream, preceded by the string 'prefix' and followed by 'suffix'.
*
* This is useful to put temporarily into code, but it's also
* potentially useful to call from a debugger.
*/
void mp_dump(FILE *fp, const char *prefix, mp_int *x, const char *suffix);
/*
* Overwrite one mp_int with another.
*/
void mp_copy_into(mp_int *dest, mp_int *src);
/*
* Conditional selection. Overwrites dest with either src0 or src1,
* according to the value of 'choose_src1'. choose_src1 should be 0 or
* 1; if it's 1, then dest is set to src1, otherwise src0.
*
* The value of choose_src1 is considered to be secret data, so
* control flow and memory access should not depend on it.
*/
void mp_select_into(mp_int *dest, mp_int *src0, mp_int *src1,
unsigned choose_src1);
/*
* Addition, subtraction and multiplication, either targeting an
* existing mp_int or making a new one large enough to hold whatever
* the output might be..
*/
void mp_add_into(mp_int *r, mp_int *a, mp_int *b);
void mp_sub_into(mp_int *r, mp_int *a, mp_int *b);
void mp_mul_into(mp_int *r, mp_int *a, mp_int *b);
mp_int *mp_add(mp_int *x, mp_int *y);
mp_int *mp_sub(mp_int *x, mp_int *y);
mp_int *mp_mul(mp_int *x, mp_int *y);
/*
* Addition, subtraction and multiplication with one argument small
* enough to fit in a C integer. For mp_mul_integer_into, it has to be
* even smaller than that.
*/
void mp_add_integer_into(mp_int *r, mp_int *a, uintmax_t n);
void mp_sub_integer_into(mp_int *r, mp_int *a, uintmax_t n);
void mp_mul_integer_into(mp_int *r, mp_int *a, uint16_t n);
/*
* Conditional addition/subtraction. If yes == 1, sets r to a+b or a-b
* (respectively). If yes == 0, sets r to just a. 'yes' is considered
* secret data.
*/
void mp_cond_add_into(mp_int *r, mp_int *a, mp_int *b, unsigned yes);
void mp_cond_sub_into(mp_int *r, mp_int *a, mp_int *b, unsigned yes);
/*
* Swap x0 and x1 if swap == 1, and not if swap == 0. 'swap' is
* considered secret.
*/
void mp_cond_swap(mp_int *x0, mp_int *x1, unsigned swap);
/*
* Set x to 0 if clear == 1, and otherwise leave it unchanged. 'clear'
* is considered secret.
*/
void mp_cond_clear(mp_int *x, unsigned clear);
/*
* Division. mp_divmod_into divides n by d, and writes the quotient
* into q and the remainder into r. You can pass either of q and r as
* NULL if you don't need one of the outputs.
*
* mp_div and mp_mod are wrappers that return one or other of those
* outputs as a freshly allocated mp_int of the appropriate size.
*
* Division by zero gives no error, and returns a quotient of 0 and a
* remainder of n (so as to still satisfy the division identity that
* n=qd+r).
*/
void mp_divmod_into(mp_int *n, mp_int *d, mp_int *q, mp_int *r);
mp_int *mp_div(mp_int *n, mp_int *d);
mp_int *mp_mod(mp_int *x, mp_int *modulus);
/*
* Trivially easy special case of mp_mod: reduce a number mod a power
* of two.
*/
void mp_reduce_mod_2to(mp_int *x, size_t p);
/*
* Modular inverses. mp_invert computes the inverse of x mod modulus
* (and will expect the two to be coprime). mp_invert_mod_2to computes
* the inverse of x mod 2^p, and is a great deal faster.
*/
mp_int *mp_invert_mod_2to(mp_int *x, size_t p);
mp_int *mp_invert(mp_int *x, mp_int *modulus);
/*
* System for taking square roots modulo an odd prime.
*
* In order to do this efficiently, you need to provide an extra piece
* of information at setup time, namely a number which is not
* congruent mod p to any square. Given p and that non-square, you can
* use modsqrt_new to make a context containing all the necessary
* equipment for actually calculating the square roots, and then you
* can call mp_modsqrt as many times as you like on that context
* before freeing it.
*
* The output parameter '*success' will be filled in with 1 if the
* operation was successful, or 0 if the input number doesn't have a
* square root mod p at all. In the latter case, the returned mp_int
* will be nonsense and you shouldn't depend on it.
*
* ==== WARNING ====
*
* This function DOES NOT TREAT THE PRIME MODULUS AS SECRET DATA! It
* will protect the number you're taking the square root _of_, but not
* the number you're taking the root of it _mod_.
*
* (This is because the algorithm requires a number of loop iterations
* equal to the number of factors of 2 in p-1. And the expected use of
* this function is for elliptic-curve point decompression, in which
* the modulus is always a well-known one written down in standards
* documents.)
*/
typedef struct ModsqrtContext ModsqrtContext;
ModsqrtContext *modsqrt_new(mp_int *p, mp_int *any_nonsquare_mod_p);
void modsqrt_free(ModsqrtContext *);
mp_int *mp_modsqrt(ModsqrtContext *sc, mp_int *x, unsigned *success);
/*
* Functions for Montgomery multiplication, a fast technique for doing
* a long series of modular multiplications all with the same modulus
* (which has to be odd).
*
* You start by calling monty_new to set up a context structure
* containing all the precomputed bits and pieces needed by the
* algorithm. Then, any numbers you want to work with must first be
* transformed into the internal Montgomery representation using
* monty_import; having done that, you can use monty_mul and monty_pow
* to operate on them efficiently; and finally, monty_export will
* convert numbers back out of Montgomery representation to give their
* ordinary values.
*
* Addition and subtraction are not optimised by the Montgomery trick,
* but monty_add and monty_sub are provided anyway for convenience.
*
* There are also monty_invert and monty_modsqrt, which are analogues
* of mp_invert and mp_modsqrt which take their inputs in Montgomery
* representation. For mp_modsqrt, the prime modulus of the
* ModsqrtContext must be the same as the modulus of the MontyContext.
*
* The query functions monty_modulus and monty_identity return numbers
* stored inside the MontyContext, without copying them. The returned
* pointers are still owned by the MontyContext, so don't free them!
*/
MontyContext *monty_new(mp_int *modulus);
MontyContext *monty_copy(MontyContext *mc);
void monty_free(MontyContext *mc);
mp_int *monty_modulus(MontyContext *mc); /* doesn't transfer ownership */
mp_int *monty_identity(MontyContext *mc); /* doesn't transfer ownership */
void monty_import_into(MontyContext *mc, mp_int *r, mp_int *x);
mp_int *monty_import(MontyContext *mc, mp_int *x);
void monty_export_into(MontyContext *mc, mp_int *r, mp_int *x);
mp_int *monty_export(MontyContext *mc, mp_int *x);
void monty_mul_into(MontyContext *, mp_int *r, mp_int *, mp_int *);
mp_int *monty_add(MontyContext *, mp_int *, mp_int *);
mp_int *monty_sub(MontyContext *, mp_int *, mp_int *);
mp_int *monty_mul(MontyContext *, mp_int *, mp_int *);
mp_int *monty_pow(MontyContext *, mp_int *base, mp_int *exponent);
mp_int *monty_invert(MontyContext *, mp_int *);
mp_int *monty_modsqrt(ModsqrtContext *sc, mp_int *mx, unsigned *success);
/*
* Modular arithmetic functions which don't use an explicit
* MontyContext. mp_modpow will use one internally (on the assumption
* that the exponent is likely to be large enough to make it
* worthwhile); the other three will just do ordinary non-Montgomery-
* optimised modular reduction. Use mp_modmul if you only have one
* product to compute; if you have a lot, consider using a
* MontyContext in the client code.
*/
mp_int *mp_modpow(mp_int *base, mp_int *exponent, mp_int *modulus);
mp_int *mp_modmul(mp_int *x, mp_int *y, mp_int *modulus);
mp_int *mp_modadd(mp_int *x, mp_int *y, mp_int *modulus);
mp_int *mp_modsub(mp_int *x, mp_int *y, mp_int *modulus);
/*
* Shift an mp_int right by a given number of bits. The shift count is
* considered to be secret data, and as a result, the algorithm takes
* O(n log n) time instead of the obvious O(n).
*/
mp_int *mp_rshift_safe(mp_int *x, size_t shift);
/*
* Shift an mp_int left or right by a fixed number of bits. The shift
* count is NOT considered to be secret data! Use this if you're
* always dividing by 2, for example, but don't use it to shift by a
* variable amount derived from another secret number.
*
* The upside is that these functions run in sensible linear time.
*/
void mp_lshift_fixed_into(mp_int *r, mp_int *a, size_t shift);
void mp_rshift_fixed_into(mp_int *r, mp_int *x, size_t shift);
mp_int *mp_rshift_fixed(mp_int *x, size_t shift);
/*
* Generate a random mp_int.
*
* The _function_ definitions here will expect to be given a gen_byte
* function that provides random data. Normally you'd use this using
* random_byte() from random.c, and the macro wrappers automate that.
*
* (This is a bit of a dodge to avoid mpint.c having a link-time
* dependency on random.c, so that programs can link against one but
* not the other: if a client of this header uses one of these macros
* then _they_ have link-time dependencies on both modules.)
*
* mp_random_bits[_fn] returns an integer 0 <= n < 2^bits.
* mp_random_in_range[_fn](lo,hi) returns an integer lo <= n < hi.
*/
mp_int *mp_random_bits_fn(size_t bits, int (*gen_byte)(void));
mp_int *mp_random_in_range_fn(
mp_int *lo_inclusive, mp_int *hi_exclusive, int (*gen_byte)(void));
#define mp_random_bits(bits) mp_random_bits_fn(bits, random_byte)
#define mp_random_in_range(lo, hi) mp_random_in_range_fn(lo, hi, random_byte)
#endif /* PUTTY_MPINT_H */

Просмотреть файл

@ -1,10 +1,15 @@
/* /*
* sshbn.h: the assorted conditional definitions of BignumInt and * mpint_i.h: definitions used internally by the bignum code, and
* multiply macros used throughout the bignum code to treat numbers as * also a few other vaguely-bignum-like places.
* arrays of the most conveniently sized word for the target machine. */
/* ----------------------------------------------------------------------
* The assorted conditional definitions of BignumInt and multiply
* macros used throughout the bignum code to treat numbers as arrays
* of the most conveniently sized word for the target machine.
* Exported so that other code (e.g. poly1305) can use it too. * Exported so that other code (e.g. poly1305) can use it too.
* *
* This file must export, in whatever ifdef branch it ends up in: * This code must export, in whatever ifdef branch it ends up in:
* *
* - two types: 'BignumInt' and 'BignumCarry'. BignumInt is an * - two types: 'BignumInt' and 'BignumCarry'. BignumInt is an
* unsigned integer type which will be used as the base word size * unsigned integer type which will be used as the base word size
@ -64,7 +69,7 @@
*/ */
typedef unsigned long long BignumInt; typedef unsigned long long BignumInt;
#define BIGNUM_INT_BITS 64 #define BIGNUM_INT_BITS_BITS 6
#define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt #define DEFINE_BIGNUMDBLINT typedef __uint128_t BignumDblInt
#elif defined _MSC_VER && defined _M_AMD64 #elif defined _MSC_VER && defined _M_AMD64
@ -85,7 +90,7 @@
#include <intrin.h> #include <intrin.h>
typedef unsigned char BignumCarry; /* the type _addcarry_u64 likes to use */ typedef unsigned char BignumCarry; /* the type _addcarry_u64 likes to use */
typedef unsigned __int64 BignumInt; typedef unsigned __int64 BignumInt;
#define BIGNUM_INT_BITS 64 #define BIGNUM_INT_BITS_BITS 6
#define BignumADC(ret, retc, a, b, c) do \ #define BignumADC(ret, retc, a, b, c) do \
{ \ { \
BignumInt ADC_tmp; \ BignumInt ADC_tmp; \
@ -119,7 +124,7 @@
/* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */ /* 32-bit BignumInt, using C99 unsigned long long as BignumDblInt */
typedef unsigned int BignumInt; typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS 32 #define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt #define DEFINE_BIGNUMDBLINT typedef unsigned long long BignumDblInt
#elif defined _MSC_VER && defined _M_IX86 #elif defined _MSC_VER && defined _M_IX86
@ -127,7 +132,7 @@
/* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */ /* 32-bit BignumInt, using Visual Studio __int64 as BignumDblInt */
typedef unsigned int BignumInt; typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS 32 #define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt #define DEFINE_BIGNUMDBLINT typedef unsigned __int64 BignumDblInt
#elif defined _LP64 #elif defined _LP64
@ -139,7 +144,7 @@
*/ */
typedef unsigned int BignumInt; typedef unsigned int BignumInt;
#define BIGNUM_INT_BITS 32 #define BIGNUM_INT_BITS_BITS 5
#define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
#else #else
@ -155,15 +160,16 @@
*/ */
typedef unsigned short BignumInt; typedef unsigned short BignumInt;
#define BIGNUM_INT_BITS 16 #define BIGNUM_INT_BITS_BITS 4
#define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt #define DEFINE_BIGNUMDBLINT typedef unsigned long BignumDblInt
#endif #endif
/* /*
* Common code across all branches of that ifdef: define the three * Common code across all branches of that ifdef: define all the
* easy constant macros in terms of BIGNUM_INT_BITS. * easy constant macros in terms of BIGNUM_INT_BITS_BITS.
*/ */
#define BIGNUM_INT_BITS (1 << BIGNUM_INT_BITS_BITS)
#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8) #define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
#define BIGNUM_TOP_BIT (((BignumInt)1) << (BIGNUM_INT_BITS-1)) #define BIGNUM_TOP_BIT (((BignumInt)1) << (BIGNUM_INT_BITS-1))
#define BIGNUM_INT_MASK (BIGNUM_TOP_BIT | (BIGNUM_TOP_BIT-1)) #define BIGNUM_INT_MASK (BIGNUM_TOP_BIT | (BIGNUM_TOP_BIT-1))
@ -218,3 +224,58 @@
} while (0) } while (0)
#endif /* DEFINE_BIGNUMDBLINT */ #endif /* DEFINE_BIGNUMDBLINT */
/* ----------------------------------------------------------------------
* Data structures used inside bignum.c.
*/
struct mp_int {
size_t nw;
BignumInt *w;
};
struct MontyContext {
/*
* The actual modulus.
*/
mp_int *m;
/*
* Montgomery multiplication works by selecting a value r > m,
* coprime to m, which is really easy to divide by. In binary
* arithmetic, that means making it a power of 2; in fact we make
* it a whole number of BignumInt.
*
* We don't store r directly as an mp_int (there's no need). But
* its value is 2^rbits; we also store rw = rbits/BIGNUM_INT_BITS
* (the corresponding word offset within an mp_int).
*
* pw is the number of words needed to store an mp_int you're
* doing reduction on: it has to be big enough to hold the sum of
* an input value up to m^2 plus an extra addend up to m*r.
*/
size_t rbits, rw, pw;
/*
* The key step in Montgomery reduction requires the inverse of -m
* mod r.
*/
mp_int *minus_minv_mod_r;
/*
* r^1, r^2 and r^3 mod m, which are used for various purposes.
*
* (Annoyingly, this is one of the rare cases where it would have
* been nicer to have a Pascal-style 1-indexed array. I couldn't
* _quite_ bring myself to put a gratuitous zero element in here.
* So you just have to live with getting r^k by taking the [k-1]th
* element of this array.)
*/
mp_int *powers_of_r_mod_m[3];
/*
* Persistent scratch space from which monty_* functions can
* allocate storage for intermediate values.
*/
mp_int *scratch;
};

Просмотреть файл

@ -7,6 +7,7 @@
#include <assert.h> #include <assert.h>
#include "putty.h" #include "putty.h"
#include "mpint.h"
#include "ssh.h" #include "ssh.h"
#include "pageant.h" #include "pageant.h"
@ -41,37 +42,9 @@ static int cmpkeys_rsa(void *av, void *bv)
{ {
struct RSAKey *a = (struct RSAKey *) av; struct RSAKey *a = (struct RSAKey *) av;
struct RSAKey *b = (struct RSAKey *) bv; struct RSAKey *b = (struct RSAKey *) bv;
Bignum am, bm;
int alen, blen;
am = a->modulus; return ((int)mp_cmp_hs(a->modulus, b->modulus) -
bm = b->modulus; (int)mp_cmp_hs(b->modulus, a->modulus));
/*
* Compare by length of moduli.
*/
alen = bignum_bitcount(am);
blen = bignum_bitcount(bm);
if (alen > blen)
return +1;
else if (alen < blen)
return -1;
/*
* Now compare by moduli themselves.
*/
alen = (alen + 7) / 8; /* byte count */
while (alen-- > 0) {
int abyte, bbyte;
abyte = bignum_byte(am, alen);
bbyte = bignum_byte(bm, alen);
if (abyte > bbyte)
return +1;
else if (abyte < bbyte)
return -1;
}
/*
* Give up.
*/
return 0;
} }
/* /*
@ -251,7 +224,7 @@ void pageant_handle_msg(BinarySink *bs,
*/ */
{ {
struct RSAKey reqkey, *key; struct RSAKey reqkey, *key;
Bignum challenge, response; mp_int *challenge, *response;
ptrlen session_id; ptrlen session_id;
unsigned response_type; unsigned response_type;
unsigned char response_md5[16]; unsigned char response_md5[16];
@ -295,7 +268,7 @@ void pageant_handle_msg(BinarySink *bs,
MD5Init(&md5c); MD5Init(&md5c);
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
put_byte(&md5c, bignum_byte(response, 31 - i)); put_byte(&md5c, mp_get_byte(response, 31 - i));
put_data(&md5c, session_id.ptr, session_id.len); put_data(&md5c, session_id.ptr, session_id.len);
MD5Final(response_md5, &md5c); MD5Final(response_md5, &md5c);
@ -306,8 +279,8 @@ void pageant_handle_msg(BinarySink *bs,
challenge1_cleanup: challenge1_cleanup:
if (response) if (response)
freebn(response); mp_free(response);
freebn(challenge); mp_free(challenge);
freersakey(&reqkey); freersakey(&reqkey);
} }
break; break;
@ -1275,7 +1248,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
request = strbuf_new_for_agent_query(); request = strbuf_new_for_agent_query();
put_byte(request, SSH1_AGENTC_ADD_RSA_IDENTITY); put_byte(request, SSH1_AGENTC_ADD_RSA_IDENTITY);
put_uint32(request, bignum_bitcount(rkey->modulus)); put_uint32(request, mp_get_nbits(rkey->modulus));
put_mp_ssh1(request, rkey->modulus); put_mp_ssh1(request, rkey->modulus);
put_mp_ssh1(request, rkey->exponent); put_mp_ssh1(request, rkey->exponent);
put_mp_ssh1(request, rkey->private_exponent); put_mp_ssh1(request, rkey->private_exponent);

169
ssh.h
Просмотреть файл

@ -390,10 +390,6 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...);
#define SSH_CIPHER_3DES 3 #define SSH_CIPHER_3DES 3
#define SSH_CIPHER_BLOWFISH 6 #define SSH_CIPHER_BLOWFISH 6
#ifndef BIGNUM_INTERNAL
typedef void *Bignum;
#endif
typedef struct ssh_keyalg ssh_keyalg; typedef struct ssh_keyalg ssh_keyalg;
typedef struct ssh_key { typedef struct ssh_key {
const struct ssh_keyalg *vt; const struct ssh_keyalg *vt;
@ -402,57 +398,52 @@ typedef struct ssh_key {
struct RSAKey { struct RSAKey {
int bits; int bits;
int bytes; int bytes;
Bignum modulus; mp_int *modulus;
Bignum exponent; mp_int *exponent;
Bignum private_exponent; mp_int *private_exponent;
Bignum p; mp_int *p;
Bignum q; mp_int *q;
Bignum iqmp; mp_int *iqmp;
char *comment; char *comment;
ssh_key sshk; ssh_key sshk;
}; };
struct dss_key { struct dss_key {
Bignum p, q, g, y, x; mp_int *p, *q, *g, *y, *x;
ssh_key sshk; ssh_key sshk;
}; };
struct ec_curve; struct ec_curve;
struct ec_point {
const struct ec_curve *curve;
Bignum x, y;
Bignum z; /* Jacobian denominator */
bool infinity;
};
/* A couple of ECC functions exported for use outside sshecc.c */
struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b);
void ec_point_free(struct ec_point *point);
/* Weierstrass form curve */ /* Weierstrass form curve */
struct ec_wcurve struct ec_wcurve
{ {
Bignum a, b, n; WeierstrassCurve *wc;
struct ec_point G; WeierstrassPoint *G;
mp_int *G_order;
}; };
/* Montgomery form curve */ /* Montgomery form curve */
struct ec_mcurve struct ec_mcurve
{ {
Bignum a, b; MontgomeryCurve *mc;
struct ec_point G; MontgomeryPoint *G;
}; };
/* Edwards form curve */ /* Edwards form curve */
struct ec_ecurve struct ec_ecurve
{ {
Bignum l, d; EdwardsCurve *ec;
struct ec_point B; EdwardsPoint *G;
mp_int *G_order;
}; };
typedef enum EllipticCurveType {
EC_WEIERSTRASS, EC_MONTGOMERY, EC_EDWARDS
} EllipticCurveType;
struct ec_curve { struct ec_curve {
enum { EC_WEIERSTRASS, EC_MONTGOMERY, EC_EDWARDS } type; EllipticCurveType type;
/* 'name' is the identifier of the curve when it has to appear in /* 'name' is the identifier of the curve when it has to appear in
* wire protocol encodings, as it does in e.g. the public key and * wire protocol encodings, as it does in e.g. the public key and
* signature formats for NIST curves. Curves which do not format * signature formats for NIST curves. Curves which do not format
@ -461,8 +452,8 @@ struct ec_curve {
* 'textname' is non-NULL for all curves, and is a human-readable * 'textname' is non-NULL for all curves, and is a human-readable
* identification suitable for putting in log messages. */ * identification suitable for putting in log messages. */
const char *name, *textname; const char *name, *textname;
unsigned int fieldBits; size_t fieldBits, fieldBytes;
Bignum p; mp_int *p;
union { union {
struct ec_wcurve w; struct ec_wcurve w;
struct ec_mcurve m; struct ec_mcurve m;
@ -481,13 +472,21 @@ bool ec_ed_alg_and_curve_by_bits(int bits,
const struct ec_curve **curve, const struct ec_curve **curve,
const ssh_keyalg **alg); const ssh_keyalg **alg);
struct ec_key { struct ecdsa_key {
struct ec_point publicKey; const struct ec_curve *curve;
Bignum privateKey; WeierstrassPoint *publicKey;
mp_int *privateKey;
ssh_key sshk;
};
struct eddsa_key {
const struct ec_curve *curve;
EdwardsPoint *publicKey;
mp_int *privateKey;
ssh_key sshk; ssh_key sshk;
}; };
struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve); WeierstrassPoint *ecdsa_public(mp_int *private_key, const ssh_keyalg *alg);
EdwardsPoint *eddsa_public(mp_int *private_key, const ssh_keyalg *alg);
/* /*
* SSH-1 never quite decided which order to store the two components * SSH-1 never quite decided which order to store the two components
@ -504,8 +503,9 @@ void BinarySource_get_rsa_ssh1_pub(
void BinarySource_get_rsa_ssh1_priv( void BinarySource_get_rsa_ssh1_priv(
BinarySource *src, struct RSAKey *rsa); BinarySource *src, struct RSAKey *rsa);
bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key); bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key);
Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key); mp_int *rsa_ssh1_decrypt(mp_int *input, struct RSAKey *key);
bool rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf); bool rsa_ssh1_decrypt_pkcs1(mp_int *input, struct RSAKey *key,
strbuf *outbuf);
char *rsastr_fmt(struct RSAKey *key); char *rsastr_fmt(struct RSAKey *key);
char *rsa_ssh1_fingerprint(struct RSAKey *key); char *rsa_ssh1_fingerprint(struct RSAKey *key);
bool rsa_verify(struct RSAKey *key); bool rsa_verify(struct RSAKey *key);
@ -538,25 +538,26 @@ int ssh_rsakex_klen(struct RSAKey *key);
void ssh_rsakex_encrypt(const struct ssh_hashalg *h, void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
unsigned char *in, int inlen, unsigned char *in, int inlen,
unsigned char *out, int outlen, struct RSAKey *key); unsigned char *out, int outlen, struct RSAKey *key);
Bignum ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext, mp_int *ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
struct RSAKey *rsa); struct RSAKey *rsa);
/* /*
* SSH2 ECDH key exchange functions * SSH2 ECDH key exchange functions
*/ */
struct ssh_kex; struct ssh_kex;
typedef struct ecdh_key ecdh_key;
const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex); const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex);
struct ec_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex); ecdh_key *ssh_ecdhkex_newkey(const struct ssh_kex *kex);
void ssh_ecdhkex_freekey(struct ec_key *key); void ssh_ecdhkex_freekey(ecdh_key *key);
void ssh_ecdhkex_getpublic(struct ec_key *key, BinarySink *bs); void ssh_ecdhkex_getpublic(ecdh_key *key, BinarySink *bs);
Bignum ssh_ecdhkex_getkey(struct ec_key *key, mp_int *ssh_ecdhkex_getkey(ecdh_key *key, ptrlen remoteKey);
const void *remoteKey, int remoteKeyLen);
/* /*
* Helper function for k generation in DSA, reused in ECDSA * Helper function for k generation in DSA, reused in ECDSA
*/ */
Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key, mp_int *dss_gen_k(const char *id_string,
unsigned char *digest, int digest_len); mp_int *modulus, mp_int *private_key,
unsigned char *digest, int digest_len);
struct ssh2_cipheralg; struct ssh2_cipheralg;
typedef struct ssh2_cipher { typedef struct ssh2_cipher {
@ -740,14 +741,14 @@ typedef struct ssh_hash {
BinarySink_DELEGATE_IMPLEMENTATION; BinarySink_DELEGATE_IMPLEMENTATION;
} ssh_hash; } ssh_hash;
struct ssh_hashalg { typedef struct ssh_hashalg {
ssh_hash *(*new)(const struct ssh_hashalg *alg); ssh_hash *(*new)(const struct ssh_hashalg *alg);
ssh_hash *(*copy)(ssh_hash *); ssh_hash *(*copy)(ssh_hash *);
void (*final)(ssh_hash *, unsigned char *); /* ALSO FREES THE ssh_hash! */ void (*final)(ssh_hash *, unsigned char *); /* ALSO FREES THE ssh_hash! */
void (*free)(ssh_hash *); void (*free)(ssh_hash *);
int hlen; /* output length in bytes */ int hlen; /* output length in bytes */
const char *text_name; const char *text_name;
}; } ssh_hashalg;
#define ssh_hash_new(alg) ((alg)->new(alg)) #define ssh_hash_new(alg) ((alg)->new(alg))
#define ssh_hash_copy(ctx) ((ctx)->vt->copy(ctx)) #define ssh_hash_copy(ctx) ((ctx)->vt->copy(ctx))
@ -1053,58 +1054,15 @@ void *x11_dehexify(ptrlen hex, int *outlen);
Channel *agentf_new(SshChannel *c); Channel *agentf_new(SshChannel *c);
Bignum copybn(Bignum b);
Bignum bn_power_2(int n);
void bn_restore_invariant(Bignum b);
Bignum bignum_from_long(unsigned long n);
void freebn(Bignum b);
Bignum modpow(Bignum base, Bignum exp, Bignum mod);
Bignum modmul(Bignum a, Bignum b, Bignum mod);
Bignum modsub(const Bignum a, const Bignum b, const Bignum n);
void decbn(Bignum n);
extern Bignum Zero, One;
Bignum bignum_from_bytes(const void *data, int nbytes);
Bignum bignum_from_bytes_le(const void *data, int nbytes);
Bignum bignum_random_in_range(const Bignum lower, const Bignum upper);
int bignum_bitcount(Bignum bn);
int bignum_byte(Bignum bn, int i);
int bignum_bit(Bignum bn, int i);
void bignum_set_bit(Bignum bn, int i, int value);
Bignum biggcd(Bignum a, Bignum b);
unsigned short bignum_mod_short(Bignum number, unsigned short modulus);
Bignum bignum_add_long(Bignum number, unsigned long addend);
Bignum bigadd(Bignum a, Bignum b);
Bignum bigsub(Bignum a, Bignum b);
Bignum bigmul(Bignum a, Bignum b);
Bignum bigmuladd(Bignum a, Bignum b, Bignum addend);
Bignum bigdiv(Bignum a, Bignum b);
Bignum bigmod(Bignum a, Bignum b);
Bignum modinv(Bignum number, Bignum modulus);
Bignum bignum_bitmask(Bignum number);
Bignum bignum_rshift(Bignum number, int shift);
Bignum bignum_lshift(Bignum number, int shift);
int bignum_cmp(Bignum a, Bignum b);
char *bignum_decimal(Bignum x);
Bignum bignum_from_decimal(const char *decimal);
void BinarySink_put_mp_ssh1(BinarySink *, Bignum);
void BinarySink_put_mp_ssh2(BinarySink *, Bignum);
Bignum BinarySource_get_mp_ssh1(BinarySource *);
Bignum BinarySource_get_mp_ssh2(BinarySource *);
#ifdef DEBUG
void diagbn(char *prefix, Bignum md);
#endif
bool dh_is_gex(const struct ssh_kex *kex); bool dh_is_gex(const struct ssh_kex *kex);
struct dh_ctx; struct dh_ctx;
struct dh_ctx *dh_setup_group(const struct ssh_kex *kex); struct dh_ctx *dh_setup_group(const struct ssh_kex *kex);
struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval); struct dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval);
int dh_modulus_bit_size(const struct dh_ctx *ctx); int dh_modulus_bit_size(const struct dh_ctx *ctx);
void dh_cleanup(struct dh_ctx *); void dh_cleanup(struct dh_ctx *);
Bignum dh_create_e(struct dh_ctx *, int nbits); mp_int *dh_create_e(struct dh_ctx *, int nbits);
const char *dh_validate_f(struct dh_ctx *, Bignum f); const char *dh_validate_f(struct dh_ctx *, mp_int *f);
Bignum dh_find_K(struct dh_ctx *, Bignum f); mp_int *dh_find_K(struct dh_ctx *, mp_int *f);
bool rsa_ssh1_encrypted(const Filename *filename, char **comment); bool rsa_ssh1_encrypted(const Filename *filename, char **comment);
int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs, int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
@ -1114,6 +1072,14 @@ int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
bool rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key, bool rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key,
char *passphrase); char *passphrase);
static inline bool is_base64_char(char c)
{
return ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
c == '+' || c == '/' || c == '=');
}
extern int base64_decode_atom(const char *atom, unsigned char *out); extern int base64_decode_atom(const char *atom, unsigned char *out);
extern int base64_lines(int datalen); extern int base64_lines(int datalen);
extern void base64_encode_atom(const unsigned char *data, int n, char *out); extern void base64_encode_atom(const unsigned char *data, int n, char *out);
@ -1233,12 +1199,13 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
void *pfnparam); void *pfnparam);
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
void *pfnparam); void *pfnparam);
int ec_generate(struct ec_key *key, int bits, progfn_t pfn, int ecdsa_generate(struct ecdsa_key *key, int bits, progfn_t pfn,
void *pfnparam); void *pfnparam);
int ec_edgenerate(struct ec_key *key, int bits, progfn_t pfn, int eddsa_generate(struct eddsa_key *key, int bits, progfn_t pfn,
void *pfnparam); void *pfnparam);
Bignum primegen(int bits, int modulus, int residue, Bignum factor, mp_int *primegen(
int phase, progfn_t pfn, void *pfnparam, unsigned firstbits); int bits, int modulus, int residue, mp_int *factor,
int phase, progfn_t pfn, void *pfnparam, unsigned firstbits);
void invent_firstbits(unsigned *one, unsigned *two); void invent_firstbits(unsigned *one, unsigned *two);
/* /*

Просмотреть файл

@ -5,6 +5,7 @@
#include <assert.h> #include <assert.h>
#include "putty.h" #include "putty.h"
#include "mpint.h"
#include "ssh.h" #include "ssh.h"
#include "sshbpp.h" #include "sshbpp.h"
#include "sshppl.h" #include "sshppl.h"
@ -29,7 +30,7 @@ struct ssh1_login_server_state {
struct RSAKey *servkey, *hostkey; struct RSAKey *servkey, *hostkey;
bool servkey_generated_here; bool servkey_generated_here;
Bignum sesskey; mp_int *sesskey;
AuthPolicy *authpolicy; AuthPolicy *authpolicy;
unsigned ap_methods, current_method; unsigned ap_methods, current_method;
@ -206,8 +207,8 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
struct RSAKey *smaller, *larger; struct RSAKey *smaller, *larger;
strbuf *data = strbuf_new(); strbuf *data = strbuf_new();
if (bignum_bitcount(s->hostkey->modulus) > if (mp_get_nbits(s->hostkey->modulus) >
bignum_bitcount(s->servkey->modulus)) { mp_get_nbits(s->servkey->modulus)) {
larger = s->hostkey; larger = s->hostkey;
smaller = s->servkey; smaller = s->servkey;
} else { } else {
@ -216,13 +217,13 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
} }
if (rsa_ssh1_decrypt_pkcs1(s->sesskey, larger, data)) { if (rsa_ssh1_decrypt_pkcs1(s->sesskey, larger, data)) {
freebn(s->sesskey); mp_free(s->sesskey);
s->sesskey = bignum_from_bytes(data->u, data->len); s->sesskey = mp_from_bytes_be(ptrlen_from_strbuf(data));
data->len = 0; data->len = 0;
if (rsa_ssh1_decrypt_pkcs1(s->sesskey, smaller, data) && if (rsa_ssh1_decrypt_pkcs1(s->sesskey, smaller, data) &&
data->len == sizeof(s->session_key)) { data->len == sizeof(s->session_key)) {
memcpy(s->session_key, data->u, sizeof(s->session_key)); memcpy(s->session_key, data->u, sizeof(s->session_key));
freebn(s->sesskey); mp_free(s->sesskey);
s->sesskey = NULL; /* indicates success */ s->sesskey = NULL; /* indicates success */
} }
} }
@ -288,10 +289,10 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
continue; continue;
{ {
Bignum modulus = get_mp_ssh1(pktin); mp_int *modulus = get_mp_ssh1(pktin);
s->authkey = auth_publickey_ssh1( s->authkey = auth_publickey_ssh1(
s->authpolicy, s->username, modulus); s->authpolicy, s->username, modulus);
freebn(modulus); mp_free(modulus);
} }
if (!s->authkey) if (!s->authkey)
@ -321,7 +322,8 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
continue; continue;
} }
Bignum bn = bignum_from_bytes(rsabuf, s->authkey->bytes); mp_int *bn = mp_from_bytes_be(
make_ptrlen(rsabuf, s->authkey->bytes));
smemclr(rsabuf, s->authkey->bytes); smemclr(rsabuf, s->authkey->bytes);
sfree(rsabuf); sfree(rsabuf);
@ -330,7 +332,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
put_mp_ssh1(pktout, bn); put_mp_ssh1(pktout, bn);
pq_push(s->ppl.out_pq, pktout); pq_push(s->ppl.out_pq, pktout);
freebn(bn); mp_free(bn);
} }
crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL); crMaybeWaitUntilV((pktin = ssh1_login_server_pop(s)) != NULL);

Просмотреть файл

@ -7,6 +7,7 @@
#include "putty.h" #include "putty.h"
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
#include "sshbpp.h" #include "sshbpp.h"
#include "sshppl.h" #include "sshppl.h"
#include "sshcr.h" #include "sshcr.h"
@ -49,7 +50,7 @@ struct ssh1_login_state {
int keyi, nkeys; int keyi, nkeys;
bool authed; bool authed;
struct RSAKey key; struct RSAKey key;
Bignum challenge; mp_int *challenge;
ptrlen comment; ptrlen comment;
int dlgret; int dlgret;
Filename *keyfile; Filename *keyfile;
@ -537,7 +538,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
ppl_logevent("Received RSA challenge"); ppl_logevent("Received RSA challenge");
s->challenge = get_mp_ssh1(pktin); s->challenge = get_mp_ssh1(pktin);
if (get_err(pktin)) { if (get_err(pktin)) {
freebn(s->challenge); mp_free(s->challenge);
ssh_proto_error(s->ppl.ssh, "Server's RSA challenge " ssh_proto_error(s->ppl.ssh, "Server's RSA challenge "
"was badly formatted"); "was badly formatted");
return; return;
@ -549,7 +550,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
agentreq = strbuf_new_for_agent_query(); agentreq = strbuf_new_for_agent_query();
put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE); put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
put_uint32(agentreq, bignum_bitcount(s->key.modulus)); put_uint32(agentreq, mp_get_nbits(s->key.modulus));
put_mp_ssh1(agentreq, s->key.exponent); put_mp_ssh1(agentreq, s->key.exponent);
put_mp_ssh1(agentreq, s->key.modulus); put_mp_ssh1(agentreq, s->key.modulus);
put_mp_ssh1(agentreq, s->challenge); put_mp_ssh1(agentreq, s->challenge);
@ -594,9 +595,9 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
ppl_logevent("No reply received from Pageant"); ppl_logevent("No reply received from Pageant");
} }
} }
freebn(s->key.exponent); mp_free(s->key.exponent);
freebn(s->key.modulus); mp_free(s->key.modulus);
freebn(s->challenge); mp_free(s->challenge);
if (s->authed) if (s->authed)
break; break;
} }
@ -719,11 +720,11 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
{ {
int i; int i;
unsigned char buffer[32]; unsigned char buffer[32];
Bignum challenge, response; mp_int *challenge, *response;
challenge = get_mp_ssh1(pktin); challenge = get_mp_ssh1(pktin);
if (get_err(pktin)) { if (get_err(pktin)) {
freebn(challenge); mp_free(challenge);
ssh_proto_error(s->ppl.ssh, "Server's RSA challenge " ssh_proto_error(s->ppl.ssh, "Server's RSA challenge "
"was badly formatted"); "was badly formatted");
return; return;
@ -732,7 +733,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
freersapriv(&s->key); /* burn the evidence */ freersapriv(&s->key); /* burn the evidence */
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
buffer[i] = bignum_byte(response, 31 - i); buffer[i] = mp_get_byte(response, 31 - i);
} }
{ {
@ -748,8 +749,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
put_data(pkt, buffer, 16); put_data(pkt, buffer, 16);
pq_push(s->ppl.out_pq, pkt); pq_push(s->ppl.out_pq, pkt);
freebn(challenge); mp_free(challenge);
freebn(response); mp_free(response);
} }
crMaybeWaitUntilV((pktin = ssh1_login_pop(s)) crMaybeWaitUntilV((pktin = ssh1_login_pop(s))

Просмотреть файл

@ -11,6 +11,7 @@
#include "sshcr.h" #include "sshcr.h"
#include "storage.h" #include "storage.h"
#include "ssh2transport.h" #include "ssh2transport.h"
#include "mpint.h"
void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted) void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
{ {
@ -170,10 +171,10 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
dh_cleanup(s->dh_ctx); dh_cleanup(s->dh_ctx);
s->dh_ctx = NULL; s->dh_ctx = NULL;
freebn(s->f); s->f = NULL; mp_free(s->f); s->f = NULL;
if (dh_is_gex(s->kex_alg)) { if (dh_is_gex(s->kex_alg)) {
freebn(s->g); s->g = NULL; mp_free(s->g); s->g = NULL;
freebn(s->p); s->p = NULL; mp_free(s->p); s->p = NULL;
} }
} else if (s->kex_alg->main_type == KEXTYPE_ECDH) { } else if (s->kex_alg->main_type == KEXTYPE_ECDH) {
@ -223,7 +224,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
{ {
ptrlen keydata = get_string(pktin); ptrlen keydata = get_string(pktin);
put_stringpl(s->exhash, keydata); put_stringpl(s->exhash, keydata);
s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata.ptr, keydata.len); s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata);
if (!get_err(pktin) && !s->K) { if (!get_err(pktin) && !s->K) {
ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve " ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve "
"point in ECDH reply"); "point in ECDH reply");
@ -501,10 +502,10 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
dh_cleanup(s->dh_ctx); dh_cleanup(s->dh_ctx);
s->dh_ctx = NULL; s->dh_ctx = NULL;
freebn(s->f); s->f = NULL; mp_free(s->f); s->f = NULL;
if (dh_is_gex(s->kex_alg)) { if (dh_is_gex(s->kex_alg)) {
freebn(s->g); s->g = NULL; mp_free(s->g); s->g = NULL;
freebn(s->p); s->p = NULL; mp_free(s->p); s->p = NULL;
} }
#endif #endif
} else { } else {
@ -560,13 +561,13 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
unsigned char *outstr; unsigned char *outstr;
int outstrlen; int outstrlen;
s->K = bn_power_2(nbits - 1); s->K = mp_power_2(nbits - 1);
for (i = 0; i < nbits; i++) { for (i = 0; i < nbits; i++) {
if ((i & 7) == 0) { if ((i & 7) == 0) {
byte = random_byte(); byte = random_byte();
} }
bignum_set_bit(s->K, i, (byte >> (i & 7)) & 1); mp_set_bit(s->K, i, (byte >> (i & 7)) & 1);
} }
/* /*

Просмотреть файл

@ -11,6 +11,7 @@
#include "sshcr.h" #include "sshcr.h"
#include "storage.h" #include "storage.h"
#include "ssh2transport.h" #include "ssh2transport.h"
#include "mpint.h"
void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ppl, void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ppl,
ssh_key *const *hostkeys, int nhostkeys) ssh_key *const *hostkeys, int nhostkeys)
@ -98,7 +99,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
* but not for serious use. * but not for serious use.
*/ */
s->p = primegen(s->pbits, 2, 2, NULL, 1, no_progress, NULL, 1); s->p = primegen(s->pbits, 2, 2, NULL, 1, no_progress, NULL, 1);
s->g = bignum_from_long(2); s->g = mp_from_integer(2);
s->dh_ctx = dh_setup_gex(s->p, s->g); s->dh_ctx = dh_setup_gex(s->p, s->g);
s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;
@ -177,10 +178,10 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
dh_cleanup(s->dh_ctx); dh_cleanup(s->dh_ctx);
s->dh_ctx = NULL; s->dh_ctx = NULL;
freebn(s->f); s->f = NULL; mp_free(s->f); s->f = NULL;
if (dh_is_gex(s->kex_alg)) { if (dh_is_gex(s->kex_alg)) {
freebn(s->g); s->g = NULL; mp_free(s->g); s->g = NULL;
freebn(s->p); s->p = NULL; mp_free(s->p); s->p = NULL;
} }
} else if (s->kex_alg->main_type == KEXTYPE_ECDH) { } else if (s->kex_alg->main_type == KEXTYPE_ECDH) {
ppl_logevent("Doing ECDH key exchange with curve %s and hash %s", ppl_logevent("Doing ECDH key exchange with curve %s and hash %s",
@ -211,7 +212,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
ptrlen keydata = get_string(pktin); ptrlen keydata = get_string(pktin);
put_stringpl(s->exhash, keydata); put_stringpl(s->exhash, keydata);
s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata.ptr, keydata.len); s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata);
if (!get_err(pktin) && !s->K) { if (!get_err(pktin) && !s->K) {
ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve " ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve "
"point in ECDH initial packet"); "point in ECDH initial packet");

Просмотреть файл

@ -11,6 +11,7 @@
#include "sshcr.h" #include "sshcr.h"
#include "storage.h" #include "storage.h"
#include "ssh2transport.h" #include "ssh2transport.h"
#include "mpint.h"
const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = { const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = {
#define ARRAYENT_HOSTKEY_ALGORITHM(type, alg) { &alg, type }, #define ARRAYENT_HOSTKEY_ALGORITHM(type, alg) { &alg, type },
@ -200,10 +201,10 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl)
ssh_key_free(s->hkey); ssh_key_free(s->hkey);
s->hkey = NULL; s->hkey = NULL;
} }
if (s->f) freebn(s->f); if (s->f) mp_free(s->f);
if (s->p) freebn(s->p); if (s->p) mp_free(s->p);
if (s->g) freebn(s->g); if (s->g) mp_free(s->g);
if (s->K) freebn(s->K); if (s->K) mp_free(s->K);
if (s->dh_ctx) if (s->dh_ctx)
dh_cleanup(s->dh_ctx); dh_cleanup(s->dh_ctx);
if (s->rsa_kex_key) if (s->rsa_kex_key)
@ -225,7 +226,7 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl)
*/ */
static void ssh2_mkkey( static void ssh2_mkkey(
struct ssh2_transport_state *s, strbuf *out, struct ssh2_transport_state *s, strbuf *out,
Bignum K, unsigned char *H, char chr, int keylen) mp_int *K, unsigned char *H, char chr, int keylen)
{ {
int hlen = s->kex_alg->hash->hlen; int hlen = s->kex_alg->hash->hlen;
int keylen_padded; int keylen_padded;
@ -1365,7 +1366,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
/* /*
* Free shared secret. * Free shared secret.
*/ */
freebn(s->K); s->K = NULL; mp_free(s->K); s->K = NULL;
/* /*
* Update the specials menu to list the remaining uncertified host * Update the specials menu to list the remaining uncertified host

Просмотреть файл

@ -166,7 +166,7 @@ struct ssh2_transport_state {
int nbits, pbits; int nbits, pbits;
bool warn_kex, warn_hk, warn_cscipher, warn_sccipher; bool warn_kex, warn_hk, warn_cscipher, warn_sccipher;
Bignum p, g, e, f, K; mp_int *p, *g, *e, *f, *K;
strbuf *outgoing_kexinit, *incoming_kexinit; strbuf *outgoing_kexinit, *incoming_kexinit;
strbuf *client_kexinit, *server_kexinit; /* aliases to the above */ strbuf *client_kexinit, *server_kexinit; /* aliases to the above */
int kex_init_value, kex_reply_value; int kex_init_value, kex_reply_value;
@ -176,7 +176,7 @@ struct ssh2_transport_state {
char *keystr, *fingerprint; char *keystr, *fingerprint;
ssh_key *hkey; /* actual host key */ ssh_key *hkey; /* actual host key */
struct RSAKey *rsa_kex_key; /* for RSA kex */ struct RSAKey *rsa_kex_key; /* for RSA kex */
struct ec_key *ecdh_key; /* for ECDH kex */ ecdh_key *ecdh_key; /* for ECDH kex */
unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN]; unsigned char exchange_hash[SSH2_KEX_MAX_HASH_LEN];
bool can_gssapi_keyex; bool can_gssapi_keyex;
bool need_gss_transient_hostkey; bool need_gss_transient_hostkey;

2180
sshbn.c

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -30,7 +30,7 @@
*/ */
#include "ssh.h" #include "ssh.h"
#include "sshbn.h" #include "mpint_i.h"
#ifndef INLINE #ifndef INLINE
#define INLINE #define INLINE

Просмотреть файл

@ -7,6 +7,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "putty.h" #include "putty.h"
#include "mpint.h"
#include "ssh.h" #include "ssh.h"
#include "sshbpp.h" #include "sshbpp.h"
#include "sshppl.h" #include "sshppl.h"
@ -1008,13 +1009,12 @@ void ssh1_compute_session_id(
struct RSAKey *hostkey, struct RSAKey *servkey) struct RSAKey *hostkey, struct RSAKey *servkey)
{ {
struct MD5Context md5c; struct MD5Context md5c;
int i;
MD5Init(&md5c); MD5Init(&md5c);
for (i = (bignum_bitcount(hostkey->modulus) + 7) / 8; i-- ;) for (size_t i = (mp_get_nbits(hostkey->modulus) + 7) / 8; i-- ;)
put_byte(&md5c, bignum_byte(hostkey->modulus, i)); put_byte(&md5c, mp_get_byte(hostkey->modulus, i));
for (i = (bignum_bitcount(servkey->modulus) + 7) / 8; i-- ;) for (size_t i = (mp_get_nbits(servkey->modulus) + 7) / 8; i-- ;)
put_byte(&md5c, bignum_byte(servkey->modulus, i)); put_byte(&md5c, mp_get_byte(servkey->modulus, i));
put_data(&md5c, cookie, 8); put_data(&md5c, cookie, 8);
MD5Final(session_id, &md5c); MD5Final(session_id, &md5c);
} }

193
sshdh.c
Просмотреть файл

@ -2,61 +2,35 @@
* Diffie-Hellman implementation for PuTTY. * Diffie-Hellman implementation for PuTTY.
*/ */
#include <assert.h>
#include "ssh.h" #include "ssh.h"
#include "misc.h"
#include "mpint.h"
/* struct dh_ctx {
* The primes used in the group1 and group14 key exchange. mp_int *x, *e, *p, *q, *g;
*/
static const unsigned char P1[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
}; };
static const unsigned char P14[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF
};
/*
* The generator g = 2 (used for both group1 and group14).
*/
static const unsigned char G[] = { 2 };
struct dh_extra { struct dh_extra {
const unsigned char *pdata, *gdata; /* NULL means group exchange */ bool gex;
int plen, glen; void (*construct)(struct dh_ctx *ctx);
}; };
static void dh_group1_construct(struct dh_ctx *ctx)
{
ctx->p = MP_LITERAL(0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF);
ctx->g = mp_from_integer(2);
}
static void dh_group14_construct(struct dh_ctx *ctx)
{
ctx->p = MP_LITERAL(0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF);
ctx->g = mp_from_integer(2);
}
static const struct dh_extra extra_group1 = { static const struct dh_extra extra_group1 = {
P1, G, lenof(P1), lenof(G), false, dh_group1_construct,
}; };
static const struct ssh_kex ssh_diffiehellman_group1_sha1 = { static const struct ssh_kex ssh_diffiehellman_group1_sha1 = {
@ -74,7 +48,7 @@ const struct ssh_kexes ssh_diffiehellman_group1 = {
}; };
static const struct dh_extra extra_group14 = { static const struct dh_extra extra_group14 = {
P14, G, lenof(P14), lenof(G), false, dh_group14_construct,
}; };
static const struct ssh_kex ssh_diffiehellman_group14_sha256 = { static const struct ssh_kex ssh_diffiehellman_group14_sha256 = {
@ -97,9 +71,7 @@ const struct ssh_kexes ssh_diffiehellman_group14 = {
group14_list group14_list
}; };
static const struct dh_extra extra_gex = { static const struct dh_extra extra_gex = { true };
NULL, NULL, 0, 0,
};
static const struct ssh_kex ssh_diffiehellman_gex_sha256 = { static const struct ssh_kex ssh_diffiehellman_gex_sha256 = {
"diffie-hellman-group-exchange-sha256", NULL, "diffie-hellman-group-exchange-sha256", NULL,
@ -161,27 +133,19 @@ const struct ssh_kexes ssh_gssk5_sha1_kex = {
gssk5_sha1_kex_list gssk5_sha1_kex_list
}; };
/*
* Variables.
*/
struct dh_ctx {
Bignum x, e, p, q, qmask, g;
};
/* /*
* Common DH initialisation. * Common DH initialisation.
*/ */
static void dh_init(struct dh_ctx *ctx) static void dh_init(struct dh_ctx *ctx)
{ {
ctx->q = bignum_rshift(ctx->p, 1); ctx->q = mp_rshift_fixed(ctx->p, 1);
ctx->qmask = bignum_bitmask(ctx->q);
ctx->x = ctx->e = NULL; ctx->x = ctx->e = NULL;
} }
bool dh_is_gex(const struct ssh_kex *kex) bool dh_is_gex(const struct ssh_kex *kex)
{ {
const struct dh_extra *extra = (const struct dh_extra *)kex->extra; const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
return extra->pdata == NULL; return extra->gex;
} }
/* /*
@ -190,9 +154,9 @@ bool dh_is_gex(const struct ssh_kex *kex)
struct dh_ctx *dh_setup_group(const struct ssh_kex *kex) struct dh_ctx *dh_setup_group(const struct ssh_kex *kex)
{ {
const struct dh_extra *extra = (const struct dh_extra *)kex->extra; const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
assert(!extra->gex);
struct dh_ctx *ctx = snew(struct dh_ctx); struct dh_ctx *ctx = snew(struct dh_ctx);
ctx->p = bignum_from_bytes(extra->pdata, extra->plen); extra->construct(ctx);
ctx->g = bignum_from_bytes(extra->gdata, extra->glen);
dh_init(ctx); dh_init(ctx);
return ctx; return ctx;
} }
@ -200,11 +164,11 @@ struct dh_ctx *dh_setup_group(const struct ssh_kex *kex)
/* /*
* Initialise DH for a server-supplied group. * Initialise DH for a server-supplied group.
*/ */
struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval) struct dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval)
{ {
struct dh_ctx *ctx = snew(struct dh_ctx); struct dh_ctx *ctx = snew(struct dh_ctx);
ctx->p = copybn(pval); ctx->p = mp_copy(pval);
ctx->g = copybn(gval); ctx->g = mp_copy(gval);
dh_init(ctx); dh_init(ctx);
return ctx; return ctx;
} }
@ -214,7 +178,7 @@ struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval)
*/ */
int dh_modulus_bit_size(const struct dh_ctx *ctx) int dh_modulus_bit_size(const struct dh_ctx *ctx)
{ {
return bignum_bitcount(ctx->p); return mp_get_nbits(ctx->p);
} }
/* /*
@ -222,12 +186,11 @@ int dh_modulus_bit_size(const struct dh_ctx *ctx)
*/ */
void dh_cleanup(struct dh_ctx *ctx) void dh_cleanup(struct dh_ctx *ctx)
{ {
freebn(ctx->x); mp_free(ctx->x);
freebn(ctx->e); mp_free(ctx->e);
freebn(ctx->p); mp_free(ctx->p);
freebn(ctx->g); mp_free(ctx->g);
freebn(ctx->q); mp_free(ctx->q);
freebn(ctx->qmask);
sfree(ctx); sfree(ctx);
} }
@ -246,49 +209,36 @@ void dh_cleanup(struct dh_ctx *ctx)
* Advances in Cryptology: Proceedings of Eurocrypt '96 * Advances in Cryptology: Proceedings of Eurocrypt '96
* Springer-Verlag, May 1996. * Springer-Verlag, May 1996.
*/ */
Bignum dh_create_e(struct dh_ctx *ctx, int nbits) mp_int *dh_create_e(struct dh_ctx *ctx, int nbits)
{ {
int i; /*
* Lower limit is just 2.
int nbytes; */
unsigned char *buf; mp_int *lo = mp_from_integer(2);
nbytes = (bignum_bitcount(ctx->qmask) + 7) / 8;
buf = snewn(nbytes, unsigned char);
do {
/*
* Create a potential x, by ANDing a string of random bytes
* with qmask.
*/
if (ctx->x)
freebn(ctx->x);
if (nbits == 0 || nbits > bignum_bitcount(ctx->qmask)) {
for (i = 0; i < nbytes; i++)
buf[i] = bignum_byte(ctx->qmask, i) & random_byte();
ctx->x = bignum_from_bytes(buf, nbytes);
} else {
int b, nb;
ctx->x = bn_power_2(nbits);
b = nb = 0;
for (i = 0; i < nbits; i++) {
if (nb == 0) {
nb = 8;
b = random_byte();
}
bignum_set_bit(ctx->x, i, b & 1);
b >>= 1;
nb--;
}
}
} while (bignum_cmp(ctx->x, One) <= 0 || bignum_cmp(ctx->x, ctx->q) >= 0);
sfree(buf);
/* /*
* Done. Now compute e = g^x mod p. * Upper limit.
*/ */
ctx->e = modpow(ctx->g, ctx->x, ctx->p); mp_int *hi = mp_copy(ctx->q);
mp_sub_integer_into(hi, hi, 1);
if (nbits) {
mp_int *pow2 = mp_power_2(nbits+1);
mp_min_into(pow2, pow2, hi);
mp_free(hi);
hi = pow2;
}
/*
* Make a random number in that range.
*/
ctx->x = mp_random_in_range(lo, hi);
mp_free(lo);
mp_free(hi);
/*
* Now compute e = g^x mod p.
*/
ctx->e = mp_modpow(ctx->g, ctx->x, ctx->p);
return ctx->e; return ctx->e;
} }
@ -301,15 +251,16 @@ Bignum dh_create_e(struct dh_ctx *ctx, int nbits)
* they lead to obviously weak keys that even a passive eavesdropper * they lead to obviously weak keys that even a passive eavesdropper
* can figure out.) * can figure out.)
*/ */
const char *dh_validate_f(struct dh_ctx *ctx, Bignum f) const char *dh_validate_f(struct dh_ctx *ctx, mp_int *f)
{ {
if (bignum_cmp(f, One) <= 0) { if (!mp_hs_integer(f, 2)) {
return "f value received is too small"; return "f value received is too small";
} else { } else {
Bignum pm1 = bigsub(ctx->p, One); mp_int *pm1 = mp_copy(ctx->p);
int cmp = bignum_cmp(f, pm1); mp_sub_integer_into(pm1, pm1, 1);
freebn(pm1); unsigned cmp = mp_cmp_hs(f, pm1);
if (cmp >= 0) mp_free(pm1);
if (cmp)
return "f value received is too large"; return "f value received is too large";
} }
return NULL; return NULL;
@ -318,9 +269,7 @@ const char *dh_validate_f(struct dh_ctx *ctx, Bignum f)
/* /*
* DH stage 2: given a number f, compute K = f^x mod p. * DH stage 2: given a number f, compute K = f^x mod p.
*/ */
Bignum dh_find_K(struct dh_ctx *ctx, Bignum f) mp_int *dh_find_K(struct dh_ctx *ctx, mp_int *f)
{ {
Bignum ret; return mp_modpow(f, ctx->x, ctx->p);
ret = modpow(f, ctx->x, ctx->p);
return ret;
} }

180
sshdss.c
Просмотреть файл

@ -7,6 +7,7 @@
#include <assert.h> #include <assert.h>
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
#include "misc.h" #include "misc.h"
static void dss_freekey(ssh_key *key); /* forward reference */ static void dss_freekey(ssh_key *key); /* forward reference */
@ -29,7 +30,7 @@ static ssh_key *dss_new_pub(const ssh_keyalg *self, ptrlen data)
dss->x = NULL; dss->x = NULL;
if (get_err(src) || if (get_err(src) ||
!bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) { mp_eq_integer(dss->p, 0) || mp_eq_integer(dss->q, 0)) {
/* Invalid key. */ /* Invalid key. */
dss_freekey(&dss->sshk); dss_freekey(&dss->sshk);
return NULL; return NULL;
@ -42,29 +43,28 @@ static void dss_freekey(ssh_key *key)
{ {
struct dss_key *dss = container_of(key, struct dss_key, sshk); struct dss_key *dss = container_of(key, struct dss_key, sshk);
if (dss->p) if (dss->p)
freebn(dss->p); mp_free(dss->p);
if (dss->q) if (dss->q)
freebn(dss->q); mp_free(dss->q);
if (dss->g) if (dss->g)
freebn(dss->g); mp_free(dss->g);
if (dss->y) if (dss->y)
freebn(dss->y); mp_free(dss->y);
if (dss->x) if (dss->x)
freebn(dss->x); mp_free(dss->x);
sfree(dss); sfree(dss);
} }
static void append_hex_to_strbuf(strbuf *sb, Bignum *x) static void append_hex_to_strbuf(strbuf *sb, mp_int *x)
{ {
if (sb->len > 0) if (sb->len > 0)
put_byte(sb, ','); put_byte(sb, ',');
put_data(sb, "0x", 2); put_data(sb, "0x", 2);
int nibbles = (3 + bignum_bitcount(x)) / 4; char *hex = mp_get_hex(x);
if (nibbles < 1) size_t hexlen = strlen(hex);
nibbles = 1; put_data(sb, hex, hexlen);
static const char hex[] = "0123456789abcdef"; smemclr(hex, hexlen);
for (int i = nibbles; i--;) sfree(hex);
put_byte(sb, hex[(bignum_byte(x, i / 2) >> (4 * (i % 2))) & 0xF]);
} }
static char *dss_cache_str(ssh_key *key) static char *dss_cache_str(ssh_key *key)
@ -88,7 +88,6 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
struct dss_key *dss = container_of(key, struct dss_key, sshk); struct dss_key *dss = container_of(key, struct dss_key, sshk);
BinarySource src[1]; BinarySource src[1];
unsigned char hash[20]; unsigned char hash[20];
Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v;
bool toret; bool toret;
if (!dss->p) if (!dss->p)
@ -117,29 +116,29 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
} }
/* Now we're sitting on a 40-byte string for sure. */ /* Now we're sitting on a 40-byte string for sure. */
r = bignum_from_bytes(sig.ptr, 20); mp_int *r = mp_from_bytes_be(make_ptrlen(sig.ptr, 20));
s = bignum_from_bytes((const char *)sig.ptr + 20, 20); mp_int *s = mp_from_bytes_be(make_ptrlen((const char *)sig.ptr + 20, 20));
if (!r || !s) { if (!r || !s) {
if (r) if (r)
freebn(r); mp_free(r);
if (s) if (s)
freebn(s); mp_free(s);
return false; return false;
} }
if (!bignum_cmp(s, Zero)) { if (mp_eq_integer(s, 0)) {
freebn(r); mp_free(r);
freebn(s); mp_free(s);
return false; return false;
} }
/* /*
* Step 1. w <- s^-1 mod q. * Step 1. w <- s^-1 mod q.
*/ */
w = modinv(s, dss->q); mp_int *w = mp_invert(s, dss->q);
if (!w) { if (!w) {
freebn(r); mp_free(r);
freebn(s); mp_free(s);
return false; return false;
} }
@ -147,38 +146,38 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
* Step 2. u1 <- SHA(message) * w mod q. * Step 2. u1 <- SHA(message) * w mod q.
*/ */
SHA_Simple(data.ptr, data.len, hash); SHA_Simple(data.ptr, data.len, hash);
sha = bignum_from_bytes(hash, 20); mp_int *sha = mp_from_bytes_be(make_ptrlen(hash, 20));
u1 = modmul(sha, w, dss->q); mp_int *u1 = mp_modmul(sha, w, dss->q);
/* /*
* Step 3. u2 <- r * w mod q. * Step 3. u2 <- r * w mod q.
*/ */
u2 = modmul(r, w, dss->q); mp_int *u2 = mp_modmul(r, w, dss->q);
/* /*
* Step 4. v <- (g^u1 * y^u2 mod p) mod q. * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
*/ */
gu1p = modpow(dss->g, u1, dss->p); mp_int *gu1p = mp_modpow(dss->g, u1, dss->p);
yu2p = modpow(dss->y, u2, dss->p); mp_int *yu2p = mp_modpow(dss->y, u2, dss->p);
gu1yu2p = modmul(gu1p, yu2p, dss->p); mp_int *gu1yu2p = mp_modmul(gu1p, yu2p, dss->p);
v = modmul(gu1yu2p, One, dss->q); mp_int *v = mp_mod(gu1yu2p, dss->q);
/* /*
* Step 5. v should now be equal to r. * Step 5. v should now be equal to r.
*/ */
toret = !bignum_cmp(v, r); toret = mp_cmp_eq(v, r);
freebn(w); mp_free(w);
freebn(sha); mp_free(sha);
freebn(u1); mp_free(u1);
freebn(u2); mp_free(u2);
freebn(gu1p); mp_free(gu1p);
freebn(yu2p); mp_free(yu2p);
freebn(gu1yu2p); mp_free(gu1yu2p);
freebn(v); mp_free(v);
freebn(r); mp_free(r);
freebn(s); mp_free(s);
return toret; return toret;
} }
@ -209,7 +208,7 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv)
ptrlen hash; ptrlen hash;
SHA_State s; SHA_State s;
unsigned char digest[20]; unsigned char digest[20];
Bignum ytest; mp_int *ytest;
sshk = dss_new_pub(self, pub); sshk = dss_new_pub(self, pub);
if (!sshk) if (!sshk)
@ -233,7 +232,7 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv)
put_mp_ssh2(&s, dss->q); put_mp_ssh2(&s, dss->q);
put_mp_ssh2(&s, dss->g); put_mp_ssh2(&s, dss->g);
SHA_Final(&s, digest); SHA_Final(&s, digest);
if (0 != memcmp(hash.ptr, digest, 20)) { if (!smemeq(hash.ptr, digest, 20)) {
dss_freekey(&dss->sshk); dss_freekey(&dss->sshk);
return NULL; return NULL;
} }
@ -242,13 +241,13 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv)
/* /*
* Now ensure g^x mod p really is y. * Now ensure g^x mod p really is y.
*/ */
ytest = modpow(dss->g, dss->x, dss->p); ytest = mp_modpow(dss->g, dss->x, dss->p);
if (0 != bignum_cmp(ytest, dss->y)) { if (!mp_cmp_eq(ytest, dss->y)) {
mp_free(ytest);
dss_freekey(&dss->sshk); dss_freekey(&dss->sshk);
freebn(ytest);
return NULL; return NULL;
} }
freebn(ytest); mp_free(ytest);
return &dss->sshk; return &dss->sshk;
} }
@ -268,7 +267,7 @@ static ssh_key *dss_new_priv_openssh(const ssh_keyalg *self,
dss->x = get_mp_ssh2(src); dss->x = get_mp_ssh2(src);
if (get_err(src) || if (get_err(src) ||
!bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) { mp_eq_integer(dss->q, 0) || mp_eq_integer(dss->p, 0)) {
/* Invalid key. */ /* Invalid key. */
dss_freekey(&dss->sshk); dss_freekey(&dss->sshk);
return NULL; return NULL;
@ -299,14 +298,15 @@ static int dss_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
return -1; return -1;
dss = container_of(sshk, struct dss_key, sshk); dss = container_of(sshk, struct dss_key, sshk);
ret = bignum_bitcount(dss->p); ret = mp_get_nbits(dss->p);
dss_freekey(&dss->sshk); dss_freekey(&dss->sshk);
return ret; return ret;
} }
Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key, mp_int *dss_gen_k(const char *id_string, mp_int *modulus,
unsigned char *digest, int digest_len) mp_int *private_key,
unsigned char *digest, int digest_len)
{ {
/* /*
* The basic DSS signing algorithm is: * The basic DSS signing algorithm is:
@ -381,7 +381,6 @@ Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
*/ */
SHA512_State ss; SHA512_State ss;
unsigned char digest512[64]; unsigned char digest512[64];
Bignum proto_k, k;
/* /*
* Hash some identifying text plus x. * Hash some identifying text plus x.
@ -397,72 +396,63 @@ Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
SHA512_Init(&ss); SHA512_Init(&ss);
put_data(&ss, digest512, sizeof(digest512)); put_data(&ss, digest512, sizeof(digest512));
put_data(&ss, digest, digest_len); put_data(&ss, digest, digest_len);
SHA512_Final(&ss, digest512);
while (1) { /*
SHA512_State ss2 = ss; /* structure copy */ * Now convert the result into a bignum, and coerce it to the
SHA512_Final(&ss2, digest512); * 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(&ss2, sizeof(ss2)); smemclr(&ss, sizeof(ss));
smemclr(digest512, sizeof(digest512));
/* return k;
* Now convert the result into a bignum, and reduce it mod q.
*/
proto_k = bignum_from_bytes(digest512, 64);
k = bigmod(proto_k, modulus);
freebn(proto_k);
if (bignum_cmp(k, One) != 0 && bignum_cmp(k, Zero) != 0) {
smemclr(&ss, sizeof(ss));
smemclr(digest512, sizeof(digest512));
return k;
}
/* Very unlikely we get here, but if so, k was unsuitable. */
freebn(k);
/* Perturb the hash to think of a different k. */
put_byte(&ss, 'x');
/* Go round and try again. */
}
} }
static void dss_sign(ssh_key *key, const void *data, int datalen, static void dss_sign(ssh_key *key, const void *data, int datalen,
unsigned flags, BinarySink *bs) unsigned flags, BinarySink *bs)
{ {
struct dss_key *dss = container_of(key, struct dss_key, sshk); struct dss_key *dss = container_of(key, struct dss_key, sshk);
Bignum k, gkp, hash, kinv, hxr, r, s;
unsigned char digest[20]; unsigned char digest[20];
int i; int i;
SHA_Simple(data, datalen, digest); SHA_Simple(data, datalen, digest);
k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x, mp_int *k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x,
digest, sizeof(digest)); digest, sizeof(digest));
kinv = modinv(k, dss->q); /* k^-1 mod q */ mp_int *kinv = mp_invert(k, dss->q); /* k^-1 mod q */
assert(kinv);
/* /*
* Now we have k, so just go ahead and compute the signature. * Now we have k, so just go ahead and compute the signature.
*/ */
gkp = modpow(dss->g, k, dss->p); /* g^k mod p */ mp_int *gkp = mp_modpow(dss->g, k, dss->p); /* g^k mod p */
r = bigmod(gkp, dss->q); /* r = (g^k mod p) mod q */ mp_int *r = mp_mod(gkp, dss->q); /* r = (g^k mod p) mod q */
freebn(gkp); mp_free(gkp);
hash = bignum_from_bytes(digest, 20); mp_int *hash = mp_from_bytes_be(make_ptrlen(digest, 20));
hxr = bigmuladd(dss->x, r, hash); /* hash + x*r */ mp_int *hxr = mp_mul(dss->x, r);
s = modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash + x*r) mod q */ mp_add_into(hxr, hxr, hash); /* hash + x*r */
freebn(hxr); mp_int *s = mp_modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash+x*r) mod q */
freebn(kinv); mp_free(hxr);
freebn(k); mp_free(kinv);
freebn(hash); mp_free(k);
mp_free(hash);
put_stringz(bs, "ssh-dss"); put_stringz(bs, "ssh-dss");
put_uint32(bs, 40); put_uint32(bs, 40);
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
put_byte(bs, bignum_byte(r, 19 - i)); put_byte(bs, mp_get_byte(r, 19 - i));
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
put_byte(bs, bignum_byte(s, 19 - i)); put_byte(bs, mp_get_byte(s, 19 - i));
freebn(r); mp_free(r);
freebn(s); mp_free(s);
} }
const ssh_keyalg ssh_dss = { const ssh_keyalg ssh_dss = {

Просмотреть файл

@ -4,16 +4,11 @@
#include "misc.h" #include "misc.h"
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
void *pfnparam) void *pfnparam)
{ {
Bignum qm1, power, g, h, tmp;
unsigned pfirst, qfirst;
int progress;
key->sshk.vt = &ssh_dss;
/* /*
* Set up the phase limits for the progress report. We do this * Set up the phase limits for the progress report. We do this
* by passing minus the phase number. * by passing minus the phase number.
@ -59,30 +54,19 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x2000); pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x2000);
pfn(pfnparam, PROGFN_EXP_PHASE, 3, -32768); pfn(pfnparam, PROGFN_EXP_PHASE, 3, -32768);
/*
* In phase four we are finding an element x between 1 and q-1
* (exclusive), by inventing 160 random bits and hoping they
* come out to a plausible number; so assuming q is uniformly
* distributed between 2^159 and 2^160, the chance of any given
* attempt succeeding is somewhere between 0.5 and 1. Lacking
* the energy to arrange to be able to specify this probability
* _after_ generating q, we'll just set it to 0.75.
*/
pfn(pfnparam, PROGFN_PHASE_EXTENT, 4, 0x2000);
pfn(pfnparam, PROGFN_EXP_PHASE, 4, -49152);
pfn(pfnparam, PROGFN_READY, 0, 0); pfn(pfnparam, PROGFN_READY, 0, 0);
unsigned pfirst, qfirst;
invent_firstbits(&pfirst, &qfirst); invent_firstbits(&pfirst, &qfirst);
/* /*
* Generate q: a prime of length 160. * Generate q: a prime of length 160.
*/ */
key->q = primegen(160, 2, 2, NULL, 1, pfn, pfnparam, qfirst); mp_int *q = primegen(160, 2, 2, NULL, 1, pfn, pfnparam, qfirst);
/* /*
* Now generate p: a prime of length `bits', such that p-1 is * Now generate p: a prime of length `bits', such that p-1 is
* divisible by q. * divisible by q.
*/ */
key->p = primegen(bits-160, 2, 2, key->q, 2, pfn, pfnparam, pfirst); mp_int *p = primegen(bits-160, 2, 2, q, 2, pfn, pfnparam, pfirst);
/* /*
* Next we need g. Raise 2 to the power (p-1)/q modulo p, and * Next we need g. Raise 2 to the power (p-1)/q modulo p, and
@ -90,58 +74,40 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
* soon as we hit a non-unit (and non-zero!) one, that'll do * soon as we hit a non-unit (and non-zero!) one, that'll do
* for g. * for g.
*/ */
power = bigdiv(key->p, key->q); /* this is floor(p/q) == (p-1)/q */ mp_int *power = mp_div(p, q); /* this is floor(p/q) == (p-1)/q */
h = bignum_from_long(1); mp_int *h = mp_from_integer(1);
progress = 0; int progress = 0;
mp_int *g;
while (1) { while (1) {
pfn(pfnparam, PROGFN_PROGRESS, 3, ++progress); pfn(pfnparam, PROGFN_PROGRESS, 3, ++progress);
g = modpow(h, power, key->p); g = mp_modpow(h, power, p);
if (bignum_cmp(g, One) > 0) if (mp_hs_integer(g, 2))
break; /* got one */ break; /* got one */
tmp = h; mp_free(g);
h = bignum_add_long(h, 1); mp_add_integer_into(h, h, 1);
freebn(tmp);
} }
key->g = g; mp_free(h);
freebn(h); mp_free(power);
/* /*
* Now we're nearly done. All we need now is our private key x, * Now we're nearly done. All we need now is our private key x,
* which should be a number between 1 and q-1 exclusive, and * which should be a number between 1 and q-1 exclusive, and
* our public key y = g^x mod p. * our public key y = g^x mod p.
*/ */
qm1 = copybn(key->q); mp_int *two = mp_from_integer(2);
decbn(qm1); mp_int *qm1 = mp_copy(q);
progress = 0; mp_sub_integer_into(qm1, qm1, 1);
while (1) { mp_int *x = mp_random_in_range(two, qm1);
int i, v, byte, bitsleft; mp_free(two);
Bignum x; mp_free(qm1);
pfn(pfnparam, PROGFN_PROGRESS, 4, ++progress); key->sshk.vt = &ssh_dss;
x = bn_power_2(159);
byte = 0;
bitsleft = 0;
for (i = 0; i < 160; i++) { key->p = p;
if (bitsleft <= 0) key->q = q;
bitsleft = 8, byte = random_byte(); key->g = g;
v = byte & 1; key->x = x;
byte >>= 1; key->y = mp_modpow(key->g, key->x, key->p);
bitsleft--;
bignum_set_bit(x, i, v);
}
if (bignum_cmp(x, One) <= 0 || bignum_cmp(x, qm1) >= 0) {
freebn(x);
continue;
} else {
key->x = x;
break;
}
}
freebn(qm1);
key->y = modpow(key->g, key->x, key->p);
return 1; return 1;
} }

3305
sshecc.c

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -3,66 +3,36 @@
*/ */
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
int ec_generate(struct ec_key *key, int bits, progfn_t pfn, int ecdsa_generate(struct ecdsa_key *ek, int bits,
void *pfnparam) progfn_t pfn, void *pfnparam)
{ {
struct ec_point *publicKey; if (!ec_nist_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt))
if (!ec_nist_alg_and_curve_by_bits(bits, &key->publicKey.curve,
&key->sshk.vt))
return 0; return 0;
key->privateKey = bignum_random_in_range(One, key->publicKey.curve->w.n); mp_int *one = mp_from_integer(1);
if (!key->privateKey) return 0; ek->privateKey = mp_random_in_range(one, ek->curve->w.G_order);
mp_free(one);
publicKey = ec_public(key->privateKey, key->publicKey.curve); ek->publicKey = ecdsa_public(ek->privateKey, ek->sshk.vt);
if (!publicKey) {
freebn(key->privateKey);
key->privateKey = NULL;
return 0;
}
key->publicKey.x = publicKey->x;
key->publicKey.y = publicKey->y;
key->publicKey.z = NULL;
sfree(publicKey);
return 1; return 1;
} }
int ec_edgenerate(struct ec_key *key, int bits, progfn_t pfn, int eddsa_generate(struct eddsa_key *ek, int bits,
void *pfnparam) progfn_t pfn, void *pfnparam)
{ {
struct ec_point *publicKey; if (!ec_ed_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt))
if (!ec_ed_alg_and_curve_by_bits(bits, &key->publicKey.curve,
&key->sshk.vt))
return 0; return 0;
{ /* EdDSA secret keys are just 32 bytes of hash preimage; the
/* EdDSA secret keys are just 32 bytes of hash preimage; the * 64-byte SHA-512 hash of that key will be used when signing,
* 64-byte SHA-512 hash of that key will be used when signing, * but the form of the key stored on disk is the preimage
* but the form of the key stored on disk is the preimage * only. */
* only. */ ek->privateKey = mp_random_bits(bits);
Bignum privMax = bn_power_2(bits);
if (!privMax) return 0;
key->privateKey = bignum_random_in_range(Zero, privMax);
freebn(privMax);
if (!key->privateKey) return 0;
}
publicKey = ec_public(key->privateKey, key->publicKey.curve); ek->publicKey = eddsa_public(ek->privateKey, ek->sshk.vt);
if (!publicKey) {
freebn(key->privateKey);
key->privateKey = NULL;
return 0;
}
key->publicKey.x = publicKey->x;
key->publicKey.y = publicKey->y;
key->publicKey.z = NULL;
sfree(publicKey);
return 1; return 1;
} }

Просмотреть файл

@ -4,6 +4,7 @@
#include <assert.h> #include <assert.h>
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
/* /*
* This prime generation algorithm is pretty much cribbed from * This prime generation algorithm is pretty much cribbed from
@ -134,6 +135,23 @@ static void init_primes_array(void)
assert(pos == NPRIMES); assert(pos == NPRIMES);
} }
static unsigned short mp_mod_short(mp_int *x, unsigned short modulus)
{
/*
* This function lives here rather than in mpint.c partly because
* this is the only place it's needed, but mostly because it
* doesn't pay careful attention to constant running time, since
* as far as I can tell that's a lost cause for key generation
* anyway.
*/
unsigned accumulator = 0;
for (size_t i = mp_max_bytes(x); i-- > 0 ;) {
accumulator = 0x100 * accumulator + mp_get_byte(x, i);
accumulator %= modulus;
}
return accumulator;
}
/* /*
* Generate a prime. We can deal with various extra properties of * Generate a prime. We can deal with various extra properties of
* the prime: * the prime:
@ -154,23 +172,15 @@ static void init_primes_array(void)
* 'firstbits' is not needed, specifying it to either 0 or 1 is * 'firstbits' is not needed, specifying it to either 0 or 1 is
* an adequate no-op. * an adequate no-op.
*/ */
Bignum primegen(int bits, int modulus, int residue, Bignum factor, mp_int *primegen(
int phase, progfn_t pfn, void *pfnparam, unsigned firstbits) int bits, int modulus, int residue, mp_int *factor,
int phase, progfn_t pfn, void *pfnparam, unsigned firstbits)
{ {
int i, k, v, byte, bitsleft, check, checks, fbsize;
unsigned long delta;
unsigned long moduli[NPRIMES + 1];
unsigned long residues[NPRIMES + 1];
unsigned long multipliers[NPRIMES + 1];
Bignum p, pm1, q, wqp, wqp2;
int progress = 0;
init_primes_array(); init_primes_array();
byte = 0; int progress = 0;
bitsleft = 0;
fbsize = 0; size_t fbsize = 0;
while (firstbits >> fbsize) /* work out how to align this */ while (firstbits >> fbsize) /* work out how to align this */
fbsize++; fbsize++;
@ -184,184 +194,172 @@ Bignum primegen(int bits, int modulus, int residue, Bignum factor,
* random number with the top bit set and the bottom bit clear, * random number with the top bit set and the bottom bit clear,
* multiply it by `factor', and add one. * multiply it by `factor', and add one.
*/ */
p = bn_power_2(bits - 1); mp_int *p = mp_random_bits(bits - 1);
for (i = 0; i < bits; i++) {
if (i == 0 || i == bits - 1) { mp_set_bit(p, 0, factor ? 0 : 1); /* bottom bit */
v = (i != 0 || !factor) ? 1 : 0; mp_set_bit(p, bits-1, 1); /* top bit */
} else if (i >= bits - fbsize) { for (size_t i = 0; i < fbsize; i++)
v = (firstbits >> (i - (bits - fbsize))) & 1; mp_set_bit(p, bits-fbsize + i, 1 & (firstbits >> i));
} else {
if (bitsleft <= 0)
bitsleft = 8, byte = random_byte();
v = byte & 1;
byte >>= 1;
bitsleft--;
}
bignum_set_bit(p, i, v);
}
if (factor) { if (factor) {
Bignum tmp = p; mp_int *tmp = p;
p = bigmul(tmp, factor); p = mp_mul(tmp, factor);
freebn(tmp); mp_free(tmp);
assert(bignum_bit(p, 0) == 0); assert(mp_get_bit(p, 0) == 0);
bignum_set_bit(p, 0, 1); mp_set_bit(p, 0, 1);
} }
/* /*
* Ensure this random number is coprime to the first few * We need to ensure this random number is coprime to the first
* primes, by repeatedly adding either 2 or 2*factor to it * few primes, by repeatedly adding either 2 or 2*factor to it
* until it is. * until it is. To do this we make a list of (modulus, residue)
* pairs to avoid, and we also add to that list the extra pair our
* caller wants to avoid.
*/ */
for (i = 0; i < NPRIMES; i++) {
/* List the moduli */
unsigned long moduli[NPRIMES + 1];
for (size_t i = 0; i < NPRIMES; i++)
moduli[i] = primes[i]; moduli[i] = primes[i];
residues[i] = bignum_mod_short(p, primes[i]); moduli[NPRIMES] = modulus;
/* Find the residue of our starting number mod each of them. Also
* set up the multipliers array which tells us how each one will
* change when we increment the number (which isn't just 1 if
* we're incrementing by multiples of factor). */
unsigned long residues[NPRIMES + 1], multipliers[NPRIMES + 1];
for (size_t i = 0; i < lenof(moduli); i++) {
residues[i] = mp_mod_short(p, moduli[i]);
if (factor) if (factor)
multipliers[i] = bignum_mod_short(factor, primes[i]); multipliers[i] = mp_mod_short(factor, moduli[i]);
else else
multipliers[i] = 1; multipliers[i] = 1;
} }
moduli[NPRIMES] = modulus;
residues[NPRIMES] = (bignum_mod_short(p, (unsigned short) modulus) /* Adjust the last entry so that it avoids a residue other than zero */
+ modulus - residue); residues[NPRIMES] = (residues[NPRIMES] + modulus - residue) % modulus;
if (factor)
multipliers[NPRIMES] = bignum_mod_short(factor, modulus); /*
else * Now loop until no residue in that list is zero, to find a
multipliers[NPRIMES] = 1; * sensible increment. We maintain the increment in an ordinary
delta = 0; * integer, so if it gets too big, we'll have to give up and go
* back to making up a fresh random large integer.
*/
unsigned delta = 0;
while (1) { while (1) {
for (i = 0; i < (sizeof(moduli) / sizeof(*moduli)); i++) for (size_t i = 0; i < lenof(moduli); i++)
if (!((residues[i] + delta * multipliers[i]) % moduli[i])) if (!((residues[i] + delta * multipliers[i]) % moduli[i]))
break; goto found_a_zero;
if (i < (sizeof(moduli) / sizeof(*moduli))) { /* we broke */
delta += 2; /* If we didn't exit that loop by goto, we've got our candidate. */
if (delta > 65536) { break;
freebn(p);
goto STARTOVER; found_a_zero:
} delta += 2;
continue; if (delta > 65536) {
} mp_free(p);
break; goto STARTOVER;
}
} }
q = p;
/*
* Having found a plausible increment, actually add it on.
*/
if (factor) { if (factor) {
Bignum tmp; mp_int *d = mp_from_integer(delta);
tmp = bignum_from_long(delta); mp_int *df = mp_mul(d, factor);
p = bigmuladd(tmp, factor, q); mp_add_into(p, p, df);
freebn(tmp); mp_free(d);
mp_free(df);
} else { } else {
p = bignum_add_long(q, delta); mp_add_integer_into(p, p, delta);
} }
freebn(q);
/* /*
* Now apply the Miller-Rabin primality test a few times. First * Now apply the Miller-Rabin primality test a few times. First
* work out how many checks are needed. * work out how many checks are needed.
*/ */
checks = 27; unsigned checks =
if (bits >= 150) bits >= 1300 ? 2 : bits >= 850 ? 3 : bits >= 650 ? 4 :
checks = 18; bits >= 550 ? 5 : bits >= 450 ? 6 : bits >= 400 ? 7 :
if (bits >= 200) bits >= 350 ? 8 : bits >= 300 ? 9 : bits >= 250 ? 12 :
checks = 15; bits >= 200 ? 15 : bits >= 150 ? 18 : 27;
if (bits >= 250)
checks = 12;
if (bits >= 300)
checks = 9;
if (bits >= 350)
checks = 8;
if (bits >= 400)
checks = 7;
if (bits >= 450)
checks = 6;
if (bits >= 550)
checks = 5;
if (bits >= 650)
checks = 4;
if (bits >= 850)
checks = 3;
if (bits >= 1300)
checks = 2;
/* /*
* Next, write p-1 as q*2^k. * Next, write p-1 as q*2^k.
*/ */
for (k = 0; bignum_bit(p, k) == !k; k++) size_t k;
for (k = 0; mp_get_bit(p, k) == !k; k++)
continue; /* find first 1 bit in p-1 */ continue; /* find first 1 bit in p-1 */
q = bignum_rshift(p, k); mp_int *q = mp_rshift_safe(p, k);
/* And store p-1 itself, which we'll need. */
pm1 = copybn(p); /*
decbn(pm1); * Set up stuff for the Miller-Rabin checks.
*/
mp_int *two = mp_from_integer(2);
mp_int *pm1 = mp_copy(p);
mp_sub_integer_into(pm1, pm1, 1);
MontyContext *mc = monty_new(p);
mp_int *m_pm1 = monty_import(mc, pm1);
bool known_bad = false;
/* /*
* Now, for each check ... * Now, for each check ...
*/ */
for (check = 0; check < checks; check++) { for (unsigned check = 0; check < checks && !known_bad; check++) {
Bignum w;
/* /*
* Invent a random number between 1 and p-1 inclusive. * Invent a random number between 1 and p-1.
*/ */
while (1) { mp_int *w = mp_random_in_range(two, pm1);
w = bn_power_2(bits - 1); monty_import_into(mc, w, w);
for (i = 0; i < bits; i++) {
if (bitsleft <= 0)
bitsleft = 8, byte = random_byte();
v = byte & 1;
byte >>= 1;
bitsleft--;
bignum_set_bit(w, i, v);
}
bn_restore_invariant(w);
if (bignum_cmp(w, p) >= 0 || bignum_cmp(w, Zero) == 0) {
freebn(w);
continue;
}
break;
}
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress); pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
/* /*
* Compute w^q mod p. * Compute w^q mod p.
*/ */
wqp = modpow(w, q, p); mp_int *wqp = monty_pow(mc, w, q);
freebn(w); mp_free(w);
/* /*
* See if this is 1, or if it is -1, or if it becomes -1 * See if this is 1, or if it is -1, or if it becomes -1
* when squared at most k-1 times. * when squared at most k-1 times.
*/ */
if (bignum_cmp(wqp, One) == 0 || bignum_cmp(wqp, pm1) == 0) { bool passed = false;
freebn(wqp);
continue; if (mp_cmp_eq(wqp, monty_identity(mc)) || mp_cmp_eq(wqp, m_pm1)) {
} passed = true;
for (i = 0; i < k - 1; i++) { } else {
wqp2 = modmul(wqp, wqp, p); for (size_t i = 0; i < k - 1; i++) {
freebn(wqp); monty_mul_into(mc, wqp, wqp, wqp);
wqp = wqp2; if (mp_cmp_eq(wqp, m_pm1)) {
if (bignum_cmp(wqp, pm1) == 0) passed = true;
break; break;
} }
if (i < k - 1) { }
freebn(wqp);
continue;
} }
/* if (!passed)
* It didn't. Therefore, w is a witness for the known_bad = true;
* compositeness of p.
*/ mp_free(wqp);
freebn(wqp); }
freebn(p);
freebn(pm1); mp_free(q);
freebn(q); mp_free(two);
goto STARTOVER; mp_free(pm1);
monty_free(mc);
mp_free(m_pm1);
if (known_bad) {
mp_free(p);
goto STARTOVER;
} }
/* /*
* We have a prime! * We have a prime!
*/ */
freebn(q);
freebn(pm1);
return p; return p;
} }

Просмотреть файл

@ -10,6 +10,7 @@
#include <assert.h> #include <assert.h>
#include "putty.h" #include "putty.h"
#include "mpint.h"
#include "ssh.h" #include "ssh.h"
#include "misc.h" #include "misc.h"
@ -276,11 +277,11 @@ int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
} }
memset(&key, 0, sizeof(key)); memset(&key, 0, sizeof(key));
key.exponent = bignum_from_decimal(expp); key.exponent = mp_from_decimal(expp);
key.modulus = bignum_from_decimal(modp); key.modulus = mp_from_decimal(modp);
if (atoi(bitsp) != bignum_bitcount(key.modulus)) { if (atoi(bitsp) != mp_get_nbits(key.modulus)) {
freebn(key.exponent); mp_free(key.exponent);
freebn(key.modulus); mp_free(key.modulus);
sfree(line); sfree(line);
error = "key bit count does not match in SSH-1 public key file"; error = "key bit count does not match in SSH-1 public key file";
goto end; goto end;
@ -1360,10 +1361,9 @@ char *ssh1_pubkey_str(struct RSAKey *key)
char *buffer; char *buffer;
char *dec1, *dec2; char *dec1, *dec2;
dec1 = bignum_decimal(key->exponent); dec1 = mp_get_decimal(key->exponent);
dec2 = bignum_decimal(key->modulus); dec2 = mp_get_decimal(key->modulus);
buffer = dupprintf("%d %s %s%s%s", bignum_bitcount(key->modulus), buffer = dupprintf("%zd %s %s%s%s", mp_get_nbits(key->modulus), dec1, dec2,
dec1, dec2,
key->comment ? " " : "", key->comment ? " " : "",
key->comment ? key->comment : ""); key->comment ? key->comment : "");
sfree(dec1); sfree(dec1);

409
sshrsa.c
Просмотреть файл

@ -8,13 +8,14 @@
#include <assert.h> #include <assert.h>
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
#include "misc.h" #include "misc.h"
void BinarySource_get_rsa_ssh1_pub( void BinarySource_get_rsa_ssh1_pub(
BinarySource *src, struct RSAKey *rsa, RsaSsh1Order order) BinarySource *src, struct RSAKey *rsa, RsaSsh1Order order)
{ {
unsigned bits; unsigned bits;
Bignum e, m; mp_int *e, *m;
bits = get_uint32(src); bits = get_uint32(src);
if (order == RSA_SSH1_EXPONENT_FIRST) { if (order == RSA_SSH1_EXPONENT_FIRST) {
@ -29,10 +30,10 @@ void BinarySource_get_rsa_ssh1_pub(
rsa->bits = bits; rsa->bits = bits;
rsa->exponent = e; rsa->exponent = e;
rsa->modulus = m; rsa->modulus = m;
rsa->bytes = (bignum_bitcount(m) + 7) / 8; rsa->bytes = (mp_get_nbits(m) + 7) / 8;
} else { } else {
freebn(e); mp_free(e);
freebn(m); mp_free(m);
} }
} }
@ -44,7 +45,7 @@ void BinarySource_get_rsa_ssh1_priv(
bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key) bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key)
{ {
Bignum b1, b2; mp_int *b1, *b2;
int i; int i;
unsigned char *p; unsigned char *p;
@ -62,17 +63,17 @@ bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key)
} }
data[key->bytes - length - 1] = 0; data[key->bytes - length - 1] = 0;
b1 = bignum_from_bytes(data, key->bytes); b1 = mp_from_bytes_be(make_ptrlen(data, key->bytes));
b2 = modpow(b1, key->exponent, key->modulus); b2 = mp_modpow(b1, key->exponent, key->modulus);
p = data; p = data;
for (i = key->bytes; i--;) { for (i = key->bytes; i--;) {
*p++ = bignum_byte(b2, i); *p++ = mp_get_byte(b2, i);
} }
freebn(b1); mp_free(b1);
freebn(b2); mp_free(b2);
return true; return true;
} }
@ -83,28 +84,33 @@ bool rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key)
* Uses Chinese Remainder Theorem to speed computation up over the * Uses Chinese Remainder Theorem to speed computation up over the
* obvious implementation of a single big modpow. * obvious implementation of a single big modpow.
*/ */
Bignum crt_modpow(Bignum base, Bignum exp, Bignum mod, mp_int *crt_modpow(mp_int *base, mp_int *exp, mp_int *mod,
Bignum p, Bignum q, Bignum iqmp) mp_int *p, mp_int *q, mp_int *iqmp)
{ {
Bignum pm1, qm1, pexp, qexp, presult, qresult, diff, multiplier, ret0, ret; mp_int *pm1, *qm1, *pexp, *qexp, *presult, *qresult;
mp_int *diff, *multiplier, *ret0, *ret;
/* /*
* Reduce the exponent mod phi(p) and phi(q), to save time when * Reduce the exponent mod phi(p) and phi(q), to save time when
* exponentiating mod p and mod q respectively. Of course, since p * exponentiating mod p and mod q respectively. Of course, since p
* and q are prime, phi(p) == p-1 and similarly for q. * and q are prime, phi(p) == p-1 and similarly for q.
*/ */
pm1 = copybn(p); pm1 = mp_copy(p);
decbn(pm1); mp_sub_integer_into(pm1, pm1, 1);
qm1 = copybn(q); qm1 = mp_copy(q);
decbn(qm1); mp_sub_integer_into(qm1, qm1, 1);
pexp = bigmod(exp, pm1); pexp = mp_mod(exp, pm1);
qexp = bigmod(exp, qm1); qexp = mp_mod(exp, qm1);
/* /*
* Do the two modpows. * Do the two modpows.
*/ */
presult = modpow(base, pexp, p); mp_int *base_mod_p = mp_mod(base, p);
qresult = modpow(base, qexp, q); presult = mp_modpow(base_mod_p, pexp, p);
mp_free(base_mod_p);
mp_int *base_mod_q = mp_mod(base, q);
qresult = mp_modpow(base_mod_q, qexp, q);
mp_free(base_mod_q);
/* /*
* Recombine the results. We want a value which is congruent to * Recombine the results. We want a value which is congruent to
@ -115,189 +121,66 @@ Bignum crt_modpow(Bignum base, Bignum exp, Bignum mod,
* (which is congruent to qresult mod both primes), and add on * (which is congruent to qresult mod both primes), and add on
* (presult-qresult) * (iqmp * q) which adjusts it to be congruent * (presult-qresult) * (iqmp * q) which adjusts it to be congruent
* to presult mod p without affecting its value mod q. * to presult mod p without affecting its value mod q.
*
* (If presult-qresult < 0, we add p to it to keep it positive.)
*/ */
if (bignum_cmp(presult, qresult) < 0) { unsigned presult_too_small = mp_cmp_hs(qresult, presult);
/* mp_cond_add_into(presult, presult, p, presult_too_small);
* Can't subtract presult from qresult without first adding on
* p. diff = mp_sub(presult, qresult);
*/ multiplier = mp_mul(iqmp, q);
Bignum tmp = presult; ret0 = mp_mul(multiplier, diff);
presult = bigadd(presult, p); mp_add_into(ret0, ret0, qresult);
freebn(tmp);
}
diff = bigsub(presult, qresult);
multiplier = bigmul(iqmp, q);
ret0 = bigmuladd(multiplier, diff, qresult);
/* /*
* Finally, reduce the result mod n. * Finally, reduce the result mod n.
*/ */
ret = bigmod(ret0, mod); ret = mp_mod(ret0, mod);
/* /*
* Free all the intermediate results before returning. * Free all the intermediate results before returning.
*/ */
freebn(pm1); mp_free(pm1);
freebn(qm1); mp_free(qm1);
freebn(pexp); mp_free(pexp);
freebn(qexp); mp_free(qexp);
freebn(presult); mp_free(presult);
freebn(qresult); mp_free(qresult);
freebn(diff); mp_free(diff);
freebn(multiplier); mp_free(multiplier);
freebn(ret0); mp_free(ret0);
return ret; return ret;
} }
/* /*
* This function is a wrapper on modpow(). It has the same effect as * Wrapper on crt_modpow that looks up all the right values from an
* modpow(), but employs RSA blinding to protect against timing * RSAKey.
* attacks and also uses the Chinese Remainder Theorem (implemented
* above, in crt_modpow()) to speed up the main operation.
*/ */
static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) static mp_int *rsa_privkey_op(mp_int *input, struct RSAKey *key)
{ {
Bignum random, random_encrypted, random_inverse; return crt_modpow(input, key->private_exponent,
Bignum input_blinded, ret_blinded; key->modulus, key->p, key->q, key->iqmp);
Bignum ret;
SHA512_State ss;
unsigned char digest512[64];
int digestused = lenof(digest512);
int hashseq = 0;
/*
* Start by inventing a random number chosen uniformly from the
* range 2..modulus-1. (We do this by preparing a random number
* of the right length and retrying if it's greater than the
* modulus, to prevent any potential Bleichenbacher-like
* attacks making use of the uneven distribution within the
* range that would arise from just reducing our number mod n.
* There are timing implications to the potential retries, of
* course, but all they tell you is the modulus, which you
* already knew.)
*
* To preserve determinism and avoid Pageant needing to share
* the random number pool, we actually generate this `random'
* number by hashing stuff with the private key.
*/
while (1) {
int bits, byte, bitsleft, v;
random = copybn(key->modulus);
/*
* Find the topmost set bit. (This function will return its
* index plus one.) Then we'll set all bits from that one
* downwards randomly.
*/
bits = bignum_bitcount(random);
byte = 0;
bitsleft = 0;
while (bits--) {
if (bitsleft <= 0) {
bitsleft = 8;
/*
* Conceptually the following few lines are equivalent to
* byte = random_byte();
*/
if (digestused >= lenof(digest512)) {
SHA512_Init(&ss);
put_data(&ss, "RSA deterministic blinding", 26);
put_uint32(&ss, hashseq);
put_mp_ssh2(&ss, key->private_exponent);
SHA512_Final(&ss, digest512);
hashseq++;
/*
* Now hash that digest plus the signature
* input.
*/
SHA512_Init(&ss);
put_data(&ss, digest512, sizeof(digest512));
put_mp_ssh2(&ss, input);
SHA512_Final(&ss, digest512);
digestused = 0;
}
byte = digest512[digestused++];
}
v = byte & 1;
byte >>= 1;
bitsleft--;
bignum_set_bit(random, bits, v);
}
bn_restore_invariant(random);
/*
* Now check that this number is strictly greater than
* zero, and strictly less than modulus.
*/
if (bignum_cmp(random, Zero) <= 0 ||
bignum_cmp(random, key->modulus) >= 0) {
freebn(random);
continue;
}
/*
* Also, make sure it has an inverse mod modulus.
*/
random_inverse = modinv(random, key->modulus);
if (!random_inverse) {
freebn(random);
continue;
}
break;
}
/*
* RSA blinding relies on the fact that (xy)^d mod n is equal
* to (x^d mod n) * (y^d mod n) mod n. We invent a random pair
* y and y^d; then we multiply x by y, raise to the power d mod
* n as usual, and divide by y^d to recover x^d. Thus an
* attacker can't correlate the timing of the modpow with the
* input, because they don't know anything about the number
* that was input to the actual modpow.
*
* The clever bit is that we don't have to do a huge modpow to
* get y and y^d; we will use the number we just invented as
* _y^d_, and use the _public_ exponent to compute (y^d)^e = y
* from it, which is much faster to do.
*/
random_encrypted = crt_modpow(random, key->exponent,
key->modulus, key->p, key->q, key->iqmp);
input_blinded = modmul(input, random_encrypted, key->modulus);
ret_blinded = crt_modpow(input_blinded, key->private_exponent,
key->modulus, key->p, key->q, key->iqmp);
ret = modmul(ret_blinded, random_inverse, key->modulus);
freebn(ret_blinded);
freebn(input_blinded);
freebn(random_inverse);
freebn(random_encrypted);
freebn(random);
return ret;
} }
Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key) mp_int *rsa_ssh1_decrypt(mp_int *input, struct RSAKey *key)
{ {
return rsa_privkey_op(input, key); return rsa_privkey_op(input, key);
} }
bool rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf) bool rsa_ssh1_decrypt_pkcs1(mp_int *input, struct RSAKey *key,
strbuf *outbuf)
{ {
strbuf *data = strbuf_new(); strbuf *data = strbuf_new();
bool success = false; bool success = false;
BinarySource src[1]; BinarySource src[1];
{ {
Bignum *b = rsa_ssh1_decrypt(input, key); mp_int *b = rsa_ssh1_decrypt(input, key);
int i; for (size_t i = (mp_get_nbits(key->modulus) + 7) / 8; i-- > 0 ;) {
for (i = (bignum_bitcount(key->modulus) + 7) / 8; i-- > 0 ;) { put_byte(data, mp_get_byte(b, i));
put_byte(data, bignum_byte(b, i));
} }
freebn(b); mp_free(b);
} }
BinarySource_BARE_INIT(src, data->u, data->len); BinarySource_BARE_INIT(src, data->u, data->len);
@ -321,17 +204,16 @@ bool rsa_ssh1_decrypt_pkcs1(Bignum input, struct RSAKey *key, strbuf *outbuf)
return success; return success;
} }
static void append_hex_to_strbuf(strbuf *sb, Bignum *x) static void append_hex_to_strbuf(strbuf *sb, mp_int *x)
{ {
if (sb->len > 0) if (sb->len > 0)
put_byte(sb, ','); put_byte(sb, ',');
put_data(sb, "0x", 2); put_data(sb, "0x", 2);
int nibbles = (3 + bignum_bitcount(x)) / 4; char *hex = mp_get_hex(x);
if (nibbles < 1) size_t hexlen = strlen(hex);
nibbles = 1; put_data(sb, hex, hexlen);
static const char hex[] = "0123456789abcdef"; smemclr(hex, hexlen);
for (int i = nibbles; i--;) sfree(hex);
put_byte(sb, hex[(bignum_byte(x, i / 2) >> (4 * (i % 2))) & 0xF]);
} }
char *rsastr_fmt(struct RSAKey *key) char *rsastr_fmt(struct RSAKey *key)
@ -361,7 +243,7 @@ char *rsa_ssh1_fingerprint(struct RSAKey *key)
MD5Final(digest, &md5c); MD5Final(digest, &md5c);
out = strbuf_new(); out = strbuf_new();
strbuf_catf(out, "%d ", bignum_bitcount(key->modulus)); strbuf_catf(out, "%d ", mp_get_nbits(key->modulus));
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
strbuf_catf(out, "%s%02x", i ? ":" : "", digest[i]); strbuf_catf(out, "%s%02x", i ? ":" : "", digest[i]);
if (key->comment) if (key->comment)
@ -376,34 +258,32 @@ char *rsa_ssh1_fingerprint(struct RSAKey *key)
*/ */
bool rsa_verify(struct RSAKey *key) bool rsa_verify(struct RSAKey *key)
{ {
Bignum n, ed, pm1, qm1; mp_int *n, *ed, *pm1, *qm1;
int cmp; unsigned ok = 1;
/* Preliminary checks: p,q must actually be nonzero. */
if (mp_eq_integer(key->p, 0) | mp_eq_integer(key->q, 0))
return false;
/* n must equal pq. */ /* n must equal pq. */
n = bigmul(key->p, key->q); n = mp_mul(key->p, key->q);
cmp = bignum_cmp(n, key->modulus); ok &= mp_cmp_eq(n, key->modulus);
freebn(n); mp_free(n);
if (cmp != 0)
return false;
/* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */ /* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */
pm1 = copybn(key->p); pm1 = mp_copy(key->p);
decbn(pm1); mp_sub_integer_into(pm1, pm1, 1);
ed = modmul(key->exponent, key->private_exponent, pm1); ed = mp_modmul(key->exponent, key->private_exponent, pm1);
freebn(pm1); mp_free(pm1);
cmp = bignum_cmp(ed, One); ok &= mp_eq_integer(ed, 1);
freebn(ed); mp_free(ed);
if (cmp != 0)
return false;
qm1 = copybn(key->q); qm1 = mp_copy(key->q);
decbn(qm1); mp_sub_integer_into(qm1, qm1, 1);
ed = modmul(key->exponent, key->private_exponent, qm1); ed = mp_modmul(key->exponent, key->private_exponent, qm1);
freebn(qm1); mp_free(qm1);
cmp = bignum_cmp(ed, One); ok &= mp_eq_integer(ed, 1);
freebn(ed); mp_free(ed);
if (cmp != 0)
return false;
/* /*
* Ensure p > q. * Ensure p > q.
@ -413,33 +293,18 @@ bool rsa_verify(struct RSAKey *key)
* should instead flip them round into the canonical order of * should instead flip them round into the canonical order of
* p > q. This also involves regenerating iqmp. * p > q. This also involves regenerating iqmp.
*/ */
if (bignum_cmp(key->p, key->q) <= 0) { unsigned swap_pq = mp_cmp_hs(key->q, key->p);
Bignum tmp = key->p; mp_cond_swap(key->p, key->q, swap_pq);
key->p = key->q; mp_free(key->iqmp);
key->q = tmp; key->iqmp = mp_invert(key->q, key->p);
freebn(key->iqmp); return ok;
key->iqmp = modinv(key->q, key->p);
if (!key->iqmp)
return false;
}
/*
* Ensure iqmp * q is congruent to 1, modulo p.
*/
n = modmul(key->iqmp, key->q, key->p);
cmp = bignum_cmp(n, One);
freebn(n);
if (cmp != 0)
return false;
return true;
} }
void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key, void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
RsaSsh1Order order) RsaSsh1Order order)
{ {
put_uint32(bs, bignum_bitcount(key->modulus)); put_uint32(bs, mp_get_nbits(key->modulus));
if (order == RSA_SSH1_EXPONENT_FIRST) { if (order == RSA_SSH1_EXPONENT_FIRST) {
put_mp_ssh1(bs, key->exponent); put_mp_ssh1(bs, key->exponent);
put_mp_ssh1(bs, key->modulus); put_mp_ssh1(bs, key->modulus);
@ -459,8 +324,8 @@ int rsa_ssh1_public_blob_len(void *data, int maxlen)
/* Expect a length word, then exponent and modulus. (It doesn't /* Expect a length word, then exponent and modulus. (It doesn't
* even matter which order.) */ * even matter which order.) */
get_uint32(src); get_uint32(src);
freebn(get_mp_ssh1(src)); mp_free(get_mp_ssh1(src));
freebn(get_mp_ssh1(src)); mp_free(get_mp_ssh1(src));
if (get_err(src)) if (get_err(src))
return -1; return -1;
@ -472,19 +337,19 @@ int rsa_ssh1_public_blob_len(void *data, int maxlen)
void freersapriv(struct RSAKey *key) void freersapriv(struct RSAKey *key)
{ {
if (key->private_exponent) { if (key->private_exponent) {
freebn(key->private_exponent); mp_free(key->private_exponent);
key->private_exponent = NULL; key->private_exponent = NULL;
} }
if (key->p) { if (key->p) {
freebn(key->p); mp_free(key->p);
key->p = NULL; key->p = NULL;
} }
if (key->q) { if (key->q) {
freebn(key->q); mp_free(key->q);
key->q = NULL; key->q = NULL;
} }
if (key->iqmp) { if (key->iqmp) {
freebn(key->iqmp); mp_free(key->iqmp);
key->iqmp = NULL; key->iqmp = NULL;
} }
} }
@ -493,11 +358,11 @@ void freersakey(struct RSAKey *key)
{ {
freersapriv(key); freersapriv(key);
if (key->modulus) { if (key->modulus) {
freebn(key->modulus); mp_free(key->modulus);
key->modulus = NULL; key->modulus = NULL;
} }
if (key->exponent) { if (key->exponent) {
freebn(key->exponent); mp_free(key->exponent);
key->exponent = NULL; key->exponent = NULL;
} }
if (key->comment) { if (key->comment) {
@ -642,7 +507,7 @@ static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
return -1; return -1;
rsa = container_of(sshk, struct RSAKey, sshk); rsa = container_of(sshk, struct RSAKey, sshk);
ret = bignum_bitcount(rsa->modulus); ret = mp_get_nbits(rsa->modulus);
rsa2_freekey(&rsa->sshk); rsa2_freekey(&rsa->sshk);
return ret; return ret;
@ -738,8 +603,7 @@ static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
BinarySource src[1]; BinarySource src[1];
ptrlen type, in_pl; ptrlen type, in_pl;
Bignum in, out; mp_int *in, *out;
bool toret;
BinarySource_BARE_INIT(src, sig.ptr, sig.len); BinarySource_BARE_INIT(src, sig.ptr, sig.len);
type = get_string(src); type = get_string(src);
@ -751,28 +615,27 @@ static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
* BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's * BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's
* there.) So we can't use get_mp_ssh2, which enforces that * there.) So we can't use get_mp_ssh2, which enforces that
* leading-byte scheme; instead we use get_string and * leading-byte scheme; instead we use get_string and
* bignum_from_bytes, which will tolerate anything. * mp_from_bytes_be, which will tolerate anything.
*/ */
in_pl = get_string(src); in_pl = get_string(src);
if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa")) if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa"))
return false; return false;
in = bignum_from_bytes(in_pl.ptr, in_pl.len); in = mp_from_bytes_be(in_pl);
out = modpow(in, rsa->exponent, rsa->modulus); out = mp_modpow(in, rsa->exponent, rsa->modulus);
freebn(in); mp_free(in);
toret = true; unsigned diff = 0;
size_t nbytes = (bignum_bitcount(rsa->modulus) + 7) / 8; size_t nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
unsigned char *bytes = rsa_pkcs1_signature_string(nbytes, &ssh_sha1, data); unsigned char *bytes = rsa_pkcs1_signature_string(nbytes, &ssh_sha1, data);
for (size_t i = 0; i < nbytes; i++) for (size_t i = 0; i < nbytes; i++)
if (bytes[nbytes-1 - i] != bignum_byte(out, i)) diff |= bytes[nbytes-1 - i] ^ mp_get_byte(out, i);
toret = false;
smemclr(bytes, nbytes); smemclr(bytes, nbytes);
sfree(bytes); sfree(bytes);
freebn(out); mp_free(out);
return toret; return diff == 0;
} }
static void rsa2_sign(ssh_key *key, const void *data, int datalen, static void rsa2_sign(ssh_key *key, const void *data, int datalen,
@ -780,8 +643,8 @@ static void rsa2_sign(ssh_key *key, const void *data, int datalen,
{ {
struct RSAKey *rsa = container_of(key, struct RSAKey, sshk); struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
unsigned char *bytes; unsigned char *bytes;
int nbytes; size_t nbytes;
Bignum in, out; mp_int *in, *out;
const struct ssh_hashalg *halg; const struct ssh_hashalg *halg;
const char *sign_alg_name; const char *sign_alg_name;
@ -796,24 +659,24 @@ static void rsa2_sign(ssh_key *key, const void *data, int datalen,
sign_alg_name = "ssh-rsa"; sign_alg_name = "ssh-rsa";
} }
nbytes = (bignum_bitcount(rsa->modulus) + 7) / 8; nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8;
bytes = rsa_pkcs1_signature_string( bytes = rsa_pkcs1_signature_string(
nbytes, halg, make_ptrlen(data, datalen)); nbytes, halg, make_ptrlen(data, datalen));
in = bignum_from_bytes(bytes, nbytes); in = mp_from_bytes_be(make_ptrlen(bytes, nbytes));
smemclr(bytes, nbytes); smemclr(bytes, nbytes);
sfree(bytes); sfree(bytes);
out = rsa_privkey_op(in, rsa); out = rsa_privkey_op(in, rsa);
freebn(in); mp_free(in);
put_stringz(bs, sign_alg_name); put_stringz(bs, sign_alg_name);
nbytes = (bignum_bitcount(out) + 7) / 8; nbytes = (mp_get_nbits(out) + 7) / 8;
put_uint32(bs, nbytes); put_uint32(bs, nbytes);
for (size_t i = 0; i < nbytes; i++) for (size_t i = 0; i < nbytes; i++)
put_byte(bs, bignum_byte(out, nbytes - 1 - i)); put_byte(bs, mp_get_byte(out, nbytes - 1 - i));
freebn(out); mp_free(out);
} }
const ssh_keyalg ssh_rsa = { const ssh_keyalg ssh_rsa = {
@ -852,7 +715,7 @@ void ssh_rsakex_freekey(struct RSAKey *key)
int ssh_rsakex_klen(struct RSAKey *rsa) int ssh_rsakex_klen(struct RSAKey *rsa)
{ {
return bignum_bitcount(rsa->modulus); return mp_get_nbits(rsa->modulus);
} }
static void oaep_mask(const struct ssh_hashalg *h, void *seed, int seedlen, static void oaep_mask(const struct ssh_hashalg *h, void *seed, int seedlen,
@ -885,7 +748,7 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
unsigned char *in, int inlen, unsigned char *in, int inlen,
unsigned char *out, int outlen, struct RSAKey *rsa) unsigned char *out, int outlen, struct RSAKey *rsa)
{ {
Bignum b1, b2; mp_int *b1, *b2;
int k, i; int k, i;
char *p; char *p;
const int HLEN = h->hlen; const int HLEN = h->hlen;
@ -918,7 +781,7 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
*/ */
/* k denotes the length in octets of the RSA modulus. */ /* k denotes the length in octets of the RSA modulus. */
k = (7 + bignum_bitcount(rsa->modulus)) / 8; k = (7 + mp_get_nbits(rsa->modulus)) / 8;
/* The length of the input data must be at most k - 2hLen - 2. */ /* The length of the input data must be at most k - 2hLen - 2. */
assert(inlen > 0 && inlen <= k - 2*HLEN - 2); assert(inlen > 0 && inlen <= k - 2*HLEN - 2);
@ -961,24 +824,24 @@ void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
* Now `out' contains precisely the data we want to * Now `out' contains precisely the data we want to
* RSA-encrypt. * RSA-encrypt.
*/ */
b1 = bignum_from_bytes(out, outlen); b1 = mp_from_bytes_be(make_ptrlen(out, outlen));
b2 = modpow(b1, rsa->exponent, rsa->modulus); b2 = mp_modpow(b1, rsa->exponent, rsa->modulus);
p = (char *)out; p = (char *)out;
for (i = outlen; i--;) { for (i = outlen; i--;) {
*p++ = bignum_byte(b2, i); *p++ = mp_get_byte(b2, i);
} }
freebn(b1); mp_free(b1);
freebn(b2); mp_free(b2);
/* /*
* And we're done. * And we're done.
*/ */
} }
Bignum ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext, mp_int *ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
struct RSAKey *rsa) struct RSAKey *rsa)
{ {
Bignum b1, b2; mp_int *b1, *b2;
int outlen, i; int outlen, i;
unsigned char *out; unsigned char *out;
unsigned char labelhash[64]; unsigned char labelhash[64];
@ -992,18 +855,18 @@ Bignum ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
/* The length of the encrypted data should be exactly the length /* The length of the encrypted data should be exactly the length
* in octets of the RSA modulus.. */ * in octets of the RSA modulus.. */
outlen = (7 + bignum_bitcount(rsa->modulus)) / 8; outlen = (7 + mp_get_nbits(rsa->modulus)) / 8;
if (ciphertext.len != outlen) if (ciphertext.len != outlen)
return NULL; return NULL;
/* Do the RSA decryption, and extract the result into a byte array. */ /* Do the RSA decryption, and extract the result into a byte array. */
b1 = bignum_from_bytes(ciphertext.ptr, ciphertext.len); b1 = mp_from_bytes_be(ciphertext);
b2 = rsa_privkey_op(b1, rsa); b2 = rsa_privkey_op(b1, rsa);
out = snewn(outlen, unsigned char); out = snewn(outlen, unsigned char);
for (i = 0; i < outlen; i++) for (i = 0; i < outlen; i++)
out[i] = bignum_byte(b2, outlen-1-i); out[i] = mp_get_byte(b2, outlen-1-i);
freebn(b1); mp_free(b1);
freebn(b2); mp_free(b2);
/* Do the OAEP masking operations, in the reverse order from encryption */ /* Do the OAEP masking operations, in the reverse order from encryption */
oaep_mask(h, out+HLEN+1, outlen-HLEN-1, out+1, HLEN); oaep_mask(h, out+HLEN+1, outlen-HLEN-1, out+1, HLEN);
@ -1038,7 +901,7 @@ Bignum ssh_rsakex_decrypt(const struct ssh_hashalg *h, ptrlen ciphertext,
b1 = get_mp_ssh2(src); b1 = get_mp_ssh2(src);
sfree(out); sfree(out);
if (get_err(src) || get_avail(src) != 0) { if (get_err(src) || get_avail(src) != 0) {
freebn(b1); mp_free(b1);
return NULL; return NULL;
} }

Просмотреть файл

@ -5,13 +5,13 @@
#include <assert.h> #include <assert.h>
#include "ssh.h" #include "ssh.h"
#include "mpint.h"
#define RSA_EXPONENT 37 /* we like this prime */ #define RSA_EXPONENT 37 /* we like this prime */
int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn, int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
void *pfnparam) void *pfnparam)
{ {
Bignum pm1, qm1, phi_n;
unsigned pfirst, qfirst; unsigned pfirst, qfirst;
key->sshk.vt = &ssh_rsa; key->sshk.vt = &ssh_rsa;
@ -55,7 +55,7 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
/* /*
* We don't generate e; we just use a standard one always. * We don't generate e; we just use a standard one always.
*/ */
key->exponent = bignum_from_long(RSA_EXPONENT); mp_int *exponent = mp_from_integer(RSA_EXPONENT);
/* /*
* Generate p and q: primes with combined length `bits', not * Generate p and q: primes with combined length `bits', not
@ -65,19 +65,15 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
* a prime e, we can simplify the criterion.) * a prime e, we can simplify the criterion.)
*/ */
invent_firstbits(&pfirst, &qfirst); invent_firstbits(&pfirst, &qfirst);
key->p = primegen(bits / 2, RSA_EXPONENT, 1, NULL, mp_int *p = primegen(bits / 2, RSA_EXPONENT, 1, NULL,
1, pfn, pfnparam, pfirst); 1, pfn, pfnparam, pfirst);
key->q = primegen(bits - bits / 2, RSA_EXPONENT, 1, NULL, mp_int *q = primegen(bits - bits / 2, RSA_EXPONENT, 1, NULL,
2, pfn, pfnparam, qfirst); 2, pfn, pfnparam, qfirst);
/* /*
* Ensure p > q, by swapping them if not. * Ensure p > q, by swapping them if not.
*/ */
if (bignum_cmp(key->p, key->q) < 0) { mp_cond_swap(p, q, mp_cmp_hs(q, p));
Bignum t = key->p;
key->p = key->q;
key->q = t;
}
/* /*
* Now we have p, q and e. All we need to do now is work out * Now we have p, q and e. All we need to do now is work out
@ -85,27 +81,31 @@ int rsa_generate(struct RSAKey *key, int bits, progfn_t pfn,
* and (q^-1 mod p). * and (q^-1 mod p).
*/ */
pfn(pfnparam, PROGFN_PROGRESS, 3, 1); pfn(pfnparam, PROGFN_PROGRESS, 3, 1);
key->modulus = bigmul(key->p, key->q); mp_int *modulus = mp_mul(p, q);
pfn(pfnparam, PROGFN_PROGRESS, 3, 2); pfn(pfnparam, PROGFN_PROGRESS, 3, 2);
pm1 = copybn(key->p); mp_int *pm1 = mp_copy(p);
decbn(pm1); mp_sub_integer_into(pm1, pm1, 1);
qm1 = copybn(key->q); mp_int *qm1 = mp_copy(q);
decbn(qm1); mp_sub_integer_into(qm1, qm1, 1);
phi_n = bigmul(pm1, qm1); mp_int *phi_n = mp_mul(pm1, qm1);
pfn(pfnparam, PROGFN_PROGRESS, 3, 3); pfn(pfnparam, PROGFN_PROGRESS, 3, 3);
freebn(pm1); mp_free(pm1);
freebn(qm1); mp_free(qm1);
key->private_exponent = modinv(key->exponent, phi_n); mp_int *private_exponent = mp_invert(exponent, phi_n);
assert(key->private_exponent);
pfn(pfnparam, PROGFN_PROGRESS, 3, 4); pfn(pfnparam, PROGFN_PROGRESS, 3, 4);
key->iqmp = modinv(key->q, key->p); mp_free(phi_n);
assert(key->iqmp); mp_int *iqmp = mp_invert(q, p);
pfn(pfnparam, PROGFN_PROGRESS, 3, 5); pfn(pfnparam, PROGFN_PROGRESS, 3, 5);
/* /*
* Clean up temporary numbers. * Populate the returned structure.
*/ */
freebn(phi_n); key->modulus = modulus;
key->exponent = exponent;
key->private_exponent = private_exponent;
key->p = p;
key->q = q;
key->iqmp = iqmp;
return 1; return 1;
} }

Просмотреть файл

@ -62,7 +62,7 @@ char *auth_ssh1int_challenge(AuthPolicy *, unsigned method, ptrlen username);
bool auth_ssh1int_response(AuthPolicy *, ptrlen response); bool auth_ssh1int_response(AuthPolicy *, ptrlen response);
struct RSAKey *auth_publickey_ssh1( struct RSAKey *auth_publickey_ssh1(
AuthPolicy *ap, ptrlen username, Bignum rsa_modulus); AuthPolicy *ap, ptrlen username, mp_int *rsa_modulus);
/* auth_successful returns false if further authentication is needed */ /* auth_successful returns false if further authentication is needed */
bool auth_successful(AuthPolicy *, ptrlen username, unsigned method); bool auth_successful(AuthPolicy *, ptrlen username, unsigned method);

275
testbn.c
Просмотреть файл

@ -1,275 +0,0 @@
/*
* testbn.c: standalone test program for the bignum code.
*/
/*
* Accepts input on standard input, in the form generated by
* testdata/bignum.py.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "ssh.h"
#include "sshbn.h"
void modalfatalbox(const char *p, ...)
{
va_list ap;
fprintf(stderr, "FATAL ERROR: ");
va_start(ap, p);
vfprintf(stderr, p, ap);
va_end(ap);
fputc('\n', stderr);
exit(1);
}
int random_byte(void)
{
modalfatalbox("random_byte called in testbn");
return 0;
}
void queue_idempotent_callback(IdempotentCallback *ic) { assert(0); }
#define fromxdigit(c) ( (c)>'9' ? ((c)&0xDF) - 'A' + 10 : (c) - '0' )
/* For Unix in particular, but harmless if this main() is reused elsewhere */
const bool buildinfo_gtk_relevant = false;
int main(int argc, char **argv)
{
char *buf;
int line = 0;
int passes = 0, fails = 0;
printf("BIGNUM_INT_BITS = %d\n", (int)BIGNUM_INT_BITS);
while ((buf = fgetline(stdin)) != NULL) {
int maxlen = strlen(buf);
unsigned char *data = snewn(maxlen, unsigned char);
unsigned char *ptrs[5], *q;
int ptrnum;
char *bufp = buf;
line++;
q = data;
ptrnum = 0;
while (*bufp && !isspace((unsigned char)*bufp))
bufp++;
if (*bufp)
*bufp++ = '\0';
while (*bufp) {
char *start, *end;
int i;
while (*bufp && !isxdigit((unsigned char)*bufp))
bufp++;
start = bufp;
if (!*bufp)
break;
while (*bufp && isxdigit((unsigned char)*bufp))
bufp++;
end = bufp;
if (ptrnum >= lenof(ptrs))
break;
ptrs[ptrnum++] = q;
for (i = -((end - start) & 1); i < end-start; i += 2) {
unsigned char val = (i < 0 ? 0 : fromxdigit(start[i]));
val = val * 16 + fromxdigit(start[i+1]);
*q++ = val;
}
}
if (ptrnum < lenof(ptrs))
ptrs[ptrnum] = q;
if (!strcmp(buf, "mul")) {
Bignum a, b, c, p;
if (ptrnum != 3) {
printf("%d: mul with %d parameters, expected 3\n", line, ptrnum);
exit(1);
}
a = bignum_from_bytes(ptrs[0], ptrs[1]-ptrs[0]);
b = bignum_from_bytes(ptrs[1], ptrs[2]-ptrs[1]);
c = bignum_from_bytes(ptrs[2], ptrs[3]-ptrs[2]);
p = bigmul(a, b);
if (bignum_cmp(c, p) == 0) {
passes++;
} else {
char *as = bignum_decimal(a);
char *bs = bignum_decimal(b);
char *cs = bignum_decimal(c);
char *ps = bignum_decimal(p);
printf("%d: fail: %s * %s gave %s expected %s\n",
line, as, bs, ps, cs);
fails++;
sfree(as);
sfree(bs);
sfree(cs);
sfree(ps);
}
freebn(a);
freebn(b);
freebn(c);
freebn(p);
} else if (!strcmp(buf, "modmul")) {
Bignum a, b, m, c, p;
if (ptrnum != 4) {
printf("%d: modmul with %d parameters, expected 4\n",
line, ptrnum);
exit(1);
}
a = bignum_from_bytes(ptrs[0], ptrs[1]-ptrs[0]);
b = bignum_from_bytes(ptrs[1], ptrs[2]-ptrs[1]);
m = bignum_from_bytes(ptrs[2], ptrs[3]-ptrs[2]);
c = bignum_from_bytes(ptrs[3], ptrs[4]-ptrs[3]);
p = modmul(a, b, m);
if (bignum_cmp(c, p) == 0) {
passes++;
} else {
char *as = bignum_decimal(a);
char *bs = bignum_decimal(b);
char *ms = bignum_decimal(m);
char *cs = bignum_decimal(c);
char *ps = bignum_decimal(p);
printf("%d: fail: %s * %s mod %s gave %s expected %s\n",
line, as, bs, ms, ps, cs);
fails++;
sfree(as);
sfree(bs);
sfree(ms);
sfree(cs);
sfree(ps);
}
freebn(a);
freebn(b);
freebn(m);
freebn(c);
freebn(p);
} else if (!strcmp(buf, "pow")) {
Bignum base, expt, modulus, expected, answer;
if (ptrnum != 4) {
printf("%d: pow with %d parameters, expected 4\n", line, ptrnum);
exit(1);
}
base = bignum_from_bytes(ptrs[0], ptrs[1]-ptrs[0]);
expt = bignum_from_bytes(ptrs[1], ptrs[2]-ptrs[1]);
modulus = bignum_from_bytes(ptrs[2], ptrs[3]-ptrs[2]);
expected = bignum_from_bytes(ptrs[3], ptrs[4]-ptrs[3]);
answer = modpow(base, expt, modulus);
if (bignum_cmp(expected, answer) == 0) {
passes++;
} else {
char *as = bignum_decimal(base);
char *bs = bignum_decimal(expt);
char *cs = bignum_decimal(modulus);
char *ds = bignum_decimal(answer);
char *ps = bignum_decimal(expected);
printf("%d: fail: %s ^ %s mod %s gave %s expected %s\n",
line, as, bs, cs, ds, ps);
fails++;
sfree(as);
sfree(bs);
sfree(cs);
sfree(ds);
sfree(ps);
}
freebn(base);
freebn(expt);
freebn(modulus);
freebn(expected);
freebn(answer);
} else if (!strcmp(buf, "divmod")) {
Bignum n, d, expect_q, expect_r, answer_q, answer_r;
bool fail;
if (ptrnum != 4) {
printf("%d: divmod with %d parameters, expected 4\n", line, ptrnum);
exit(1);
}
n = bignum_from_bytes(ptrs[0], ptrs[1]-ptrs[0]);
d = bignum_from_bytes(ptrs[1], ptrs[2]-ptrs[1]);
expect_q = bignum_from_bytes(ptrs[2], ptrs[3]-ptrs[2]);
expect_r = bignum_from_bytes(ptrs[3], ptrs[4]-ptrs[3]);
answer_q = bigdiv(n, d);
answer_r = bigmod(n, d);
fail = false;
if (bignum_cmp(expect_q, answer_q) != 0) {
char *as = bignum_decimal(n);
char *bs = bignum_decimal(d);
char *cs = bignum_decimal(answer_q);
char *ds = bignum_decimal(expect_q);
printf("%d: fail: %s / %s gave %s expected %s\n",
line, as, bs, cs, ds);
fail = true;
sfree(as);
sfree(bs);
sfree(cs);
sfree(ds);
}
if (bignum_cmp(expect_r, answer_r) != 0) {
char *as = bignum_decimal(n);
char *bs = bignum_decimal(d);
char *cs = bignum_decimal(answer_r);
char *ds = bignum_decimal(expect_r);
printf("%d: fail: %s mod %s gave %s expected %s\n",
line, as, bs, cs, ds);
fail = true;
sfree(as);
sfree(bs);
sfree(cs);
sfree(ds);
}
freebn(n);
freebn(d);
freebn(expect_q);
freebn(expect_r);
freebn(answer_q);
freebn(answer_r);
if (fail)
fails++;
else
passes++;
} else {
printf("%d: unrecognised test keyword: '%s'\n", line, buf);
exit(1);
}
sfree(buf);
sfree(data);
}
printf("passed %d failed %d total %d\n", passes, fails, passes+fails);
return fails != 0;
}

140
testdata/bignum.py поставляемый
Просмотреть файл

@ -1,140 +0,0 @@
# Generate test cases for a bignum implementation.
import sys
# integer square roots
def sqrt(n):
d = long(n)
a = 0L
# b must start off as a power of 4 at least as large as n
ndigits = len(hex(long(n)))
b = 1L << (ndigits*4)
while 1:
a = a >> 1
di = 2*a + b
if di <= d:
d = d - di
a = a + b
b = b >> 2
if b == 0: break
return a
# continued fraction convergents of a rational
def confrac(n, d):
coeffs = [(1,0),(0,1)]
while d != 0:
i = n / d
n, d = d, n % d
coeffs.append((coeffs[-2][0]-i*coeffs[-1][0],
coeffs[-2][1]-i*coeffs[-1][1]))
return coeffs
def findprod(target, dir = +1, ratio=(1,1)):
# Return two numbers whose product is as close as we can get to
# 'target', with any deviation having the sign of 'dir', and in
# the same approximate ratio as 'ratio'.
r = sqrt(target * ratio[0] * ratio[1])
a = r / ratio[1]
b = r / ratio[0]
if a*b * dir < target * dir:
a = a + 1
b = b + 1
assert a*b * dir >= target * dir
best = (a,b,a*b)
while 1:
improved = 0
a, b = best[:2]
coeffs = confrac(a, b)
for c in coeffs:
# a*c[0]+b*c[1] is as close as we can get it to zero. So
# if we replace a and b with a+c[1] and b+c[0], then that
# will be added to our product, along with c[0]*c[1].
da, db = c[1], c[0]
# Flip signs as appropriate.
if (a+da) * (b+db) * dir < target * dir:
da, db = -da, -db
# Multiply up. We want to get as close as we can to a
# solution of the quadratic equation in n
#
# (a + n da) (b + n db) = target
# => n^2 da db + n (b da + a db) + (a b - target) = 0
A,B,C = da*db, b*da+a*db, a*b-target
discrim = B^2-4*A*C
if discrim > 0 and A != 0:
root = sqrt(discrim)
vals = []
vals.append((-B + root) / (2*A))
vals.append((-B - root) / (2*A))
if root * root != discrim:
root = root + 1
vals.append((-B + root) / (2*A))
vals.append((-B - root) / (2*A))
for n in vals:
ap = a + da*n
bp = b + db*n
pp = ap*bp
if pp * dir >= target * dir and pp * dir < best[2]*dir:
best = (ap, bp, pp)
improved = 1
if not improved:
break
return best
def hexstr(n):
s = hex(n)
if s[:2] == "0x": s = s[2:]
if s[-1:] == "L": s = s[:-1]
return s
# Tests of multiplication which exercise the propagation of the last
# carry to the very top of the number.
for i in range(1,4200):
a, b, p = findprod((1<<i)+1, +1, (i, i*i+1))
print "mul", hexstr(a), hexstr(b), hexstr(p)
a, b, p = findprod((1<<i)+1, +1, (i, i+1))
print "mul", hexstr(a), hexstr(b), hexstr(p)
# Bare tests of division/modulo.
prefixes = [2**63, int(2**63.5), 2**64-1]
for nsize in range(20, 200):
for dsize in range(20, 200):
for dprefix in prefixes:
d = sqrt(3<<(2*dsize)) + (dprefix<<dsize)
for nprefix in prefixes:
nbase = sqrt(3<<(2*nsize)) + (nprefix<<nsize)
for modulus in sorted({-1, 0, +1, d/2, nbase % d}):
n = nbase - (nbase % d) + modulus
if n < 0:
n += d
assert n >= 0
print "divmod", hexstr(n), hexstr(d), hexstr(n/d), hexstr(n%d)
# Simple tests of modmul.
for ai in range(20, 200, 60):
a = sqrt(3<<(2*ai-1))
for bi in range(20, 200, 60):
b = sqrt(5<<(2*bi-1))
for m in range(20, 600, 32):
m = sqrt(2**(m+1))
print "modmul", hexstr(a), hexstr(b), hexstr(m), hexstr((a*b) % m)
# Simple tests of modpow.
for i in range(64, 4097, 63):
modulus = sqrt(1<<(2*i-1)) | 1
base = sqrt(3*modulus*modulus) % modulus
expt = sqrt(modulus*modulus*2/5)
print "pow", hexstr(base), hexstr(expt), hexstr(modulus), hexstr(pow(base, expt, modulus))
if i <= 1024:
# Test even moduli, which can't be done by Montgomery.
modulus = modulus - 1
print "pow", hexstr(base), hexstr(expt), hexstr(modulus), hexstr(pow(base, expt, modulus))
print "pow", hexstr(i), hexstr(expt), hexstr(modulus), hexstr(pow(i, expt, modulus))

205
testdata/bignumtests.txt поставляемый
Просмотреть файл

@ -1,205 +0,0 @@
mul 6fcb0ed13247be24ded416f0d08612eb67d81017568e424698c442e4d7454d64315ffb51ce7af0bc6450c372d95c35967fde3adf6cec11a5c1e60847eccc8b4329b600bf917dbe4cab07ab82fbc439b5300000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000adf6cec11a5c1e60847eccc8b4329b2e4d7454d64315ffb51ce7af0bc6450c372d95c35967fde3adf6cec11a5c1e60847eccc8b4329b600bf917dbe4cab07ab82fbc439b5300000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000adf6cec11a5c1e60847eccc8b4329b600bf917dbe4cab07ab82fbc439b5300000000000000000000000000600bf917dbe4cab07ab82fbc439b5300000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000005967fde3adf6cec11a5c1e60847eccc8b4329b600bf917dbe4cab07ab82fbc439b53000000000000000000000000000000000d0000000000000000000000030000000000000000000000000000000000000000000adf6cec11a5c1e60847eccc8b4329b2e4d7454d64315ffb51ce7af0bc6450c372d95c35967fde3adf6cec11a5c1e60847eccc8b4329b600bf917dbe4cab07ab82fbc439b530d000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000adf6cec11a5c1e60847eccc8b4329b600bf917dbe4cab07ab82fbc439b5300000000000000000000000000600bf917dbe4cab07ab82fbc439b53000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000d2b00000000000000000000000000000000000000000d2b000000000000000000000000 5472abe25fd603c76d0790f25654cfcdad1c78b8d78f0043b544a82bd2f00000000000000000000000000000000000d2b00000000000000000000000000000000000000000d2b000000000000000000000000 24e0b458bbaa8f7f910bb243b2d8072f7c19f6b6b5da853b24621fe88c2833151e92cc3e22d3127aa16eeda3bf38eb59768e3b212f87e19fc0a18bf71e12baa8322778957ba93757abb8f584595e6510d943b3bb1ca9de1f034a2a0c31ab11156d1da7181ba0163c761ce7bb7def818e7900f8dd1cdd5b5943111bcc50b9b7a5845a1da04c70edf907604814320c59c0cb2ca1171de6c5c3e74e1a9628397f2de04459f13ceda25b1e3e3e102cd59a09d74f61151af91514689bb5120cba14ce64981190c6641e440e5d757f352f2814605cf8a9d0e0d710a1da7181ba0163c761ce7bb7def818e7900f8dd1cdd5b5943111bcc50b9b7a5845a1da04c70edf907604814320c59c0cb2cb17fe9b421f43acbe48d7ddceecd1d544f07fcbbed77175dd4342c31fd7b27c18fe581d6d4205dd52575894ecd965741a727d5a3c0ca1900553a89d5beacce763a00a290ebc3588f5e2accd1bb7a9b9ed93326d9e18438a9eb3a493c5e8fbb1fc57d1b057019c415a1f71e1b8e9f23e387990c1108dbf518a6218d207ed544f07fcbbed77175dd4342c322761217bc596aa22891716241df1342c9d73f75885cf0720c7f897a146394f4551aa5845a1da04c70edf907604814320c59c1765ba1171de6c5c3e74e1a9628397f2de04459f13cee4d8a1e3e3e102cd59a09d74f61151af91514689bb5120cba14ce64981190c6641e4412a74839b40d064580e65b061f43259e13a4e3a31cf3a6cad202f84218ae48e7900f8dd1cdd5b5943111bcc50b9b7a62f891da04c70edf907604814320c59c0cb2cb17fe9b4cd233acbe48d7ddceecd1d544f07fcbbed77175dd4342c31fd7b27c18fe581d6d4205dd52575894ecd965741a727d5a3c0ca1900553a89d5beacce763a00a290ebc3588f5e2accd1bb7a9b9ed93326d9e18438a9eb3a493a86ad00cb201d045e09a2c8db901dff75c9866404b4ee3f723c308da22a716cecc595685e9a9fe7c607d914cf670366158da22a716cecc595685e9a9fe78087b9ec56609129e5000000000000000000000000000000015aca7200000000000000000000000000000000000000ad6539000000000000000000000000000000000000000000000000
pow 4240f7064c1a41a5ec4dc53f528552ea5ec963dd373c59ca03b2f2a161cdf531d1cd5c30cc48280deedb3656dcca416 393e4b8b7fdbb26aca528ce01295f4d736806e48ca53b076cb48e2039026b61dd4ae6356aa5d4be633db00df1263807 5a827999fcef32422cbec4d9baa55f4f8eb7b05d449dd426768bd642c199cc8aa57e41821d5c5161d458ff37ee41ed8 54b00f9069773b7bb477cf039383e812f645d2afa949378e86fb3a9576dbabe44e4ebc35cb7e3e3a566083dc4f258c8
mul 169d8e69f29bd8497ec8ca970f390d39fca5aed949a931e1cf9f0a9177bd4d7156612a1841593fbc28aed186f471dc905dfe46114e392df944034cf 16a3aecd3581bb879be79d9072635f52b33ada60b6faeb0b5821e1eebd60000000000000000000000000000000000000000000000000000000000000000000000000024e5a0729c792d783819919713a5161cfaeb69da6faeb0b5821e1eebd600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007ef527ae46e531d 2000000000000000000000000000000000000000069b4e4f331f6204e5bd7808dc9b8107a41d5c358230b15a39b9e342c17f3ea02e43ca6f5293550a6d7b38497443725b83d5dbb4b20862b4375bcbb494a7891dc7248727bda5a258b93b3c95bb633a3d26d7f6074ed0bf947b23a29ca9d546ae4e3bfe71a15d583c9b4e5f82f8f022218291fb6d5aa4eb6f30aefa9398a5a75e415d150682a0a000000000000000000000000000000000000000000000000000000000000000000000000000000b373462d6da27dab3fffe3684d57a1835d8e5d3384bdde0887e1827a8a512c47c8eb28686773a45b009aaffdf5cf2d57b1fe1e16122b6ef02c6c990457ba9a9571873
pow 8483e4834c 727c9716ffb764d5 88888888888888888888888888888888cec888888888888888888888888888888888888888883978888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 5ad35993ffd525c7f0e2fdd30c77eca0ea7a7f328a6a998bcb63271c1f52ad472e33958ef17584e1c7a2b8f9e4942ccb7594e0b38c331a69f89ae7b42fbcfba9509aa610a6b34c5e2ef
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888880068888888888888888888888888888888888888883978888888d8888888888888888888888888d8888888888d88888888888888889de6485 1c04e7e3a7129c5ef42180d2f8fbe0804b8f3a35b8f2d593b4ec0ce478fd78c4e22170c03d631e91c4e8d84d7606716b0576afa60dade3fa4fb77f0fd75fb4f0e2863a749ef875a7f
pow 8483ee0c98e4834c 727c9716ffb764d5 88888888888888888888888888888888e91888888888888839778888888d88888888888888888888888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 17ff9b5d91ce08685fdd51715f0aff77216ac4911e4fb1c22bdb17609f754340d1e901c7e38f14c5569b13136b7991fcdb23d82adcb67a485b628eb01b5d1274a5eef39fd5a42dddd3d
pow 8483ee0c9834834c 727c9716ffb764d5 88888888888888888888888888888888d86dd488888888888888888888888888888888888888888888888888d8888888d8888888b504f333f9de6485 cd6d82f283b830e0e4f42243e661fc09cf379d7ade2ee39eedd941fd93db77f9ccebec1ca7ed7b321b2378dbf1238ffa5f2be38bf9d7688eb1652f7
pow 840000888888888888888888888888888888880000000000 727c9716ffb764d5 88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 6ede8a488a46e535a5c25c17236cc66c4e49e5de6bd31399366b19a9346ec95b5b36126726d63241a3031e41c0c1345fa5a17a3c48f141e951f4152c9ecdc8
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888888888888888888888888888888888888d8888888888d8888888b504f333f9d88888888888e6485 19090849092b2f94c22605d47301625de4b2a34f57c35796f6619d33b73b15ed917f776577f9f219adb6b4c7b5dce0ed6e4963d38150ad104b8bf1a03a8da74590
pow 8483e4834c 727c9716ffb764d5 88888888888888888888888888888888888888888888888888888888888888888888888888883978888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 60ca03e099dbf17c93db528e84638037419e28fff7639cc1d9af02d62407908207a3d622c4358491b93878580d8eca7b2a1fe89bcafa1ae32cba9248162ccb65cd86c717c6ad76369ac
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888888888888888888888888883978888888d8888888888888888888888888d8888888888d88888888888888889de6485 16e28809be035b05923c747a4ee9d75306a8529aa954028057efe5d72a09666d51afcac7ce03ddd6fbebad1e1ec67f64b7826d00123ca472abde81b56e8a4c9e532f759e60e9f1054
pow 8483ee0c9834834c 727c9716ffb764d5 88888888888888888888888888888888888888888888886839788888888888888888888d8888888888d888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 11a1c98f64b4d3a2a926fd1237e7f39c98eb6ef7a67ed9ccfd6d6ade87e0198469ea21c3fa8fe67e87dce8e4d59da5a7f2623a074377352f7a4246612254b1672e68a8f7fb5e6574cc84ac
pow 8483ee0c98e4834c 727c9716ffb764d5 88888888888888888888888888888888888888888888888839778888888d88888888888888888888888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 215d10c7bc86820b2c783e4b5ff4d2d6e57f3715d24cb9a7b2902b7513c261ef0c089929b26a52fcf6897c75519e83782761ef8f0ff816cf61e45de89da6a148cbab7aa93ea5d65e67b
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888888888888888888888883978888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 2ce9a51423d4223564b726e77575aab190e26cb0d1ce2bdc29c6f0e87599808df40a2e7062d9e9e410e54b02e7ef92bed6561b72b7b0b0fc662c7d04a242aeb7229dae5f1a8af1
pow 84 727c9716ffb764d5 8888888888888888888888888888888888888888d888888d8888888888888888888888d888888d88888888888888888888b504f333f9de6485 5c42fe284175b01a14b34e5c89b69097ec1d5dc9373285b82a946ea41899593ae43b7a482cb3cdcc5e21f97cfcc5ebdbffb5cafb60d252a2a9
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888880888888888888888888d888888d8888888b504f38888888888888888888888888888888833f9de6485 75ced9c9d94e6ffc16cfa101b9aa8dd547b25e986cc26a297ed2a4ad88e6f6e4a0e31484600194248d8e5154466191ddd67daaf3514cbfce78e0d47be37d1bf81b
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888d888888d888888888888888888888888888d888888d8888888b504f333f9de6485 537529b1dbacd7ae8e63e0356947a8ed5a7e9e770290a38e135b46183731d6276f80c68817076fae903b6c7cbba7bdcef90a70004b5a94ca1e
pow 8483c 727c9716ffb764d5 888888888888888888888888888888888888888888d888888d8888888b504f333f9de64888d8888888b504f333f9de6485 53244b21a7a17ff24160c5b96a0a98515a52296f44e0bbfbc48980a08a1f89182ae3977ba35b0e1d7d57075dc63002e640
pow 8483ee0c9834834c 727c9716ffb764d5 888f9de6488888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 14bf546b6c806f8b9b84671e7a46096966f1fe1e8de4c450fe89b57fd5408c36c8060eb169a57e76aa7ae76f330ef137bd9566834
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888888888888888888888888888888888888888d8888888b504f333f9de6485 511219ae4968000dae7b6d4ae111f7e8fc19dc33020ecaba3a7f45b1c1ddfcc4cbd2539307ec619481afb4d449ed8ed7a76f668558533
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888d8888888b504f333f9de888888888888888888888888888d888888d8888888b504f333f9de64de88888888888888888885 8135bbedf63d766808ea9e043323609d85eed687eebb6803271304ec68dc87de8ce362c3f16c9ac31e6dcb9542c9e7e2518e1fee06950d139aaebf9c2a7f827c26a9889491605470
pow 8483ee0c9834834c 727c9716ffb764d5 88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 44ed50d437512d99e38b02141a5d98fe47217f6cf5ebd237c8e79772eeac3ac2f33c13bbd80e9dbf3925147dfd135486611066110c4e1bbfe9655639b419941600032a2f9af21
pow 34c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 2928a55555c4efca16738b016cb559173f877bed11969bc281440c13b7caa65ce9af4067e7f1c21d0b21f1
pow 8483ee0c9834834c 727c9716ffb764d5 88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f6485 4c3ef21c414369560eab90c986b78a156045825bcdeb9d9bcea091916549f8f58ba49d0241cda890a4e2a9177f12bc71c4deec9a31b0f927582c0b5091
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888886888888888888888888888888d888888d8888888b504f333f9de6488b504f333f9de648585 6f03a4f2c77bec9c99564930f7972eae6f7f63c44a96e3e4747870d16aca5552300da1b7c705fa23b31e612f16275686e43b73a899a65d0e13a6
pow 8483ec 727c97c6ffb764d5 8888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 64b634614732913628140a72e9f4e2b59f8d75427ccc5c990e989aa358d7e8ee067a0f13f2fba3f7e747b1ee3c5f105515
pow 8483be0c9834834c 727c9716ffb764d5 88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 2a7e622ef5d374e587a48251eac21656ad40922326ee152ff20d9c8746a879e27a4fd414938da900c0d62480ae857e17b4a8fd9b404f7d6f1f13059313b073eff
pow 8483ee0c9834834c 727c9716ffb764a5 8888888888888888888888888888888888888888888888888888888888888888888888888888888888d888f333f9de6485 c97e716de0974491160fb8b2a2cc16ad5abbc07266e1e6cf25ca3a595981fd49cf1c526e7c04f5ed77df591ec327549e3
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888888d888888d8888d8888888b504f333f9de888888b504f333f9de6485 48b31ef21735201bbe4d2e6bae6cd76b1c90ddbaeb639369150b010f1b170edc966893c76d6d7edf21078529530f5232731ed399b19cd4dedcf9f8c69
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888888d888888d88888888888888888888888888888888888888b504f333f9de64888888888885 2ce54ff4a8a9dce961c4cfaf5a5a05b94b27cf215cd60d6b6c97da184582b90986bcfe25c0245a1a04967cc4dbebb78645fc060c58128a8252676d435c0927b987829d07e21
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888d8888888d8888888b504f333f9de6485 109e5bfc2d7df8823079a2dfe19129d443268f91fecb08d0b34aaa704fce9d085656a5e90bcda51c496e0b652a8aa8d4230286f8f3e0ccf9ade06fd2
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888e1ed888888d8888888b504f333f9de6485 7a4973c5e0e6bb423afc9f42658e6a9325485e0a9291c3805d5a3d766795746fc6f7270c79442d8c90888427d5793e9808
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888d08d888888d8888888b504f333f9de6485 6a862f8f33f51553d95fe131ece8cff25b79c052de028cf66b485fd46b5f4cf913962978b56850a8e5ec9bb07fd6f5f2c
pow 8400000000000000 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 5851978fe5efd8a522ac7c2d0e17f7aeaebc9f8c4a77a6c7bd3d734c47f247a2b9b291961aea0b69b53bbc9906889e3912
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888889888d888888d8888888b504f333f9de6485 1e7770c5546c601df48ccb9c929dfc9f36eaab78911c089e0b3459f0d80c80bfce2eded75c3d205a6d998aa628f3e9396b
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888880888888888888888888d888888d8888888b504f333f9de6485 2909fa1be537ec2cfd106f3f11664492283789e3f376e6179c170a4e080adc6a8a6850b77d35811c86b8dba0e6a98768c4
modmul 13988e 194bd642cccccccccccccccccccccccccccccccccccccccccccccccccc22cbec4d97999fcef32b7b05d449dd426768bd6462cbec4d9ba58 5a827999fcef32422cbec4d97999fcef32422cbec4d9baa55baa55f4f8eb7b05d449dd426768bd642cccccccccccccccccccccccccccccccc1999fcef32422cbec4d97999fcef324229cc8aa57 1efb3f63db5da66666666666666666666666666666666666666666666596306eb2d65742a759166d49874c30845d5019afffd7a6b2db4bf19cd0
modmul 139dddddddddddddddddddddddddddddd88e 194bd642ccccccccccccccccccccccc22cbec4d97999fcef32462cbec4d9ba58 5a8fcef32422cbec4d9baa55baa55f4f8eb7b05d449dd426768bd642cccccccccccccccccccccccccccccccc1999fcef32422cbec4d97999fcef324229cc8aa57 1f03a55c086d3a06d3a06d3a06d3a0602aba523c81830925e79c8b3b98eb9562b9d3f70790b415a26ba251983b4bbf79cd0
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888883978888888d8888888888888888888888888d8888888888d8888888b504f333f9de6485 4a0d96e0c39349b7377b15b5bf7b49f447a37349045d96c7e9f5122852162c9762d8381161f8db975e9e820b66a7042c850734679de7a7f548c1ed6
pow 8483ee0c9834834c 727c9716ffb764d5 88888c888888888888888888888888888888888d888888d888888192ea3333f9de6485 6434b339504f053e2a5ff58f64998f96f47aa632d6343459a9d2c1f77a0f2c2e942f77
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888324888d888888d8888888b504faaaaaaaaaaaaaaaaaaaaa333f9de6485 27a8e8c85285125d5617ebab1f839ecd5e20a606b4bd2e997a338399feb25fd6144045ffc50aa71167c7203b8e1
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 2c6b37a2df4595500b7460400ce897817970cfadaaf1c386eeba15e08aaa6ce24019713a30e1a2c459eb2e1dacb768b
pow 8483ee0c9834834c 727c9716ffb764d5 88888888888888888888888d88888888888888888888888888888888888888888888888d88888888888888888888d888888d8888888b504f333f9de6485 526b82e86fed0f1046b22b974a17b14d5a76f8c5c91f886e9aabf47d38c30d2dcd55f16391b4b719308169b0a6ca6e96ccf689fa6d9866dd88f36118472
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888888888888888f88888d888888d8888888b504f333f9de6485 156e2c168bf9cdbc4d37f0863b0748cf244afc19db0ff3e8d2801efc574dc9ffe094500fc828cc6349b9f9c64b1c6ba4d7ec
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888d888888d5 7d604b4171f1ef090338e494f47645ee6ce9b7d410cc52894bd4f25ab281
pow c 727c9716ffb764d5 888888888888888888888888888888888888888d888888d8888888b504888d8888888b504f333f9de648f333f9de6485 74231cb11902ffe7ee56597e45e007732106d1565aee8d97cbba145ecbb034e7dfecacdf37b942b1d1c6db411b8f1ad5
pow 8483884d9834834c 727c9716ffb764d5 888888888888888888888888888888888888888d888888d8888888b504f333f98b8d888888888888888888888888d888888d85 5adc4c88b8c112c2089468b51a545d218a07874bd9402923db6d8ba76f5f0e6e681396838574843fb46638b54e8a2f9ac71651
pow 8483ee0a9834834c 727c9716ffb764d5 888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 848898833195df7201ea83c1fd5b865de18b1f7f3535407f8721c743c68c0d1e119342dc99250d516a142e8b436
pow 8483ee0c9834834c 227c9716ffb764d5 888888888888888888888888888888888888888888888888888888b504f333f9de6485 12131509fa930f74d86f4da97b87c7c752320130b8dcc83c2bff6218a9b722def1636b
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888d888f333f9de6485 2be812603b8a9707dadde37bb5a61dd0444eb6f30eb721057009cc7adbcc8d6667011c0504e68
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 3ad25628fe61d80cd41e987f9325b8b74725dad97c564df113d78169d6bfcf643656caa89b7156faab66c982f61b9957ad
pow 8483ee0c9838dd4c 727c9716ffb764d5 888888888888888888888888888888888888888d888888888d888888d8888888b88d8888888b504f333f9de6485 30e87a722c8f3086881e32a662cc14a75b1a9122aebe5b4f615d4e03df5b59db82a2e1425cc2434afab8b0550b2
pow 8483ee0c9834834c 727c9716ffb764d5 888804888888888888888888888888888888888d888888d8888888b504f333f9de6485 32c13f9ea9459a14779564d65f101dd1f8640196a875f6dbff2cd4b7b5f7542520b044
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888d888888d8888888d504f333f9de6485 28d0c477fd109217949a66291f4e9816908ccad97823991e4179f5a503bd53ebeb364c
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888d888888d8888888b104f333f9de6485 6985a06f4a1c1eebf0304de7f55d13a09ccb9419448e56f213f5bb4e8c369f8e9bdd4f
modmul 13988e 194bd642ccccccccccccccccccccccc22cbec4d97999fcef32462cbec4d9ba58 5a827999fcef32422cbec4d97999fcef32422cbec4d9baa55baa55f4f8eb7b05d449dd426768bd642cccccccccccccccccccccccccccccccc1999fcef32422cbec4d97999fcef324229cc8aa57 1efb3f63db5da66666666666666666596306eb2d65742a7590dbcdfa6b2db4bf19cd0
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888888888888888d88888888888d88888888888d8888888b504f333f9de6485 5152a5e418fd58e41ca43b901cd36f7c99566568f9ff9b1e20389574908fea406f4e5ca8dd32918a07
pow 8483ee0c9834834c 727c9716ffb764d5 888888888888888888888888888888888888888d888888d8888888b504f333f9de6485 8296d34d3b715f19a9aa3a412b6f685f476201c389f11761eab46a627b44ab5ff640b0
pow 8483ee0c9834834c 6275 8888888888888888888888888888888888d8888888b5485 6a603ec3b6c06541519dda19c60de2767dbf3e8e68ca54d
pow 8483ee0c9834834c 727c9716ffb764d5 88888888888888888888888888888888d8888888b50485 3e299644f713778d7d21067fea7ee62cd137f93ee3dfe
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888d7888888b504f333f9de6485 732b121547e7602f411f5b39f04de7cc39b3561431abcd
modmul 13988e 194c22cbec4d97999fcef32422cbec4d9ba58 5a827999fcef32422cbec4d97999fcef32422cbec4d9baa55baa55f4f8eb7b05d449dd426768bd642cccccccccccccccccccccccccccccccc1999fcef32422cbec4d97999fcef324229cc8aa57 1efb9d206eb2d65742a7590d6e7d6eb2db4bf19cd0
modmul 13988e 194c58 5a827999fcef32422cbec4d97999fcef32422cbec4d9baa55baa55f4f8eb7b05dccccccc449dd426768bd642ccccccccccccccccccccccccccccc1cc199cc8aa57 1efbde498d0
modmul 13988e 194c58 5a827999fcef3cccccccccccccccccc199cc8aa2422cbec4d97999fcef32422cbec4d9baa55baa55f4f8eb7b05d449dd426768bd642cccccccccccccccccccccccccccccccc199cc8aa57 1efbde498d0
pow 1ba 1c9f25c5bfedd935654670094afa6b9b4037246529d83b65a4294670094afa6b9b4037246529d83b65a47101c8135b0eea5731ab552ea5f319ed806f8931c03fe68da4b41da004c 2d413cccfe779921165f626cdd52afa7c75bd82ea24eea128b0ea2c7f9bf720f6ce43dd2a1790e71ec b816f83baec979e163d1daccc1ed4a4779ec06ae40af4dd7f3f45bc8ced54c8626ee4adef4fbdcff0
pow 1ba f25c5bfedd93565294670094afa6b9b4037246529d83b65a47101c8135b0eea5731ab552ea5f319ed806f8931c03fe68da4b41da004c 2d413cccfe779921165f626cdd52afa7c75bd82ea24eea1338b8db2160c10eae28b0ea2c7f9bf720f6ce43cce64552bf20c10eae28b0ea2c7f9bf720f6ce43dd2a1790e71ec 23254b53a1cd644a5a998acd7e2c38f65b81909837ccc446a615a73a583ca5c92ce358370acbe6dce93031e26ce1fada16a133bf29c3143b45ecd8bb47f8383b88e8b109bdc
pow 1ba 1c9f25c5bfedd93565294670094afa6b9b4037246529d83b65a47101c8135b0eea5731ab552ea5f319d413cccfe779921165f626cdd52afae43dd2a1724eea133b45eb2160cce64552bf20c10eae28b0ea2c7f9bf720f6ce43dd2a1790e71ec 7625b7f3f6eb39f032c9212b5b62deda285df73ec12c5f00acecd70c678d010ea35311ce8f9efbc7 b5943aa9528f0519e72ccd24686656291dab86ff5916a589b9abafc14486c820b10557eba884e79
pow 1ba 1c9f25c5bfedd93565294670094afa6b9b4037246529d83b65a47101c8135b0eea5731ab152ea5f319ed806f8931c03fe68da4b41da004c 2d413cccfe779921165f626cdd52afa7c75bd82ea24eea133b45eb2160cce64552bf20c10eae28b0ea2c7f9bf720f6ce43dd2a1790e713fe68da4bec 10dd194113310a6cc9121c1e94db2410406ab41712c45b11ac10783e1f6ddae8ec2a2a4868db3ac8a74a13b525ccbb9469c9431e98b0fdb39e575fc
pow 10907dc1930690697b1371 fd4a14eabe7c7b369ec448e52aa97eb1fda3d54ba97b258f74dcf167280ecbca820000000004f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e509ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667322 11d53e8bf0e94f38a15acad76c89426e4282a01e21a5c8cb40363b3660fb6f51
pow 10907dc1930690697b13714fd957d3e3adec175a2f590b054ba97b258f74dcf167280ecbca858737d5c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099d366ea957d3e3adec175a2f590b0667323 12b697e76f7294ee42a4630ae19ebda51c4d1a40669a86ceeb78adbdf58cb9faf3320fd3cd2cfb1a886
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb136e06cf924c93ae6ea957d3e3adec17512775099da2f590b0667323 518f9910b7b9847e43ba7344c4868177aed30d7b277e0c0ad64a3dc1f992e865af889a0dccbe
pow 10907dc1930690497b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33800907dc14a57d35cda01b923294ec1db2d23880e40908b2fb1366ea957d3e3adec17512775099da2f590b0667323 1 0
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b9409ad87 16a031d9e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 14cc00562f66093169240d19685705e073c96c7547e5797c768440c5044c0e43566
pow 10907dc193b2d23880e409ad87 16a09e660690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ecc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 a03af414acae1a25bd359e46a395895fc8f3b5c96a3c25c3c1f290062cdb4972275c3eba22a21316f3339459ae54a6b5
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc966e08b2fb1366ea957d3e3adec17512775099da2f590b0667323 16869520abf32acaeac583b5781802b8b5dbce8aeed2c0b3a0db0e0359f3328a278
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b97d35cda01b923294ec1db2d23880e409667f3bcc908b2fb1366ea957d3e3adec17512775099da3f590b0667323 13e06cf924c93da01b923294ec1db2d23880eae2d00206c4813c36a0aac31d2db5e2148af132b6a099da2f590b0667323 da20997b7a493f76368d529949067b3639469e0c2d681588f7f76fbd12e1aa92b1eafa89a07b7159b8d5a4b17fcb3123
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923297 16a09e657d35cda01b923294ec1db2d2388067f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 115eec036127564768648670be45c3b1b7696d51d2ec76a657a5e090dd674e8a31cc0829ff63b3aa0150c5b591933
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858 37d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923267f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 450ce71a8eec9fcecab453e1566cf6525c70f6a69aa16a47c7d1ed754b0967c4764f6da6cf092fd49589912bc2bd3337f4
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec175127750af132b6a7c9c8a399da2f590b0667323 10bea717321c68ab600971b66e7e59047ad3682b4dbc1b64258affbe7b125af26b62c994ec365a3
pow 10907dc19306906e4f92e14fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec175127bbbbbbbbbbbbbbbbbbbbbbbbb537bbb75099da2f590b0667323 aafd00a40f14e94e5427612c7c8a2342576108dde4e32964fd4d100e60426e210f63ac4d884850cc8035e904d44e38
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c 4a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 1462290f3612e19fc67b888f7419d278efed8ef32fd37ec435410cd4601a3e4c
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc94a154ba97b258f74dcf167280e08b2fb1366ea957d3e3adec17512775099da2f590b0667323 14c84cc12c5d71de79fd96dcedf077c050baca2420aa20e33f38dcd5fbc46853150257db771c31dbda3bb53905
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c 39792e2dff6ec9ab294a33804a57d35cda01b923294ed23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 12d750a696d901ffb58cc9c2004431a44d2abd08923cf585e49dd2d95c70a001
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bc366ea957d3e3adec17512775099da2f54ba97b258f74dcf167280ecbc90b0667323 145fe455eb9d42bc17ab30f1ba224fd7e58fef09ddf0f8e62baef7b8b01bdd636b5f648097c1e913
pow 10907dc1930690697b13714fd4a154ba97b258f74d8737d4c75099da2f590b0667323 13e06cf924ccdf01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366908b2fb1366ea957d3ea957d3e3adec17512775099da2f590b0667323 b3566d563d6ba5fcc24ed18bc5f9a63e9d9b7e073d9b684156b4acc463ac9c89fe5507471d7347819
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667ff6ec9ab294a33804a57df3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 9cfdd8d180de912e9490385a14cd642f05e258745625c0cd9d403ebdaa7db90109ca1d771476a5b842a5
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b923b2fb1366ea957d3e3adec17512775099da2f590b0667323 17c1f8e9e0fc930930fb5a1cbfd90f44d95eb3cf8c7918c98ec47f3ebd4cd9bd234
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f9c36a0aac31d2db5e2248af132e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 2ba528582bdd37fe979ba13589832fd094dbd1ba79aa31b1a3fc15ea00d8908
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad930690697b13714fd4a154ba9787 16a09e667f3bcc366ea957d3e3adec17512775099da2f590b0667323 100b983f254cd0503a68b707952fd4e3930e57e48ef7521dc749302c
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e64d23bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 32edca42bb85d3a7964256b95d4c12db0a3735c8501b7d24e35c17e6471aff1
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a092047f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 100fa51ec3e14bbb7918eb18a4619b71a9c0445e1a9677387f982911df821403
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 18449e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 16e9c0ed5254e4d5fa00a8e6630cc4174d69982c67d26303805ef489c332f713
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e6c7f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 13928b672d49ab1c419847ae5c2bc6957a2792445b58bb5de8aaf35b11ec51b2
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 d6a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 d3634464bd781a4f3c3de1bb2d575988d5d861944bbcfb2d5b5fb9cb5f641b62
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099db2f590b0667323 139a26f4ce368bcc132437fa3fdff9393e529e9ad810507065eae0fe1eae75ab
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adeb17512775099da2f590b0667323 13cb39d2966a6cda4a61a7bcac4d54fc1e07f9a5911a6c9e418f424e1d690d88
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d2e3adec17512775099da2f590b0667323 1045060ef67d3e02805fc6c7c73e78d9515773cebfb94a2361bb562de44f0cef
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea955d3e3adec17512775099da2f590b0667323 e9f79f25a51263752bb6801ea2ea69f1bfe72eb29841a18fe897344e432778b
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea857d3e3adec17512775099da2f590b0667323 1603254e45e8cea74b33e0fea929a14f8031fec82f60e443d5da2177dc5d9aa3
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366da957d3e3adec17512775099da2f590b0667323 82799d2dc787e49afd44173d4373cc1e5e4c5f338639b0876da8b60f139032f
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1166ea957d3e3adec17512775099da2f590b0667323 550bb6f10292ca7bda8ee8ec2d849ca328123ff90f2bd85795c509a12d99e0a
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 12a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 106e2d72f0365650111866243cfc5a675f4d0677452da7d86354717813c4b705
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 56a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 34af9ebb1c936ee57965f89c005ea5dc91d70aefef9a3181363e39b7547856e4
pow 10907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 96a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 735eb1132cd9f59c79500163d423f3ecb1f802aa65ec6327612302f7d96ae917
pow 11907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 328fb6559104e886880c03bdc59572cc2dddb075bc405b8e37e681fdf6f14b6
pow 12907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 11d815b4b3c473a014845a6c46d4f3e0fbe1079a046d52a999a0efa4457d904e
pow 50907dc1930690697b13714fd4a154ba97b258f74dcf167280ecbca858737d4c e4f92e2dff6ec9ab294a33804a57d35cda01b923294ec1db2d23880e409ad87 16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667323 12cf3bbf47b42cd6d73e7c59aa66efe37c82efd92eadb5d3166c2514fb521ec4
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fd5b26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f41a5ec4dc53f528552e9 337f28ff252aa48023556ab30189e1eba23c1f2d451136b029
pow 4241f7064c1a41a552e9 393e4b3b55fa3d1aaf5b8bb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f4e 46aa926b3d484810eccca4e964ad5f8f
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdb2cbec4d9baa55f4e 3e73738d7999fcef32422cbec4d9baa55f4e 70ca5cba1b58bdc4c907d349716609a3749
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f44dc53f528552e9 3b76731b825ed64be2fdd42579bf2c10a666b49b347ed
pow 4241f7064c1a41c51c4dc53f528552e9 393e4b8b7f73738ddbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f4e 3dc6a608deca791097e423ce76dc7c3f
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55179 4b5b2ee754f65abca70d2ee02783bb84
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55ee5 13a5660d889b6c2b7679e4804cfb33b0
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55171 b2bee6670600e5cdca742a65fd1ff8d
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa5c5e5 209018f064798d5de50dca68e1a67bbd
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa311c9 19480fc0e92332649012fe282ac6507b
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef3bb06cbec4d9baa55f4e 4b140ce53242560dbd6e997fd2c75683
pow 2241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f4e 3c503d9f72a8809af1eef9883798b963
pow 4241f7064c1a41a5ec4dc53f528552e9 393e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f4d b507582651e7cd31dac1fe4f6e22f4b
pow 4241f7064c1a41a5ec4dc53f528552e9 793e4b8b7fdbb26aca528ce01295f4d6 5a827999fcef32422cbec4d9baa55f4e 59acb6241548663232e48f1bce0780e7
pow 40 727c9716484 870e7550437c3f9de6484 812319144f0d00b0c71c0
pow 8483 b504f333f9de6485 3192ea3e99c8b504f333f9de6485 2b83edad87fec41bdd2a2c67757
pow 8403ee0c9834834c 727c9716ffb764d5 b504f333f9de64504f333f9de6485 72de72a69fb7be9db98df5ff0666e
pow 8483179c984c 727c9716ffb764d5 b504f333f333f9de6485 45f63d048e8bf05fe15
pow 848334764d5 b504f333f9de6485 3192ea3e99c84934c 846cdce061d08961
pow 8483ee0c98348346dd00267168dd764d5 b504f333f9de6485 31b504f333f9de6485 1d3c563ca7a8355ee2
pow 8483ee0c9834834c 727c9716ffb764d5 8888888888888888888888d8888888b504f333f9de6485 262b90699d5729bbd17f13a5d5f72b8a37d53c5bc6b862
pow 8483ee0c94c 72 b504f333f9de6485e6485 873c770cd74ff4fff6c16
pow 8483e834c 727c9716ffb7644e0c9834834c 727c9716ffb7644246504f333f9de6485 98af64208d351df230c13e918ae5a012
pow 8483ee0c9834834c 727c9716ffbf333f9de648834c 727c9716ffbf333f9de645 1d7d26536d52e6422b5b81
pow 8483ee0c9834834c 727c9716ffb764d5 b504f333f9dde6485 ac208abc45050b286
pow 8483ee0c9834834c 727c9716ffb764d5 b504f333f504f333f9d9de6485 5da8095154c4248389a323559c
pow 8483ee0c9834834c 3f9de6485 82bd2a3e99c872e99c849de504f337c92ea3e99c849de504f333f9de6485 5cc8c6fc66f6da8d4fc03cf14157915bf0a46062ee2b87007a1ba5efd0ef
pow 8483ee0c9834834c 727c9716ffb764d5 b504f33333f9de6485 9b7fbbd74f27281103
pow 8483ee0c98345 b504f333f9 e6485 809bf
pow 8483ee0c9834834c 727c9716ffb764d5 b5026823f9de6485 380c222e7b1c958
pow 8483ee0c9834834c 727c9716ffb764d5 4d24f333f9de6485 2e7a29f446106c06
pow 8483ee0c9834834c 727c9716ffb764d5 1714f333f9de6485 38687f6a43fd553
pow 8483ee0c9834834c 727c9716ffb764d5 e914f333f9de6485 5f8173a3832a148b
pow 8483ee0c9834834c 727c9716ffb764d5 1754f333f9de6485 eee8599db0a878e
pow 8483ee0c9834834c 727c9716ffb764d5 2044f333f9de6485 1e559d32dc6c4d92
pow 8604ee0c9834834c 727c9716ffb764d5 b504f333f9de6485 5341d938b4b2112e
pow 37c3ee0c9834834c 727c9716ffb764d5 b504f333f9de6485 2783dee829d253f2
pow 8483ee0c9834834c 727c9716ffb764d5 b504fa33f9de6485 1b81c5c38e77c229
pow 8483ee0c9834834c 727c9716ffb764d5 b5c4f333f9de6485 6c231b78114a63d1
pow 8483ee0c9834834c 7f7c9716ffb764d5 b504f333f9de6485 2cc9b662148976d8
pow 8483ee0c9834834c a27c9716ffb764d5 b504f333f9de6485 9833d32827c56876
pow 8483ee0c9834834c 827c9716ffb764d5 b504f333f9de6485 44640cc39fd4788
pow 7483ee0c9834834c 727c9716ffb764d5 b504f333f9de6485 55086f87b6043f40
pow 8483ee0c9834834c 727c9716ffb764d5 b504f333f9de6489 5de3cc538a4912b2
pow 8483ee0c9834834c 727c9716ffb764d5 b504f333f9de7485 7dee09f7103356f7
pow 8483ee0c9834834c 727c9716ffb764d5 b504f332f9de6485 31e66ba6b6f01dbc
pow 8483ee0c9834834c 727c9716ffb764d5 b504f233f9de6485 36a16ab51897078d
pow 8483ee0c9834834c 727c9716ffb764d5 b524f333f9de6485 50139fa7019a79b2
pow 8483ee0c9834834c 727c9716ffb764d5 b544f333f9de6485 218964ebf2bf02bc
pow 8483ee0c9834834c 727c9716ffb764d5 b704f333f9de6485 60f74c122162ed95
pow 8483ee0c9834834c 727c9716ffb764d5 b104f333f9de6485 16855ca50047d45e
pow 8483ee0c9834834c 727c9716ffb764d5 c504f333f9de6485 2d27db08d15c5e30
pow 8483ee0c9834834c 727c9716ffb764d5 f504f333f9de6485 43c59cdd83e4cb0e
pow 8493ee0c9834834c 727c9716ffb764d5 b504f333f9de6485 b8f2e35b869b538
pow 8083ee0c9834834c 727c9716ffb764d5 b504f333f9de6485 709ba83061fbedec
pow 9483ee0c9834834c 727c9716ffb764d5 b504f333f9de6485 74a637bb3a6686ab
modmul 13988e 194c583ada5b529204a2bc83eb7b05d44d9baa55f4f890cd9bfea55a7 5a827999fcef32422cbec4d9baa55f4f8eb7b05d44d9baa55f4f89dd426768bd64 1efbde91a17127884d7d32ffd5f1f18750c651ddcb394371cfa91ff23baaa2
modmul 13988e 194c583ada1b529204a2bc830cd9bfea55a7 5a827999fcef32422cbec4d9baa55f4f8eb7b05d449dd426768bd64 1efbde91a122c5504d7d32fec547ba91ff23baaa2
modmul 13988e 194c583ade5b529204a2bc830cd9bfea55a7 5a827999fcef32422cbec4d9baa55f4f8eb7b05d449dd426768bd64 1efbde91a6574b084d7d32fec547ba91ff23baaa2
modmul 13988e 194c583ada5b529204a2bc830cd9bfea55a7 3a827999fcef32422cbec4d9baa55f4 3168752910948165510fe90bd7ab5d6
modmul 13988e 194c583ada7b529204a2b 5a827999fcef32422cb 564931ea2a366069fa0
modmul 13988e 194c583ada1b529204a2b 5a827999fcef32422cb 5641d8b4ea366069fa0
modmul 13988e 194c58 5a827999fcef32422cbec4d97999fcef32422cbec4d9baa55baa55f4f8eb7b05d449dd426768bd642cccccccccccccccccccccccccccccccc199cc8aa57 1efbde498d0
modmul 13988e 194c58 5a827999fcef32422cbec4d9baa55f4f8eb7b05d449dd426768bf65f4f8eb7b05d449dd426768bd642c142c199cc8aa57 1efbde498d0
modmul 13988e 194c58 5a827999fcef32422cbec827999fcef32422cbec4d99fcef32422cbe32422cbec8279aa55f4f8e4d9baa55f4f8eb 1efbde498d0
modmul 13988e 194c58ee5827999fcef32422cbec4d9baa55f4f2422cbec4d9baa55f4f8ed 1efbde48eb 17247c498b
modmul 13988e 194242b 1efbde4aa55f4f8eb 1eef84d697da
modmul 6d28e 194c58 5a82799 4b07f1e
modmul 13988e 194c58 3a8 90
modmul 13988e 194c58 9a8 438
modmul 93988e 194c58 5a8 418
mul 16c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfe8e1e 400000000000000000000000d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 5b0b662568813ac6686ed6e7fa92c1116b9e82723896e0c88f73a9faa96b8ac9b4c6efa28706e2696b0addabd81c3c9ff6167d1b5e537339bee8dfca0814b84
mul 16c2d9895a204eb19a1bb5b9b3c06d262c4bf90b040fec72b389cf6fd375533 2cfd2d7d74d29145b4ffd73ef7617d71a92e8006ee548e1d 3ffffffffffffb03af375d6c1c311c6e51e081bfe99f6b41a84698ec8806beb21ddb37330f58d39c67989aa2ebdd2300fecefebf42f0c7
mul 16c2d9895a204eb00000000000000000004bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe85b4ffd73ef7617d71a92e8006ee548e1e 3ffffffffffffffb7eda681a2eca0a66bebccfbd4ca3fa67c9ba58e8735028859d32a47c8411726411fd5c7779d7ce5b04076dbea2c376bf5bc7a45fa
mul 16c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 40000000000000 5b0b662568813ac6686ed6e6cf01b498b12fe42dd2ffb1cace273f4b5f5d34a531b96113b6fa2e5fc516d3ff5cfbdd85f5c6a4ba001bb95238780000000000000
mul 16c2d9895a2bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 400000000020cd0df0a99c9bcec9106a845f2589fb29d491cf9909dc7c53bc3dcad9a6eca00e5b04076dbea2c376bf5bc7a45fa
mul 16c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e9e 400000000000000000000000000000000000000000000000000000000000000b616cc4ad102758cd0ddadcd9e037357125cae0be6763f7fc885e7745824df7a
mul 16c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 127a4ced4bbf629ccbc8948c987f25b3a7680de91680271a98ec6120591559a00000000000000000000000000000a25affce5b04076dbea2c376bf5bc7a45fa
mul 16c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec76b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 40000000000000000000000000000000000000000000000b3f4b5f5d34a531b96113b6fa2e5fc516d3ff5cfbdd869821a4885b1fc0bff71ac376bf5bc7a45fa
mul 16c2d9895a204eb19a1bb5b9b3c06d272c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 40000000000000000000000000000002cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee553078ffce5b04076dbea2c376bf5bc7a45fa
mul 16c2d9895a204eb59a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 400000000000000b3f4b5f5d34a531b96113b6fa2e5fc516d3ff5cfbdd85f5c6a4ba001bb9523878000000000000a25affce5b04076dbea2c376bf5bc7a45fa
mul 12c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 34c0b4a0a2cb5ace469eec4905d1a03ae92c00a304227a0a395b45ffe446adc78800000000000000000000000000a25affce5b04076dbea2c376bf5bc7a45fa
mul 36c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 99fa5afae9a5298dcb089db7d172fe28b69ffae7deec2fae3525d000ddca91c3c000000000000000000000000000a25affce5b04076dbea2c376bf5bc7a45fa
mul 56c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e f3f4b5f5d34a531b96113b6fa2e5fc516d3ff5cfbdd85f5c6a4ba001bb9523878000000000000000000000000000a25affce5b04076dbea2c376bf5bc7a45fa
mul 96c2d9895a204eb19a1bb5b9b3c06d262c4bf90b74bfec72b389cf6fd375533 2cfd2d7d74d294c6e5844edbe8b97f145b4ffd73ef7617d71a92e8006ee548e1e 1a7e96beba694a6372c2276df45cbf8a2da7feb9f7bb0beb8d4974003772a470f0000000000000000000000000000a25affce5b04076dbea2c376bf5bc7a45fa
mul 1 bbbbbbbbb0 bbbbbbbbb0
mul 1 a a
mul 1 e e
mul a c 78
mul 1 1 1
mul a 4 28
mul 1 2 2
mul 1 8 8
mul 1 0 0
mul 0 4 0
mul 3 4 c
mul 5 4 14
mul 9 4 24

Просмотреть файл

@ -43,6 +43,7 @@
#define PUTTY_DO_GLOBALS /* actually _define_ globals */ #define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h" #include "putty.h"
#include "mpint.h"
#include "ssh.h" #include "ssh.h"
#include "sshserver.h" #include "sshserver.h"
@ -221,11 +222,11 @@ bool auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob)
return false; return false;
} }
struct RSAKey *auth_publickey_ssh1( struct RSAKey *auth_publickey_ssh1(
AuthPolicy *ap, ptrlen username, Bignum rsa_modulus) AuthPolicy *ap, ptrlen username, mp_int *rsa_modulus)
{ {
struct AuthPolicy_ssh1_pubkey *iter; struct AuthPolicy_ssh1_pubkey *iter;
for (iter = ap->ssh1keys; iter; iter = iter->next) { for (iter = ap->ssh1keys; iter; iter = iter->next) {
if (!bignum_cmp(rsa_modulus, iter->key.modulus)) if (mp_cmp_eq(rsa_modulus, iter->key.modulus))
return &iter->key; return &iter->key;
} }
return NULL; return NULL;

Просмотреть файл

@ -349,7 +349,8 @@ struct rsa_key_thread_params {
union { union {
struct RSAKey *key; struct RSAKey *key;
struct dss_key *dsskey; struct dss_key *dsskey;
struct ec_key *eckey; struct ecdsa_key *eckey;
struct eddsa_key *edkey;
}; };
}; };
static DWORD WINAPI generate_key_thread(void *param) static DWORD WINAPI generate_key_thread(void *param)
@ -364,9 +365,10 @@ static DWORD WINAPI generate_key_thread(void *param)
if (params->keytype == DSA) if (params->keytype == DSA)
dsa_generate(params->dsskey, params->key_bits, progress_update, &prog); dsa_generate(params->dsskey, params->key_bits, progress_update, &prog);
else if (params->keytype == ECDSA) else if (params->keytype == ECDSA)
ec_generate(params->eckey, params->curve_bits, progress_update, &prog); ecdsa_generate(params->eckey, params->curve_bits,
progress_update, &prog);
else if (params->keytype == ED25519) else if (params->keytype == ED25519)
ec_edgenerate(params->eckey, 256, progress_update, &prog); eddsa_generate(params->edkey, 256, progress_update, &prog);
else else
rsa_generate(params->key, params->key_bits, progress_update, &prog); rsa_generate(params->key, params->key_bits, progress_update, &prog);
@ -390,7 +392,8 @@ struct MainDlgState {
union { union {
struct RSAKey key; struct RSAKey key;
struct dss_key dsskey; struct dss_key dsskey;
struct ec_key eckey; struct ecdsa_key eckey;
struct eddsa_key edkey;
}; };
HMENU filemenu, keymenu, cvtmenu; HMENU filemenu, keymenu, cvtmenu;
}; };
@ -1401,7 +1404,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
} else if (state->keytype == ECDSA) { } else if (state->keytype == ECDSA) {
state->ssh2key.key = &state->eckey.sshk; state->ssh2key.key = &state->eckey.sshk;
} else if (state->keytype == ED25519) { } else if (state->keytype == ED25519) {
state->ssh2key.key = &state->eckey.sshk; state->ssh2key.key = &state->edkey.sshk;
} else { } else {
state->ssh2key.key = &state->key.sshk; state->ssh2key.key = &state->key.sshk;
} }