зеркало из https://github.com/github/putty.git
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:
Родитель
d73a1716f6
Коммит
25b034ee39
13
Recipe
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
|
||||||
|
|
12
cmdgen.c
12
cmdgen.c
|
@ -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);
|
||||||
|
|
|
@ -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
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;
|
||||||
|
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
39
import.c
39
import.c
|
@ -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 */
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||||
|
};
|
43
pageant.c
43
pageant.c
|
@ -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
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);
|
||||||
|
|
23
ssh1login.c
23
ssh1login.c
|
@ -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
2180
sshbn.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
2
sshccp.c
2
sshccp.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
|
||||||
|
|
10
sshcommon.c
10
sshcommon.c
|
@ -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
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
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 = {
|
||||||
|
|
86
sshdssg.c
86
sshdssg.c
|
@ -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
3305
sshecc.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
64
sshecdsag.c
64
sshecdsag.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;
|
||||||
}
|
}
|
||||||
|
|
280
sshprime.c
280
sshprime.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
sshpubk.c
18
sshpubk.c
|
@ -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
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
sshrsag.c
50
sshrsag.c
|
@ -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
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;
|
|
||||||
}
|
|
|
@ -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))
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче