/usr/lib/python2.7/dist-packages/passlib/handlers/oracle.py is in python-passlib 1.5.3-0ubuntu3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | """passlib.handlers.oracle - Oracle DB Password Hashes"""
#=========================================================
#imports
#=========================================================
#core
from binascii import hexlify, unhexlify
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
#pkg
from passlib.utils import xor_bytes, handlers as uh, bytes, to_unicode, \
to_hash_str, b
from passlib.utils.des import des_encrypt_block
#local
__all__ = [
"oracle10g",
"oracle11g"
]
#=========================================================
#oracle10
#=========================================================
def des_cbc_encrypt(key, value, iv=b('\x00') * 8, pad=b('\x00')):
"""performs des-cbc encryption, returns only last block.
this performs a specific DES-CBC encryption implementation
as needed by the Oracle10 hash. it probably won't be useful for
other purposes as-is.
input value is null-padded to multiple of 8 bytes.
:arg key: des key as bytes
:arg value: value to encrypt, as bytes.
:param iv: optional IV
:param pad: optional pad byte
:returns: last block of DES-CBC encryption of all ``value``'s byte blocks.
"""
value += pad * (-len(value) % 8) #null pad to multiple of 8
hash = iv #start things off
for offset in xrange(0,len(value),8):
chunk = xor_bytes(hash, value[offset:offset+8])
hash = des_encrypt_block(key, chunk)
return hash
#: magic string used as initial des key by oracle10
ORACLE10_MAGIC = b("\x01\x23\x45\x67\x89\xAB\xCD\xEF")
class oracle10(uh.StaticHandler):
"""This class implements the password hash used by Oracle up to version 10g, and follows the :ref:`password-hash-api`.
It has no salt and a single fixed round.
The :meth:`encrypt()` and :meth:`genconfig` methods accept no optional keywords.
The :meth:`encrypt()`, :meth:`genhash()`, and :meth:`verify()` methods all require the
following additional contextual keywords:
:param user: string containing name of oracle user account this password is associated with.
"""
#=========================================================
#algorithm information
#=========================================================
name = "oracle10"
setting_kwds = ()
context_kwds = ("user",)
#=========================================================
#formatting
#=========================================================
_pat = re.compile(ur"^[0-9a-fA-F]{16}$")
@classmethod
def identify(cls, hash):
return uh.identify_regexp(hash, cls._pat)
#=========================================================
#primary interface
#=========================================================
@classmethod
def genhash(cls, secret, config, user):
if config is not None and not cls.identify(config):
raise ValueError("not an oracle-10g hash")
if secret is None:
raise TypeError("secret must be specified")
if not user:
raise ValueError("user keyword must be specified for this algorithm")
#FIXME: not sure how oracle handles unicode.
# online docs about 10g hash indicate it puts ascii chars
# in a 2-byte encoding w/ the high bytenull.
# they don't say how it handles other chars,
# or what encoding.
#
# so for now, encoding secret & user to utf-16-be,
# since that fits,
# and if secret/user is bytes, we assume utf-8, and decode first.
#
# this whole mess really needs someone w/ an oracle system,
# and some answers :)
def encode(value):
"encode according to guess at how oracle encodes strings (see note above)"
#we can't trust what original encoding was.
#user should have passed us unicode in the first place.
#but try decoding as utf-8 just to work for most common case.
value = to_unicode(value, "utf-8")
return value.upper().encode("utf-16-be")
input = encode(user) + encode(secret)
hash = des_cbc_encrypt(ORACLE10_MAGIC, input)
hash = des_cbc_encrypt(hash, input)
return to_hash_str(hexlify(hash)).upper()
@classmethod
def _norm_hash(cls, hash):
if isinstance(hash, bytes):
hash = hash.decode("ascii")
return hash.upper()
#=========================================================
#eoc
#=========================================================
#=========================================================
#oracle11
#=========================================================
class oracle11(uh.HasSalt, uh.GenericHandler):
"""This class implements the Oracle11g password hash, and follows the :ref:`password-hash-api`.
It supports a fixed-length salt.
The :meth:`encrypt()` and :meth:`genconfig` methods accept the following optional keywords:
:param salt:
Optional salt string.
If not specified, one will be autogenerated (this is recommended).
If specified, it must be 20 hexidecimal characters.
"""
#=========================================================
#class attrs
#=========================================================
#--GenericHandler--
name = "oracle11"
setting_kwds = ("salt",)
checksum_size = 40
checksum_chars = uh.UC_HEX_CHARS
_stub_checksum = u'0' * 40
#--HasSalt--
min_salt_size = max_salt_size = 20
salt_chars = uh.UC_HEX_CHARS
#=========================================================
#methods
#=========================================================
_pat = re.compile(u"^S:(?P<chk>[0-9a-f]{40})(?P<salt>[0-9a-f]{20})$", re.I)
@classmethod
def identify(cls, hash):
return uh.identify_regexp(hash, cls._pat)
@classmethod
def from_string(cls, hash):
if not hash:
raise ValueError("no hash provided")
if isinstance(hash, bytes):
hash = hash.decode("ascii")
m = cls._pat.match(hash)
if not m:
raise ValueError("invalid oracle-11g hash")
salt, chk = m.group("salt", "chk")
return cls(salt=salt, checksum=chk.upper(), strict=True)
def to_string(self):
chk = (self.checksum or self._stub_checksum)
hash = u"S:%s%s" % (chk.upper(), self.salt.upper())
return to_hash_str(hash)
def calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
chk = sha1(secret + unhexlify(self.salt.encode("ascii"))).hexdigest()
return to_unicode(chk, 'ascii').upper()
#=========================================================
#eoc
#=========================================================
#=========================================================
#eof
#=========================================================
|