| Index: third_party/google-endpoints/jwkest/ecc.py
|
| diff --git a/third_party/google-endpoints/jwkest/ecc.py b/third_party/google-endpoints/jwkest/ecc.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..14956d8f3e9e994ff72ad9b2ed8df45a5299c270
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/jwkest/ecc.py
|
| @@ -0,0 +1,108 @@
|
| +#!/usr/bin/env python
|
| +
|
| +# pylint: disable=invalid-name
|
| +
|
| +from __future__ import print_function
|
| +from __future__ import absolute_import
|
| +from __future__ import division
|
| +
|
| +from Crypto.Util.number import long_to_bytes, bytes_to_long
|
| +from jwkest.elliptic import inv, mulp, sign_bit, y_from_x, muladdp
|
| +from jwkest.curves import get_curve
|
| +from random import getrandbits
|
| +from math import ceil
|
| +
|
| +
|
| +# Make the EC interface more OO
|
| +class NISTEllipticCurve(object):
|
| + def __init__(self, bits):
|
| + # (bits, prime, order, p, q, point)
|
| + (self.bits, self.p, self.N, self.a, self.b, self.G) = get_curve(bits)
|
| + self.bytes = int(ceil(self.bits / 8.0))
|
| +
|
| + @staticmethod
|
| + def by_name(name):
|
| + if name == "P-256" or name == b'P-256':
|
| + return NISTEllipticCurve(256)
|
| + if name == "P-384" or name == b'P-384':
|
| + return NISTEllipticCurve(384)
|
| + if name == "P-521" or name == b'P-521':
|
| + return NISTEllipticCurve(521)
|
| + else:
|
| + raise Exception("Unknown curve {0}".format(name))
|
| +
|
| + # Get the name of this curve
|
| + # XXX This only works because we only support prime curves right now
|
| + def name(self):
|
| + return "P-{0}".format(self.bits)
|
| +
|
| + # Integer-to-byte-string conversion
|
| + def int2bytes(self, x):
|
| + return long_to_bytes(x, self.bytes)
|
| +
|
| + @staticmethod
|
| + def bytes2int(x):
|
| + return bytes_to_long(x)
|
| +
|
| + # Point compression
|
| + @staticmethod
|
| + def compress(p):
|
| + return p[0], sign_bit(p)
|
| +
|
| + def uncompress(self, p):
|
| + return p[0], y_from_x(p[0], self.a, self.b, self.p, p[1])
|
| +
|
| + # Return a new key pair for this curve
|
| + def key_pair(self):
|
| + priv = (getrandbits(self.bits) % (self.N - 1)) + 1
|
| + pub = mulp(self.a, self.b, self.p, self.G, priv)
|
| + return priv, pub
|
| +
|
| + def public_key_for(self, priv):
|
| + return mulp(self.a, self.b, self.p, self.G, priv)
|
| +
|
| + # Compute the DH shared secret (X coordinate) from a public key and private
|
| + # key
|
| + def dh_z(self, priv, pub):
|
| + return self.int2bytes(mulp(self.a, self.b, self.p, pub, priv)[0])
|
| +
|
| + def _sign_loop(self, r, s, h, k, priv):
|
| + while r == 0 or s == 0:
|
| + if k is None:
|
| + k = (getrandbits(self.bits) % (self.N - 1)) + 1
|
| + kinv = inv(k, self.N)
|
| + kg = mulp(self.a, self.b, self.p, self.G, k)
|
| + r = kg[0] % self.N
|
| + if r == 0:
|
| + continue
|
| + s = (kinv * (h + r * priv)) % self.N
|
| + return r, s
|
| +
|
| + # ECDSA (adapted from ecdsa.py)
|
| + def sign(self, h, priv, k=None):
|
| + while h > self.N:
|
| + h >>= 1
|
| +
|
| + r = s = 0
|
| +
|
| + r, s = self._sign_loop(r, s, h, k, priv)
|
| +
|
| + return self.int2bytes(r) + self.int2bytes(s)
|
| +
|
| + def verify(self, h, sig, pub):
|
| + while h > self.N:
|
| + h >>= 1
|
| + r = self.bytes2int(sig[:self.bytes])
|
| + s = self.bytes2int(sig[self.bytes:])
|
| + if 0 < r < self.N and 0 < s < self.N:
|
| + w = inv(s, self.N)
|
| + u1 = (h * w) % self.N
|
| + u2 = (r * w) % self.N
|
| + x, y = muladdp(self.a, self.b, self.p, self.G, u1, pub, u2)
|
| + return r % self.N == x % self.N
|
| + return False
|
| +
|
| +
|
| +P256 = NISTEllipticCurve(256)
|
| +P384 = NISTEllipticCurve(384)
|
| +P521 = NISTEllipticCurve(521)
|
|
|