You are right, it is an accident that unicode can be encoded to base64. It just annoys me that the Python 2.6 error for this is "TypeError: character mapping must return integer, None or unicode". In that case, how would you feel about updating PlainTextPasswordManager instead? It is not like the others because it won't work unless hash is a unicode PlainTextPasswordManager().encodePassword(u"password") => unicode PlainTextPasswordManager().checkPassword(unicode, unicode) and the others break unless hash is always a str. .encodePassword(u"password") => str .checkPassword(str, unicode) Here's my DelegatingPasswordManager. I might update it so .encodePassword() uses the unnamed IPasswordManager if installed. It would be nice if IPasswordManager included the name of the scheme to go between {} before the hash proper. class DelegatingPasswordManager(object): """Check passwords stored RFC 2307 style as {scheme}hash. Delegates to named IPasswordManager utilities.""" implements(IPasswordManager) SCHEME = u"Delegating Password Manager" _scheme = re.compile(r"^{(?P<scheme>[^}]*)}(?P<hash>.*)$") def encodePassword(self, password): raise NotImplementedError("DelegatingPasswordManager can only check passwords") def checkPassword(self, encoded_password, password): handler = None match = self._scheme.match(encoded_password) if not match: raise ValueError("Encoded password must be formatted as {scheme}hash.") try: scheme = match.group("scheme") handler = getUtility(IPasswordManager, scheme) except zope.component.interfaces.ComponentLookupError, e: raise LookupError("Handler for password encryption scheme {%s} not found." % scheme, e) if handler != self: return handler.checkPassword(encoded_password, password) return False