Skip to content

Commit 5ec3f5c

Browse files
Fixed bug connecting to databases with older 11g password verifiers
(#189).
1 parent 9f7a1c3 commit 5ec3f5c

File tree

2 files changed

+38
-26
lines changed

2 files changed

+38
-26
lines changed

doc/src/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ oracledb 1.3.2 (TBD)
1313
Thin Mode Changes
1414
+++++++++++++++++
1515

16+
#) Fixed bug connecting to databases with older 11g password verifiers
17+
(`issue 189 <https://github.com/oracle/python-oracledb/issues/189>`__).
18+
1619
Thick Mode Changes
1720
++++++++++++++++++
1821

src/oracledb/impl/thin/messages.pyx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,20 +1326,18 @@ cdef class AuthMessage(Message):
13261326
newpassword_with_salt)
13271327
self.encoded_newpassword = encrypted_newpassword.hex().upper()
13281328

1329-
cdef int _generate_verifier(self, bint verifier_11g) except -1:
1329+
cdef int _generate_verifier(self) except -1:
13301330
"""
13311331
Generate the multi-round verifier.
13321332
"""
1333-
cdef bytes jdwp_data
1333+
cdef:
1334+
bytes jdwp_data
1335+
bytearray b
1336+
ssize_t i
13341337

13351338
# create password hash
13361339
verifier_data = bytes.fromhex(self.session_data['AUTH_VFR_DATA'])
1337-
if verifier_11g:
1338-
keylen = 24
1339-
h = hashlib.sha1(self.password)
1340-
h.update(verifier_data)
1341-
password_hash = h.digest() + bytes(4)
1342-
else:
1340+
if self.verifier_type == TNS_VERIFIER_TYPE_12C:
13431341
keylen = 32
13441342
iterations = int(self.session_data['AUTH_PBKDF2_VGEN_COUNT'])
13451343
salt = verifier_data + b'AUTH_PBKDF2_SPEEDY_KEY'
@@ -1349,28 +1347,42 @@ cdef class AuthMessage(Message):
13491347
h.update(password_key)
13501348
h.update(verifier_data)
13511349
password_hash = h.digest()[:32]
1350+
else:
1351+
keylen = 24
1352+
h = hashlib.sha1(self.password)
1353+
h.update(verifier_data)
1354+
password_hash = h.digest() + bytes(4)
13521355

13531356
# decrypt first half of session key
13541357
encoded_server_key = bytes.fromhex(self.session_data['AUTH_SESSKEY'])
13551358
session_key_part_a = decrypt_cbc(password_hash, encoded_server_key)
13561359

13571360
# generate second half of session key
1358-
session_key_part_b = secrets.token_bytes(32)
1361+
session_key_part_b = secrets.token_bytes(len(session_key_part_a))
13591362
encoded_client_key = encrypt_cbc(password_hash, session_key_part_b)
1360-
self.session_key = encoded_client_key.hex().upper()[:64]
13611363

1362-
# create session key from combo key
1363-
mixing_salt = bytes.fromhex(self.session_data['AUTH_PBKDF2_CSK_SALT'])
1364-
iterations = int(self.session_data['AUTH_PBKDF2_SDER_COUNT'])
1365-
temp_key = session_key_part_b[:keylen] + session_key_part_a[:keylen]
1366-
combo_key = get_derived_key(temp_key.hex().upper().encode(),
1367-
mixing_salt, keylen, iterations)
1364+
# create session key and combo key
1365+
if len(session_key_part_a) == 48:
1366+
self.session_key = encoded_client_key.hex().upper()[:96]
1367+
b = bytearray(24)
1368+
for i in range(16, 40):
1369+
b[i - 16] = session_key_part_a[i] ^ session_key_part_b[i]
1370+
part1 = hashlib.md5(b[:16]).digest()
1371+
part2 = hashlib.md5(b[16:]).digest()
1372+
combo_key = (part1 + part2)[:keylen]
1373+
else:
1374+
self.session_key = encoded_client_key.hex().upper()[:64]
1375+
salt = bytes.fromhex(self.session_data['AUTH_PBKDF2_CSK_SALT'])
1376+
iterations = int(self.session_data['AUTH_PBKDF2_SDER_COUNT'])
1377+
temp_key = session_key_part_b[:keylen] + session_key_part_a[:keylen]
1378+
combo_key = get_derived_key(temp_key.hex().upper().encode(), salt,
1379+
keylen, iterations)
13681380

13691381
# retain session key for use by the change password API
13701382
self.conn_impl._combo_key = combo_key
13711383

13721384
# generate speedy key for 12c verifiers
1373-
if not verifier_11g:
1385+
if self.verifier_type == TNS_VERIFIER_TYPE_12C:
13741386
salt = secrets.token_bytes(16)
13751387
speedy_key = encrypt_cbc(combo_key, salt + password_key)
13761388
self.speedy_key = speedy_key[:80].hex().upper()
@@ -1538,7 +1550,6 @@ cdef class AuthMessage(Message):
15381550
cdef int _write_message(self, WriteBuffer buf) except -1:
15391551
cdef:
15401552
uint8_t has_user = 1 if self.user_bytes_len > 0 else 0
1541-
bint verifier_11g = False
15421553
uint32_t num_pairs
15431554

15441555
# perform final determination of data to write
@@ -1558,15 +1569,13 @@ cdef class AuthMessage(Message):
15581569
else:
15591570
num_pairs += 2
15601571
self.auth_mode |= TNS_AUTH_MODE_WITH_PASSWORD
1561-
if self.verifier_type in (TNS_VERIFIER_TYPE_11G_1,
1562-
TNS_VERIFIER_TYPE_11G_2):
1563-
verifier_11g = True
1564-
elif self.verifier_type != TNS_VERIFIER_TYPE_12C:
1572+
if self.verifier_type == TNS_VERIFIER_TYPE_12C:
1573+
num_pairs += 1
1574+
elif self.verifier_type not in (TNS_VERIFIER_TYPE_11G_1,
1575+
TNS_VERIFIER_TYPE_11G_2):
15651576
errors._raise_err(errors.ERR_UNSUPPORTED_VERIFIER_TYPE,
15661577
verifier_type=self.verifier_type)
1567-
else:
1568-
num_pairs += 1
1569-
self._generate_verifier(verifier_11g)
1578+
self._generate_verifier()
15701579

15711580
# determine which other key/value pairs to write
15721581
if self.newpassword is not None:
@@ -1614,7 +1623,7 @@ cdef class AuthMessage(Message):
16141623
self._write_key_value(buf, "AUTH_TOKEN", self.token)
16151624
elif not self.change_password:
16161625
self._write_key_value(buf, "AUTH_SESSKEY", self.session_key, 1)
1617-
if not verifier_11g:
1626+
if self.verifier_type == TNS_VERIFIER_TYPE_12C:
16181627
self._write_key_value(buf, "AUTH_PBKDF2_SPEEDY_KEY",
16191628
self.speedy_key)
16201629
if self.encoded_password is not None:

0 commit comments

Comments
 (0)