OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 |
| 3 # pylint: disable=invalid-name |
| 4 |
| 5 from __future__ import print_function |
| 6 from __future__ import absolute_import |
| 7 from __future__ import division |
| 8 |
| 9 from Crypto.Util.number import long_to_bytes, bytes_to_long |
| 10 from jwkest.elliptic import inv, mulp, sign_bit, y_from_x, muladdp |
| 11 from jwkest.curves import get_curve |
| 12 from random import getrandbits |
| 13 from math import ceil |
| 14 |
| 15 |
| 16 # Make the EC interface more OO |
| 17 class NISTEllipticCurve(object): |
| 18 def __init__(self, bits): |
| 19 # (bits, prime, order, p, q, point) |
| 20 (self.bits, self.p, self.N, self.a, self.b, self.G) = get_curve(bits) |
| 21 self.bytes = int(ceil(self.bits / 8.0)) |
| 22 |
| 23 @staticmethod |
| 24 def by_name(name): |
| 25 if name == "P-256" or name == b'P-256': |
| 26 return NISTEllipticCurve(256) |
| 27 if name == "P-384" or name == b'P-384': |
| 28 return NISTEllipticCurve(384) |
| 29 if name == "P-521" or name == b'P-521': |
| 30 return NISTEllipticCurve(521) |
| 31 else: |
| 32 raise Exception("Unknown curve {0}".format(name)) |
| 33 |
| 34 # Get the name of this curve |
| 35 # XXX This only works because we only support prime curves right now |
| 36 def name(self): |
| 37 return "P-{0}".format(self.bits) |
| 38 |
| 39 # Integer-to-byte-string conversion |
| 40 def int2bytes(self, x): |
| 41 return long_to_bytes(x, self.bytes) |
| 42 |
| 43 @staticmethod |
| 44 def bytes2int(x): |
| 45 return bytes_to_long(x) |
| 46 |
| 47 # Point compression |
| 48 @staticmethod |
| 49 def compress(p): |
| 50 return p[0], sign_bit(p) |
| 51 |
| 52 def uncompress(self, p): |
| 53 return p[0], y_from_x(p[0], self.a, self.b, self.p, p[1]) |
| 54 |
| 55 # Return a new key pair for this curve |
| 56 def key_pair(self): |
| 57 priv = (getrandbits(self.bits) % (self.N - 1)) + 1 |
| 58 pub = mulp(self.a, self.b, self.p, self.G, priv) |
| 59 return priv, pub |
| 60 |
| 61 def public_key_for(self, priv): |
| 62 return mulp(self.a, self.b, self.p, self.G, priv) |
| 63 |
| 64 # Compute the DH shared secret (X coordinate) from a public key and private |
| 65 # key |
| 66 def dh_z(self, priv, pub): |
| 67 return self.int2bytes(mulp(self.a, self.b, self.p, pub, priv)[0]) |
| 68 |
| 69 def _sign_loop(self, r, s, h, k, priv): |
| 70 while r == 0 or s == 0: |
| 71 if k is None: |
| 72 k = (getrandbits(self.bits) % (self.N - 1)) + 1 |
| 73 kinv = inv(k, self.N) |
| 74 kg = mulp(self.a, self.b, self.p, self.G, k) |
| 75 r = kg[0] % self.N |
| 76 if r == 0: |
| 77 continue |
| 78 s = (kinv * (h + r * priv)) % self.N |
| 79 return r, s |
| 80 |
| 81 # ECDSA (adapted from ecdsa.py) |
| 82 def sign(self, h, priv, k=None): |
| 83 while h > self.N: |
| 84 h >>= 1 |
| 85 |
| 86 r = s = 0 |
| 87 |
| 88 r, s = self._sign_loop(r, s, h, k, priv) |
| 89 |
| 90 return self.int2bytes(r) + self.int2bytes(s) |
| 91 |
| 92 def verify(self, h, sig, pub): |
| 93 while h > self.N: |
| 94 h >>= 1 |
| 95 r = self.bytes2int(sig[:self.bytes]) |
| 96 s = self.bytes2int(sig[self.bytes:]) |
| 97 if 0 < r < self.N and 0 < s < self.N: |
| 98 w = inv(s, self.N) |
| 99 u1 = (h * w) % self.N |
| 100 u2 = (r * w) % self.N |
| 101 x, y = muladdp(self.a, self.b, self.p, self.G, u1, pub, u2) |
| 102 return r % self.N == x % self.N |
| 103 return False |
| 104 |
| 105 |
| 106 P256 = NISTEllipticCurve(256) |
| 107 P384 = NISTEllipticCurve(384) |
| 108 P521 = NISTEllipticCurve(521) |
OLD | NEW |