5 from foolscap.api import Referenceable, Tub
6 from zope.interface import implements
7 from twisted.internet import reactor
8 from twisted.application import service
9 from allmydata.util import log, fileutil
11 from pycryptopp.publickey import rsa
12 from allmydata.interfaces import RIKeyGenerator
14 class KeyGenerator(service.MultiService, Referenceable):
15 implements(RIKeyGenerator)
17 pool_size = 16 # no. keys to keep on hand in the pool
18 pool_refresh_delay = 6 # no. sec to wait after a fetch before generating new keys
21 def __init__(self, default_key_size=2048):
22 service.MultiService.__init__(self)
25 self.default_key_size = default_key_size
27 def startService(self):
28 self.timer = reactor.callLater(0, self.maybe_refill_pool)
29 return service.MultiService.startService(self)
31 def stopService(self):
32 if self.timer.active():
34 return service.MultiService.stopService(self)
37 return '<KeyGenerator[%s]>' % (len(self.keypool),)
43 def reset_timer(self):
44 self.last_fetch = time.time()
45 if self.timer.active():
46 self.timer.reset(self.pool_refresh_delay)
48 self.timer = reactor.callLater(self.pool_refresh_delay, self.maybe_refill_pool)
50 def maybe_refill_pool(self):
52 if self.last_fetch + self.pool_refresh_delay < now:
53 self.vlog('%s refilling pool' % (self,))
54 while len(self.keypool) < self.pool_size:
55 self.keypool.append(self.gen_key(self.default_key_size))
57 self.vlog('%s not refilling pool' % (self,))
58 reactor.callLater(1, self.maybe_refill_pool)
60 def gen_key(self, key_size):
61 self.vlog('%s generating key size %s' % (self, key_size, ))
62 signer = rsa.generate(key_size)
63 verifier = signer.get_verifying_key()
64 return verifier.serialize(), signer.serialize()
66 def remote_get_rsa_key_pair(self, key_size):
67 self.vlog('%s remote_get_key' % (self,))
68 if key_size != self.default_key_size or not self.keypool:
69 key = self.gen_key(key_size)
74 return self.keypool.pop()
76 class KeyGeneratorService(service.MultiService):
77 furl_file = 'key_generator.furl'
79 def __init__(self, basedir='.', display_furl=True, default_key_size=2048):
80 service.MultiService.__init__(self)
81 self.basedir = basedir
82 fileutil.make_dirs(self.basedir)
83 self.tub = Tub(certFile=os.path.join(self.basedir, 'key_generator.pem'))
84 self.tub.setOption("expose-remote-exception-types", False)
85 self.tub.setServiceParent(self)
86 self.key_generator = KeyGenerator(default_key_size=default_key_size)
87 self.key_generator.setServiceParent(self)
89 portnum = self.get_portnum()
90 self.listener = self.tub.listenOn(portnum or 'tcp:0')
91 d = self.tub.setLocationAutomatically()
93 d.addCallback(self.save_portnum)
94 d.addCallback(self.tub_ready, display_furl)
97 def get_portnum(self):
98 portnumfile = os.path.join(self.basedir, 'portnum')
99 if os.path.exists(portnumfile):
100 return file(portnumfile, 'rb').read().strip()
102 def save_portnum(self, junk):
103 portnum = self.listener.getPortnum()
104 portnumfile = os.path.join(self.basedir, 'portnum')
105 file(portnumfile, 'wb').write('%d\n' % (portnum,))
107 def tub_ready(self, junk, display_furl):
108 kgf = os.path.join(self.basedir, self.furl_file)
109 self.keygen_furl = self.tub.registerReference(self.key_generator, furlFile=kgf)
111 print 'key generator at:', self.keygen_furl