@@ -1284,7 +1284,6 @@ cdef class MessageWithData(Message):
12841284 self ._write_close_temp_lobs_piggyback(buf)
12851285
12861286
1287- @cython.final
12881287cdef class AuthMessage(Message):
12891288 cdef:
12901289 str encoded_password
@@ -1305,6 +1304,26 @@ cdef class AuthMessage(Message):
13051304 dict session_data
13061305 uint32_t auth_mode
13071306 uint32_t verifier_type
1307+ bint change_password
1308+
1309+ cdef int _encrypt_passwords(self ) except - 1 :
1310+ """
1311+ Encrypts the passwords using the session key.
1312+ """
1313+
1314+ # encrypt password
1315+ salt = secrets.token_bytes(16 )
1316+ password_with_salt = salt + self .password
1317+ encrypted_password = encrypt_cbc(self .conn_impl._combo_key,
1318+ password_with_salt)
1319+ self .encoded_password = encrypted_password.hex().upper()
1320+
1321+ # encrypt new password
1322+ if self .newpassword is not None :
1323+ newpassword_with_salt = salt + self .newpassword
1324+ encrypted_newpassword = encrypt_cbc(self .conn_impl._combo_key,
1325+ newpassword_with_salt)
1326+ self .encoded_newpassword = encrypted_newpassword.hex().upper()
13081327
13091328 cdef int _generate_verifier(self , bint verifier_11g) except - 1 :
13101329 """
@@ -1342,35 +1361,27 @@ cdef class AuthMessage(Message):
13421361 # create session key from combo key
13431362 mixing_salt = bytes.fromhex(self .session_data[' AUTH_PBKDF2_CSK_SALT' ])
13441363 iterations = int (self .session_data[' AUTH_PBKDF2_SDER_COUNT' ])
1345- combo_key = session_key_part_b[:keylen] + session_key_part_a[:keylen]
1346- session_key = get_derived_key(combo_key.hex().upper().encode(),
1347- mixing_salt, keylen, iterations)
1364+ temp_key = session_key_part_b[:keylen] + session_key_part_a[:keylen]
1365+ combo_key = get_derived_key(temp_key.hex().upper().encode(),
1366+ mixing_salt, keylen, iterations)
1367+
1368+ # retain session key for use by the change password API
1369+ self .conn_impl._combo_key = combo_key
13481370
13491371 # generate speedy key for 12c verifiers
13501372 if not verifier_11g:
13511373 salt = secrets.token_bytes(16 )
1352- speedy_key = encrypt_cbc(session_key , salt + password_key)
1374+ speedy_key = encrypt_cbc(combo_key , salt + password_key)
13531375 self .speedy_key = speedy_key[:80 ].hex().upper()
13541376
1355- # encrypt password
1356- salt = secrets.token_bytes(16 )
1357- password_with_salt = salt + self .password
1358- encrypted_password = encrypt_cbc(session_key, password_with_salt)
1359- self .encoded_password = encrypted_password.hex().upper()
1360-
1361- # encrypt new password
1362- if self .newpassword is not None :
1363- newpassword_with_salt = salt + self .newpassword
1364- encrypted_newpassword = encrypt_cbc(session_key,
1365- newpassword_with_salt)
1366- self .encoded_newpassword = encrypted_newpassword.hex().upper()
1377+ # encrypts the passwords
1378+ self ._encrypt_passwords()
13671379
13681380 # check if debug_jdwp is set. if set, encode the data using the
13691381 # combo session key with zeros padding
13701382 if self .debug_jdwp is not None :
13711383 jdwp_data = self .debug_jdwp.encode()
1372- encrypted_jdwp_data = encrypt_cbc(session_key, jdwp_data,
1373- zeros = True )
1384+ encrypted_jdwp_data = encrypt_cbc(combo_key, jdwp_data, zeros = True )
13741385 # Add a "01" at the end of the hex encrypted data to indicate the
13751386 # use of AES encryption
13761387 self .encoded_jdwp_data = encrypted_jdwp_data.hex().upper() + " 01"
@@ -1427,7 +1438,7 @@ cdef class AuthMessage(Message):
14271438 self .session_data[key] = value
14281439 if self .function_code == TNS_FUNC_AUTH_PHASE_ONE:
14291440 self .function_code = TNS_FUNC_AUTH_PHASE_TWO
1430- else :
1441+ elif not self .change_password :
14311442 self .conn_impl._session_id = \
14321443 < uint32_t> int (self .session_data[" AUTH_SESSION_ID" ])
14331444 self .conn_impl._serial_num = \
@@ -1513,6 +1524,9 @@ cdef class AuthMessage(Message):
15131524 # perform final determination of data to write
15141525 if self .function_code == TNS_FUNC_AUTH_PHASE_ONE:
15151526 num_pairs = 5
1527+ elif self .change_password:
1528+ self ._encrypt_passwords()
1529+ num_pairs = 2
15161530 else :
15171531 num_pairs = 3
15181532
@@ -1578,22 +1592,24 @@ cdef class AuthMessage(Message):
15781592 self .proxy_user)
15791593 if self .token is not None :
15801594 self ._write_key_value(buf, " AUTH_TOKEN" , self .token)
1581- else :
1595+ elif not self .change_password :
15821596 self ._write_key_value(buf, " AUTH_SESSKEY" , self .session_key, 1 )
1583- self ._write_key_value(buf, " AUTH_PASSWORD" ,
1584- self .encoded_password)
15851597 if not verifier_11g:
15861598 self ._write_key_value(buf, " AUTH_PBKDF2_SPEEDY_KEY" ,
15871599 self .speedy_key)
1588- if self .newpassword is not None :
1600+ if self .encoded_password is not None :
1601+ self ._write_key_value(buf, " AUTH_PASSWORD" ,
1602+ self .encoded_password)
1603+ if self .encoded_newpassword is not None :
15891604 self ._write_key_value(buf, " AUTH_NEWPASSWORD" ,
15901605 self .encoded_newpassword)
1591- self ._write_key_value(buf, " SESSION_CLIENT_CHARSET" , " 873" )
1592- driver_name = f" {constants.DRIVER_NAME} thn : {VERSION}"
1593- self ._write_key_value(buf, " SESSION_CLIENT_DRIVER_NAME" ,
1594- driver_name)
1595- self ._write_key_value(buf, " SESSION_CLIENT_VERSION" ,
1596- str (_connect_constants.full_version_num))
1606+ if not self .change_password:
1607+ self ._write_key_value(buf, " SESSION_CLIENT_CHARSET" , " 873" )
1608+ driver_name = f" {constants.DRIVER_NAME} thn : {VERSION}"
1609+ self ._write_key_value(buf, " SESSION_CLIENT_DRIVER_NAME" ,
1610+ driver_name)
1611+ self ._write_key_value(buf, " SESSION_CLIENT_VERSION" ,
1612+ str (_connect_constants.full_version_num))
15971613 if self .conn_impl._cclass is not None :
15981614 self ._write_key_value(buf, " AUTH_KPPL_CONN_CLASS" ,
15991615 self .conn_impl._cclass)
@@ -1615,6 +1631,21 @@ cdef class AuthMessage(Message):
16151631 self .encoded_jdwp_data)
16161632
16171633
1634+ @cython.final
1635+ cdef class ChangePasswordMessage(AuthMessage):
1636+
1637+ cdef int _initialize_hook(self ) except - 1 :
1638+ """
1639+ Perform initialization.
1640+ """
1641+ self .change_password = True
1642+ self .function_code = TNS_FUNC_AUTH_PHASE_TWO
1643+ self .user_bytes = self .conn_impl.username.encode()
1644+ self .user_bytes_len = len (self .user_bytes)
1645+ self .auth_mode = TNS_AUTH_MODE_WITH_PASSWORD | \
1646+ TNS_AUTH_MODE_CHANGE_PASSWORD
1647+
1648+
16181649@cython.final
16191650cdef class CommitMessage(Message):
16201651
0 commit comments