def get_keypair(hostname): """Generate a dummy keypair for the given hostname. This method generates a dummy DSA keypair for the given hostname. It returns a tuple (pub, priv) where "pub" is a dict of values for the public key, and "priv" is a DSA128Key object containing the private key. Multiple calls to this method for the same hostname are guaranteed to produce the same key. To make this work we take advantage of the fact that DSA key generation is just "generate x by some random method, where 0 < x < q". Replace "some random method" with "sha1 hash of hostname" and we're all set. """ # Use pre-agreed parameters for p, q and g. q = DUMMY_Q p = DUMMY_P g = DUMMY_G # Generate private key x by "some random method". x = long(hashlib.sha1(hostname).hexdigest(), 16) assert x != 0, "SHA1(hostname) is zero - what are the odds?!" # Calculate public key y as usual. y = pow(g, x, p) data = { "algorithm": "DS", "p": _hex(p), "q": _hex(q), "g": _hex(g), "y": _hex(y), "x": _hex(x), } privkey = jwt.DS128Key(data) del data["x"] return data, privkey
def test_dsa_verification(self): # This is a dummy DSA key I generated via PyCrypto. # M2Crypto doesn't seem to let me get at the values of x and y. # I've line wrapped it for readability. def _hex(value): return hex(long(value.replace(" ", "").replace("\n", "").strip())) data = { "p": _hex("""6703904104057623261995085583676902361410672713749348 7374515589871295072792250899011720632358392764362903244 12395020783955234715731001076129344181463063193L"""), "q": hex(1006478751418673383937866166434285354892250535133L), "g": _hex("""1801778249650423365253284139284406405780267098493217 0320675876307450879812560049234773036938891018778074993 01874343843218156663689824126183823813389886834L"""), "y": _hex("""4148629652526876030475847300836791685289385792662680 5886292874741635965095055693693232436255359496594291250 77637642734034732001089176915352691113947372211L"""), "x": hex(487025797851506801093339352420308364866214860934L), } key = jwt.DS128Key(data) data.pop("x") pubkey = jwt.DS128Key(data) # This key should be able to sign and verify things to itself. self.assertTrue(pubkey.verify("hello", key.sign("hello"))) self.assertFalse(pubkey.verify("HELLO", key.sign("hello"))) self.assertRaises(Exception, pubkey.sign, "hello") # And it should gracefully handle a variety of stupid input: # - signature too long self.assertFalse(pubkey.verify("HELLO", "X" * 100)) # - "r" value too large self.assertFalse(pubkey.verify("HELLO", ("\xFF" * 20) + "\x01" * 20)) # - "s" value too large self.assertFalse(pubkey.verify("HELLO", "\x01" + ("\xFF" * 20)))
def _make_keypair(self): data = DS128_KEY_DATA.copy() key = jwt.DS128Key(data) data.pop("x") pubkey = FALLBACK_DS128Key(data) return key, pubkey