Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply nonce bit-length mitigation to stop timing leakage. #125

Merged
merged 2 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/ecdsa/curves.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from __future__ import division

from . import der, ecdsa
from .util import orderlen


class UnknownCurveError(Exception):
pass
# orderlen was defined in this module previously, so keep it in __all__,
# will need to mark it as deprecated later
__all__ = ["UnknownCurveError", "orderlen", "Curve", "NIST192p",
"NIST224p", "NIST256p", "NIST384p", "NIST521p", "curves",
"find_curve"]


def orderlen(order):
return (1+len("%x" % order))//2 # bytes
class UnknownCurveError(Exception):
pass


# the NIST curves
Expand Down
11 changes: 10 additions & 1 deletion src/ecdsa/ecdsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from six import int2byte, b
from . import ellipticcurve
from . import numbertheory
from .util import bit_length


class RSZeroError(RuntimeError):
Expand Down Expand Up @@ -171,7 +172,15 @@ def sign(self, hash, random_k):
G = self.public_key.generator
n = G.order()
k = random_k % n
p1 = k * G
# Fix the bit-length of the random nonce,
# so that it doesn't leak via timing.
# This does not change that ks = k mod n
ks = k + n
kt = ks + n
if bit_length(ks) == bit_length(n):
p1 = kt * G
else:
p1 = ks * G
r = p1.x() % n
if r == 0:
raise RSZeroError("amazingly unlucky random number r")
Expand Down
10 changes: 6 additions & 4 deletions src/ecdsa/ellipticcurve.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ def __eq__(self, other):
else:
return False

def __neg__(self):
return Point(self.__curve, self.__x, self.__curve.p() - self.__y)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why point negation is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really for the fix, but the scalarmult can handle negative scalars now.

def __add__(self, other):
"""Add one point to another point."""

Expand Down Expand Up @@ -123,13 +126,12 @@ def leftmost_bit(x):
return result // 2

e = other
if self.__order:
e = e % self.__order
if e == 0:
if e == 0 or (self.__order and e % self.__order == 0):
return INFINITY
if self == INFINITY:
return INFINITY
assert e > 0
if e < 0:
return (-self) * (-e)

# From X9.62 D.3.2:

Expand Down
10 changes: 4 additions & 6 deletions src/ecdsa/rfc6979.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@

import hmac
from binascii import hexlify
from .util import number_to_string, number_to_string_crop
from .util import number_to_string, number_to_string_crop, bit_length
from six import b


def bit_length(num):
# http://docs.python.org/dev/library/stdtypes.html#int.bit_length
s = bin(num) # binary representation: bin(-37) --> '-0b100101'
s = s.lstrip('-0b') # remove leading zeros and minus sign
return len(s) # len('100101') --> 6
# bit_length was defined in this module previously so keep it for backwards
# compatibility, will need to deprecate and remove it later
__all__ = ["bit_length", "bits2int", "bits2octets", "generate_k"]


def bits2int(data, qlen):
Expand Down
12 changes: 11 additions & 1 deletion src/ecdsa/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import binascii
from hashlib import sha256
from . import der
from .curves import orderlen
from six import PY3, int2byte, b, next

# RFC5480:
Expand All @@ -17,6 +16,17 @@
encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey)


def bit_length(num):
# http://docs.python.org/dev/library/stdtypes.html#int.bit_length
s = bin(num) # binary representation: bin(-37) --> '-0b100101'
s = s.lstrip('-0b') # remove leading zeros and minus sign
return len(s) # len('100101') --> 6


def orderlen(order):
return (1+len("%x" % order))//2 # bytes


def randrange(order, entropy=None):
"""Return a random integer k such that 1 <= k < order, uniformly
distributed across that range. For simplicity, this only behaves well if
Expand Down