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

Ecc.py changes #511

Closed
wants to merge 4 commits into from
Closed
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
17 changes: 11 additions & 6 deletions tlslite/keyexchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
from .messages import ServerKeyExchange, ClientKeyExchange, CertificateVerify
from .constants import SignatureAlgorithm, HashAlgorithm, CipherSuite, \
ExtensionType, GroupName, ECCurveType, SignatureScheme
from .utils.ecc import decodeX962Point, encodeX962Point, getCurveByName, \
getPointByteSize
from .utils.ecc import getCurveByName, getPointByteSize
from .utils.rsakey import RSAKey
from .utils.cryptomath import bytesToNumber, getRandomBytes, powMod, \
numBits, numberToByteArray, divceil, numBytes, secureHash
Expand All @@ -23,7 +22,7 @@
from .utils.x25519 import x25519, x448, X25519_G, X448_G, X25519_ORDER_SIZE, \
X448_ORDER_SIZE
from .utils.compat import int_types
from .utils.codec import DecodeError
from .utils.codec import DecodeError, Writer


class KeyExchange(object):
Expand Down Expand Up @@ -1015,7 +1014,11 @@ def calc_public_value(self, private):
return fun(private, generator)
else:
curve = getCurveByName(GroupName.toStr(self.group))
return encodeX962Point(curve.generator * private)
point = curve.generator * private
writer = Writer()
writer.add(4, 1)
writer.bytes += point.to_bytes()
return writer.bytes

def calc_shared_key(self, private, peer_share):
"""Calculate the shared key,"""
Expand All @@ -1029,8 +1032,10 @@ def calc_shared_key(self, private, peer_share):
else:
curve = getCurveByName(GroupName.toRepr(self.group))
try:
ecdhYc = decodeX962Point(peer_share,
curve)
abstractPoint = ecdsa.ellipticcurve.AbstractPoint().from_bytes(curve.curve, peer_share)
ecdhYc = ecdsa.ellipticcurve.Point(curve.curve,
abstractPoint[0],
abstractPoint[1]).from_bytes(curve.curve, peer_share)
except (AssertionError, DecodeError):
raise TLSIllegalParameterException("Invalid ECC point")

Expand Down
27 changes: 1 addition & 26 deletions tlslite/utils/ecc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,10 @@
# See the LICENSE file for legal information regarding use of this file.
"""Methods for dealing with ECC points"""

from .codec import Parser, Writer, DecodeError
from .cryptomath import bytesToNumber, numberToByteArray, numBytes
from .compat import ecdsaAllCurves
import ecdsa
from .compat import ecdsaAllCurves


def decodeX962Point(data, curve=ecdsa.NIST256p):
"""Decode a point from a X9.62 encoding"""
parser = Parser(data)
encFormat = parser.get(1)
if encFormat != 4:
raise DecodeError("Not an uncompressed point encoding")
bytelength = getPointByteSize(curve)
xCoord = bytesToNumber(parser.getFixBytes(bytelength))
yCoord = bytesToNumber(parser.getFixBytes(bytelength))
if parser.getRemainingLength():
raise DecodeError("Invalid length of point encoding for curve")
return ecdsa.ellipticcurve.Point(curve.curve, xCoord, yCoord)


def encodeX962Point(point):
"""Encode a point in X9.62 format"""
bytelength = numBytes(point.curve().p())
writer = Writer()
writer.add(4, 1)
writer.bytes += numberToByteArray(point.x(), bytelength)
writer.bytes += numberToByteArray(point.y(), bytelength)
return writer.bytes

def getCurveByName(curveName):
"""Return curve identified by curveName"""
curveMap = {'secp256r1':ecdsa.NIST256p,
Expand Down
25 changes: 17 additions & 8 deletions unit_tests/test_tlslite_keyexchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@
from tlslite.x509 import X509
from tlslite.x509certchain import X509CertChain
from tlslite.utils.keyfactory import parsePEMKey
from tlslite.utils.codec import Parser
from tlslite.utils.codec import Parser, Writer
from tlslite.utils.cryptomath import bytesToNumber, getRandomBytes, powMod, \
numberToByteArray, isPrime, numBits
from tlslite.mathtls import makeX, makeU, makeK, goodGroupParameters
from tlslite.handshakehashes import HandshakeHashes
from tlslite import VerifierDB
from tlslite.extensions import SupportedGroupsExtension, SNIExtension
from tlslite.utils.ecc import getCurveByName, decodeX962Point, encodeX962Point,\
getPointByteSize
from tlslite.utils.ecc import getCurveByName, getPointByteSize
from tlslite.utils.compat import a2b_hex
import ecdsa
from operator import mul
Expand Down Expand Up @@ -1953,8 +1952,15 @@ def test_ECDHE_key_exchange(self):
curve = getCurveByName(curveName)
generator = curve.generator
cln_Xc = ecdsa.util.randrange(generator.order())
cln_Ys = decodeX962Point(srv_key_ex.ecdh_Ys, curve)
cln_Yc = encodeX962Point(generator * cln_Xc)
abstractPoint = ecdsa.ellipticcurve.AbstractPoint().from_bytes(curve.curve, srv_key_ex.ecdh_Ys)
cln_Ys = ecdsa.ellipticcurve.Point(curve.curve,
abstractPoint[0],
abstractPoint[1]).from_bytes(curve.curve, srv_key_ex.ecdh_Ys)
point = generator * cln_Xc
writer = Writer()
writer.add(4, 1)
writer.bytes += point.to_bytes()
cln_Yc = writer.bytes

cln_key_ex = ClientKeyExchange(self.cipher_suite, (3, 3))
cln_key_ex.createECDH(cln_Yc)
Expand All @@ -1981,9 +1987,12 @@ def test_ECDHE_key_exchange_with_invalid_CKE(self):
curve = getCurveByName(curveName)
generator = curve.generator
cln_Xc = ecdsa.util.randrange(generator.order())
cln_Ys = decodeX962Point(srv_key_ex.ecdh_Ys, curve)
cln_Yc = encodeX962Point(generator * cln_Xc)

point = generator * cln_Xc
writer = Writer()
writer.add(4, 1)
writer.bytes += point.to_bytes()
cln_Yc = writer.bytes

cln_key_ex = ClientKeyExchange(self.cipher_suite, (3, 3))
cln_key_ex.createECDH(cln_Yc)

Expand Down
142 changes: 1 addition & 141 deletions unit_tests/test_tlslite_utils_ecc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,149 +10,9 @@
except ImportError:
import unittest

from tlslite.utils.ecc import decodeX962Point, encodeX962Point, getCurveByName,\
getPointByteSize
from tlslite.utils.ecc import getCurveByName,getPointByteSize
import ecdsa

class TestEncoder(unittest.TestCase):
def test_encode_P_256_point(self):
point = ecdsa.NIST256p.generator * 200

self.assertEqual(encodeX962Point(point),
bytearray(b'\x04'
# x coordinate
b'\x3a\x53\x5b\xd0\xbe\x46\x6f\xf3\xd8\x56'
b'\xa0\x77\xaa\xd9\x50\x4f\x16\xaa\x5d\x52'
b'\x28\xfc\xd7\xc2\x77\x48\x85\xee\x21\x3f'
b'\x3b\x34'
# y coordinate
b'\x66\xab\xa8\x18\x5b\x33\x41\xe0\xc2\xe3'
b'\xd1\xb3\xae\x69\xe4\x7d\x0f\x01\xd4\xbb'
b'\xd7\x06\xd9\x57\x8b\x0b\x65\xd6\xd3\xde'
b'\x1e\xfe'
))

def test_encode_P_256_point_with_zero_first_byte_on_x(self):
point = ecdsa.NIST256p.generator * 379

self.assertEqual(encodeX962Point(point),
bytearray(b'\x04'
b'\x00\x55\x43\x89\x4a\xf3\xd0\x0e\xd7\xd7'
b'\x40\xab\xdb\xd7\x5c\x96\xb0\x68\x77\xb7'
b'\x87\xdb\x5f\x70\xee\xa7\x8b\x90\xa8\xd7'
b'\xc0\x0a'
b'\xbb\x4c\x85\xa3\xd8\xea\x29\xef\xaa\xfa'
b'\x24\x40\x69\x12\xdd\x84\xd5\xb1\x4d\xc3'
b'\x2b\xf6\x56\xef\x6c\x6b\xd5\x8a\x5d\x94'
b'\x3f\x92'
))

def test_encode_P_256_point_with_zero_first_byte_on_y(self):
point = ecdsa.NIST256p.generator * 43

self.assertEqual(encodeX962Point(point),
bytearray(b'\x04'
b'\x98\x6a\xe2\x50\x6f\x1f\xf1\x04\xd0\x42'
b'\x30\x86\x1d\x8f\x4b\x49\x8f\x4b\xc4\xc6'
b'\xd0\x09\xb3\x0f\x75\x44\xdc\x12\x9b\x82'
b'\xd2\x8d'
b'\x00\x3c\xcc\xc0\xa6\x46\x0e\x0a\xe3\x28'
b'\xa4\xd9\x7d\x3c\x7b\x61\xd8\x6f\xc6\x28'
b'\x9c\x18\x9f\x25\x25\x11\x0c\x44\x1b\xb0'
b'\x7e\x97'
))

def test_encode_P_256_point_with_two_zero_first_bytes_on_x(self):
point = ecdsa.NIST256p.generator * 40393

self.assertEqual(encodeX962Point(point),
bytearray(b'\x04'
b'\x00\x00\x3f\x5f\x17\x8a\xa0\x70\x6c\x42'
b'\x31\xeb\x6e\x54\x95\xaa\x16\x42\xc5\xb8'
b'\xa9\x94\x12\x7c\x89\x46\x5f\x22\x99\x4a'
b'\x42\xf9'
b'\xc2\x48\xb3\x37\x59\x9f\x0c\x2f\x29\x77'
b'\x2e\x25\x6f\x1d\x55\x49\xc8\x9b\xa9\xe5'
b'\x73\x13\x82\xcd\x1e\x3c\xc0\x9d\x10\xd0'
b'\x0b\x55'))

def test_encode_P_521_point(self):
point = ecdsa.NIST521p.generator * 200

self.assertEqual(encodeX962Point(point),
bytearray(b'\x04'
b'\x00\x3e\x2a\x2f\x9f\xd5\x9f\xc3\x8d\xfb'
b'\xde\x77\x26\xa0\xbf\xc6\x48\x2a\x6b\x2a'
b'\x86\xf6\x29\xb8\x34\xa0\x6c\x3d\x66\xcd'
b'\x79\x8d\x9f\x86\x2e\x89\x31\xf7\x10\xc7'
b'\xce\x89\x15\x9f\x35\x8b\x4a\x5c\x5b\xb3'
b'\xd2\xcc\x9e\x1b\x6e\x94\x36\x23\x6d\x7d'
b'\x6a\x5e\x00\xbc\x2b\xbe'
b'\x01\x56\x7a\x41\xcb\x48\x8d\xca\xd8\xe6'
b'\x3a\x3f\x95\xb0\x8a\xf6\x99\x2a\x69\x6a'
b'\x37\xdf\xc6\xa1\x93\xff\xbc\x3f\x91\xa2'
b'\x96\xf3\x3c\x66\x15\x57\x3c\x1c\x06\x7f'
b'\x0a\x06\x4d\x18\xbd\x0c\x81\x4e\xf7\x2a'
b'\x8f\x76\xf8\x7f\x9b\x7d\xff\xb2\xf4\x26'
b'\x36\x43\x43\x86\x11\x89'))

class TestDecoder(unittest.TestCase):
def test_decode_P_256_point(self):
point = ecdsa.NIST256p.generator * 379
data = bytearray(b'\x04'
b'\x00\x55\x43\x89\x4a\xf3\xd0\x0e\xd7\xd7'
b'\x40\xab\xdb\xd7\x5c\x96\xb0\x68\x77\xb7'
b'\x87\xdb\x5f\x70\xee\xa7\x8b\x90\xa8\xd7'
b'\xc0\x0a'
b'\xbb\x4c\x85\xa3\xd8\xea\x29\xef\xaa\xfa'
b'\x24\x40\x69\x12\xdd\x84\xd5\xb1\x4d\xc3'
b'\x2b\xf6\x56\xef\x6c\x6b\xd5\x8a\x5d\x94'
b'\x3f\x92'
)

decoded_point = decodeX962Point(data, ecdsa.NIST256p)

self.assertEqual(point, decoded_point)

def test_decode_P_521_point(self):

data = bytearray(b'\x04'
b'\x01\x7d\x8a\x5d\x11\x03\x4a\xaf\x01\x26'
b'\x5f\x2d\xd6\x2d\x76\xeb\xd8\xbe\x4e\xfb'
b'\x3b\x4b\xd2\x05\x5a\xed\x4c\x6d\x20\xc7'
b'\xf3\xd7\x08\xab\x21\x9e\x34\xfd\x14\x56'
b'\x3d\x47\xd0\x02\x65\x15\xc2\xdd\x2d\x60'
b'\x66\xf9\x15\x64\x55\x7a\xae\x56\xa6\x7a'
b'\x28\x51\x65\x26\x5c\xcc'
b'\x01\xd4\x19\x56\xfa\x14\x6a\xdb\x83\x1c'
b'\xb6\x1a\xc4\x4b\x40\xb1\xcb\xcc\x9e\x4f'
b'\x57\x2c\xb2\x72\x70\xb9\xef\x38\x15\xae'
b'\x87\x1f\x85\x40\x94\xda\x69\xed\x97\xeb'
b'\xdc\x72\x25\x25\x61\x76\xb2\xde\xed\xa2'
b'\xb0\x5c\xca\xc4\x83\x8f\xfb\x54\xae\xe0'
b'\x07\x45\x0b\xbf\x7c\xfc')

point = decodeX962Point(data, ecdsa.NIST521p)
self.assertIsNotNone(point)

self.assertEqual(encodeX962Point(point), data)

def test_decode_with_missing_data(self):
data = bytearray(b'\x04'
b'\x00\x55\x43\x89\x4a\xf3\xd0\x0e\xd7\xd7'
b'\x40\xab\xdb\xd7\x5c\x96\xb0\x68\x77\xb7'
b'\x87\xdb\x5f\x70\xee\xa7\x8b\x90\xa8\xd7'
b'\xc0\x0a'
b'\xbb\x4c\x85\xa3\xd8\xea\x29\xef\xaa\xfa'
b'\x24\x40\x69\x12\xdd\x84\xd5\xb1\x4d\xc3'
b'\x2b\xf6\x56\xef\x6c\x6b\xd5\x8a\x5d\x94'
#b'\x3f\x92'
)

# XXX will change later as decoder in tlslite-ng needs to be updated
with self.assertRaises(SyntaxError):
decodeX962Point(data, ecdsa.NIST256p)

class TestCurveLookup(unittest.TestCase):
def test_with_correct_name(self):
curve = getCurveByName('secp256r1')
Expand Down
Loading