summaryrefslogtreecommitdiff
path: root/lib/thandy/keys.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/thandy/keys.py')
-rw-r--r--lib/thandy/keys.py46
1 files changed, 32 insertions, 14 deletions
diff --git a/lib/thandy/keys.py b/lib/thandy/keys.py
index 5b4e072..2f433b5 100644
--- a/lib/thandy/keys.py
+++ b/lib/thandy/keys.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
# These require PyCrypto.
import Crypto.PublicKey.RSA
@@ -17,9 +18,8 @@ import thandy.formats
import thandy.util
class PublicKey:
+ """Abstract base class for public keys."""
def __init__(self):
- # Confusingly, these roles are the ones used for a private key to
- # remember what we're willing to do with it.
self._roles = []
def format(self):
raise NotImplemented()
@@ -32,13 +32,25 @@ class PublicKey:
def getKeyID(self):
raise NotImplemented()
def getRoles(self):
+ """Remove a list of all roles supported by this key. A role is
+ from this key. A role is a doctype,pathPattern tuple.
+ """
return self._roles
def addRole(self, role, path):
+ """Add a role to the list of roles supported by this key.
+ A role is a permission to sign a given kind of document
+ (one of thandy.format.ALL_ROLES) at a given set of relative
+ paths.
+ """
assert role in thandy.formats.ALL_ROLES
self._roles.append((role, path))
def clearRoles(self):
+ """Remove all roles from this key."""
del self._roles[:]
def hasRole(self, role, path):
+ """Return true iff this key has a role that allows it to sign
+ a document of type 'role' at location in the repository 'path'.
+ """
for r, p in self._roles:
if r == role and thandy.formats.rolePathMatches(p, path):
return True
@@ -57,6 +69,7 @@ if hex(1L).upper() == "0X1L":
return binascii.a2b_hex(h)
elif hex(1L).upper() == "0X1":
def intToBinary(number):
+ "Variant for future versions of pythons that don't append 'L'."
h = hex(long(number))
h = h[2:]
if len(h)%2:
@@ -73,9 +86,11 @@ def binaryToInt(binary):
return long(binascii.b2a_hex(binary), 16)
def intToBase64(number):
+ """Convert an int or long to a big-endian base64-encoded value."""
return thandy.formats.formatBase64(intToBinary(number))
def base64ToInt(number):
+ """Convert a big-endian base64-encoded value to a long."""
return binaryToInt(thandy.formats.parseBase64(number))
def _pkcs1_padding(m, size):
@@ -123,11 +138,14 @@ class RSAKey(PublicKey):
@staticmethod
def generate(bits=2048):
+ """Generate a new RSA key, with modulus length 'bits'."""
key = Crypto.PublicKey.RSA.generate(bits=bits, randfunc=os.urandom)
return RSAKey(key)
@staticmethod
def fromJSon(obj):
+ """Construct an RSA key from the output of the format() method.
+ """
# obj must match RSAKEY_SCHEMA
thandy.formats.RSAKEY_SCHEMA.checkMatch(obj)
@@ -150,9 +168,14 @@ class RSAKey(PublicKey):
return result
def isPrivateKey(self):
+ """Return true iff this key has private-key components"""
return hasattr(self.key, 'd')
def format(self, private=False, includeRoles=False):
+ """Returna a new object to represent this key in json format.
+ If 'private', include private-key data. If 'includeRoles',
+ include role information.
+ """
n = intToBase64(self.key.n)
e = intToBase64(self.key.e)
result = { '_keytype' : 'rsa',
@@ -168,25 +191,19 @@ class RSAKey(PublicKey):
return result
def getKeyID(self):
+ """Return the KeyID for this key.
+ """
if self.keyid == None:
d_obj = Crypto.Hash.SHA256.new()
thandy.formats.getDigest(self.format(), d_obj)
self.keyid = thandy.formats.formatHash(d_obj.digest())
return self.keyid
- def _digest(self, obj, method=None):
- if method in (None, "sha256-pkcs1"):
- d_obj = Crypto.Hash.SHA256.new()
- thandy.formats.getDigest(obj, d_obj)
- digest = d_obj.digest()
- return ("sha256-pkcs1", digest)
-
- raise UnknownMethod(method)
-
def sign(self, obj=None, digest=None):
assert _xor(obj == None, digest == None)
+ method = "sha256-pkcs1"
if digest == None:
- method, digest = self._digest(obj)
+ digest = thandy.formats.getDigest(obj)
m = _pkcs1_padding(digest, (self.key.size()+1) // 8)
sig = intToBase64(self.key.sign(m, "")[0])
return (method, sig)
@@ -194,9 +211,9 @@ class RSAKey(PublicKey):
def checkSignature(self, method, sig, obj=None, digest=None):
assert _xor(obj == None, digest == None)
if method != "sha256-pkcs1":
- raise UnknownMethod("method")
+ raise UnknownMethod(method)
if digest == None:
- method, digest = self._digest(obj, method)
+ digest = thandy.formats.getDigest(obj)
sig = base64ToInt(sig)
m = _pkcs1_padding(digest, (self.key.size()+1) // 8)
return bool(self.key.verify(m, (sig,)))
@@ -324,6 +341,7 @@ def decryptSecret(encrypted, password):
return secret
class KeyStore(thandy.formats.KeyDB):
+ """Helper to store private keys in an encrypted file."""
def __init__(self, fname, encrypted=True):
thandy.formats.KeyDB.__init__(self)