@@ -9,8 +9,7 @@ import hashlib
99import hmac
1010from hashlib import pbkdf2_hmac
1111include " scram.pyx"
12-
13-
12+ include " sha256.pyx"
1413
1514
1615cdef dict AUTH_METHOD_NAME = {
@@ -23,248 +22,6 @@ cdef dict AUTH_METHOD_NAME = {
2322}
2423
2524
26- cdef hex_string_to_bytes(str hex_string):
27- """
28- 将hex字符串转换为bytes,对应Go的hexStringToBytes函数
29- """
30- if not hex_string:
31- return b' '
32-
33- cdef str upper_string = hex_string.upper()
34- cdef int bytes_len = len (upper_string) // 2
35- cdef bytearray result = bytearray(bytes_len)
36- cdef int i, pos
37- cdef str high_char, low_char
38- cdef int high_val, low_val
39-
40- for i in range (bytes_len):
41- pos = i * 2
42- high_char = upper_string[pos]
43- low_char = upper_string[pos + 1 ]
44-
45- # 将字符转换为数值
46- high_val = " 0123456789ABCDEF" .index(high_char)
47- low_val = " 0123456789ABCDEF" .index(low_char)
48-
49- result[i] = (high_val << 4 ) | low_val
50-
51- return bytes(result)
52-
53- cdef generate_k_from_pbkdf2(str password, str random64code, int server_iteration):
54- """
55- 对应Go的generateKFromPBKDF2函数
56- 注意:Go代码使用的是SHA1,不是SHA256
57- """
58- cdef bytes random32code = hex_string_to_bytes(random64code)
59- # Go代码使用sha1.New,所以这里使用'sha1'
60- cdef bytes pwd_encoded = pbkdf2_hmac(' sha1' , password.encode(' utf-8' ), random32code, server_iteration, 32 )
61- return pwd_encoded
62-
63- cdef bytes_to_hex_string(bytes src):
64- """
65- 对应Go的bytesToHexString函数
66- """
67- cdef str s = " "
68- cdef int byte_val, v
69- cdef str hv
70-
71- for byte_val in src:
72- v = byte_val & 0xFF
73- hv = format(v, ' x' )
74- if len (hv) < 2 :
75- s += " 0" + hv
76- else :
77- s += hv
78- return s
79-
80- cdef get_key_from_hmac(bytes key, bytes data):
81- """
82- 对应Go的getKeyFromHmac函数,使用SHA256
83- """
84- cdef object h = hmac.new(key, data, hashlib.sha256)
85- return h.digest()
86-
87- cdef get_sha256(bytes message):
88- """
89- 对应Go的getSha256函数
90- """
91- cdef object hash_obj = hashlib.sha256()
92- hash_obj.update(message)
93- return hash_obj.digest()
94-
95- cdef get_sm3(bytes message):
96- """
97- 对应Go的getSm3函数 (这里用SHA256代替,因为Python标准库没有SM3)
98- 实际项目中需要安装gmssl库来支持SM3
99- """
100- # 注意:这里用SHA256代替SM3,实际使用时需要proper的SM3实现
101- cdef object hash_obj = hashlib.sha256() # 临时用SHA256代替
102- hash_obj.update(message)
103- return hash_obj.digest()
104-
105- cdef xor_between_password(bytes password1, bytes password2, int length):
106- """
107- 对应Go的XorBetweenPassword函数
108- """
109- cdef bytearray result = bytearray(length)
110- cdef int i
111-
112- for i in range (length):
113- result[i] = password1[i] ^ password2[i]
114- return bytes(result)
115-
116- cdef bytes_to_hex(bytes source_bytes, bytearray result_array = None , int start_pos = 0 , int length = - 1 ):
117- """
118- 对应Go的bytesToHex函数,支持Java风格的4参数调用
119- 但Go代码只传1个参数,所以做兼容处理
120- """
121- cdef bytes lookup = b' 0123456789abcdef'
122- cdef int pos, i, c, j
123- cdef int byte_val
124- cdef bytearray result
125-
126- if result_array is not None :
127- # Java风格:4个参数 bytesToHex(hValue, result, 0, hValue.length)
128- if length == - 1 :
129- length = len (source_bytes)
130-
131- pos = start_pos
132-
133- for i in range (length):
134- if i >= len (source_bytes):
135- break
136- byte_val = source_bytes[i]
137- c = int (byte_val & 0xFF )
138- j = c >> 4
139- result_array[pos] = lookup[j]
140- pos += 1
141- j = c & 0xF
142- result_array[pos] = lookup[j]
143- pos += 1
144- return result_array
145- else :
146- # Go风格:1个参数,返回新的bytes
147- result = bytearray(len (source_bytes) * 2 )
148- pos = 0
149-
150- for byte_val in source_bytes:
151- c = int (byte_val & 0xFF )
152- j = c >> 4
153- result[pos] = lookup[j]
154- pos += 1
155- j = c & 0xF
156- result[pos] = lookup[j]
157- pos += 1
158-
159- return bytes(result)
160-
161- cpdef rfc5802_algorithm(str password, str random64code, str token, str server_signature = " " , int server_iteration = 4096 , str method = " sha256" ):
162- """
163- RFC5802算法实现,完全对应Go代码逻辑
164- """
165- cdef bytes k, server_key, client_key, stored_key, token_byte
166- cdef bytes client_signature, hmac_result, h_value
167- cdef bytearray result
168- cdef int h_value_len
169-
170- try :
171- # Step 1: 生成K (SaltedPassword)
172- k = generate_k_from_pbkdf2(password, random64code, server_iteration)
173-
174- # Step 2: 生成ServerKey和ClientKey
175- server_key = get_key_from_hmac(k, b" Sever Key" ) # 保持"Sever Key"拼写
176- client_key = get_key_from_hmac(k, b" Client Key" )
177-
178- # Step 3: 生成StoredKey
179- if method.lower() == " sha256" :
180- stored_key = get_sha256(client_key)
181- elif method.lower() == " sm3" :
182- stored_key = get_sm3(client_key)
183- else :
184- stored_key = get_sha256(client_key) # 默认使用SHA256
185-
186- # Step 4: 转换token为bytes
187- token_byte = hex_string_to_bytes(token)
188-
189- # Step 5: 计算clientSignature (实际上是ServerSignature,用于验证)
190- client_signature = get_key_from_hmac(server_key, token_byte)
191-
192- # Step 6: 验证serverSignature (如果提供)
193- if server_signature and server_signature != bytes_to_hex_string(client_signature):
194- return b" "
195-
196- # Step 7: 计算真正的ClientSignature
197- hmac_result = get_key_from_hmac(stored_key, token_byte)
198-
199- # Step 8: XOR操作得到ClientProof
200- h_value = xor_between_password(hmac_result, client_key, len (client_key))
201-
202- # Step 9: 转换为hex bytes格式 (对应Java的 bytesToHex(hValue, result, 0, hValue.length))
203- h_value_len = len (h_value)
204- result = bytearray(h_value_len * 2 )
205- bytes_to_hex(h_value, result, 0 , h_value_len)
206-
207- return bytes(result)
208-
209- except Exception as e:
210- raise ValueError (f" RFC5802Algorithm failed: {e}" )
211-
212-
213-
214-
215-
216-
217-
218-
219-
220-
221- def bytes_to_hex (src_bytes , dst_bytes , offset , length ):
222- """
223- Java: bytesToHex(byte[] src, byte[] dst, int offset, int length)
224- - src: 源字节数组
225- - dst: 目标字节数组
226- - offset: dst写入起始位置
227- - length: 需要转换的src字节数量
228- 写入的输出是十六进制ASCII字节(不是16进制数值),每个字节转换成2个字母。
229- """
230- HEX_DIGITS = b' 0123456789abcdef'
231- for i in range (length):
232- v = src_bytes[i]
233- if isinstance (v, str ):
234- v = ord (v)
235- if v < 0 :
236- v += 256
237- dst_bytes[offset + (i * 2 )] = HEX_DIGITS[v >> 4 ]
238- dst_bytes[offset + (i * 2 ) + 1 ] = HEX_DIGITS[v & 0x0F ]
239-
240- def SHA256_MD5encode (user: bytes , password: bytes , salt: bytes ) -> bytes:
241- try:
242- md = hashlib.md5()
243- md.update(password )
244- md.update(user )
245- temp_digest = md.digest() # 16 bytes
246-
247- # hex_digest 70字节(实际前6和后64有效)
248- hex_digest = bytearray(70 )
249-
250- # 前32个字节为temp_digest的hex(16字节*2)
251- bytes_to_hex(temp_digest , hex_digest , 0, 16)
252-
253- # 取前32字节(hex后缀): hex_digest[0 :32 ], 作为SHA256输入
254- sha = hashlib.sha256()
255- sha.update(hex_digest[0 :32 ])
256- sha.update(salt)
257- pass_digest = sha.digest() # 32 bytes
258-
259- # pass_digest的hex写到hex_digest[6:]
260- bytes_to_hex(pass_digest, hex_digest, 6 , 32 )
261-
262- # 填入ASCII签名'sha256'
263- hex_digest[0 :6 ] = b' sha256'
264-
265- except Exception as e:
266- raise ValueError (' SHA256_MD5encode failed: %s ' % str (e))
267- return bytes(hex_digest)
26825
26926cdef class CoreProtocol:
27027
@@ -282,6 +39,8 @@ cdef class CoreProtocol:
28239 self .encoding = ' utf-8'
28340 # type of `scram` is `SCRAMAuthentcation`
28441 self .scram = None
42+ # type of `sha256` is `RFC5802Authentication`
43+ self .sha256 = None
28544 # type of `gss_ctx` is `gssapi.SecurityContext` or
28645 # `sspilib.SecurityContext`
28746 self .gss_ctx = None
@@ -814,7 +573,6 @@ cdef class CoreProtocol:
814573 bytes token
815574 int32_t server_iteration
816575 status = self .buffer.read_int32()
817-
818576 if status == AUTH_SUCCESSFUL:
819577 # AuthenticationOk
820578 self .result_type = RESULT_OK
@@ -842,15 +600,15 @@ cdef class CoreProtocol:
842600 ' The server requested password-based authentication, '
843601 ' but no password was provided.' )
844602 if password_stored_method in (SHA256_PASSWORD,PLAIN_PASSWORD):
845- # 读取认证参数
603+ # Read authentication parameters
846604 random64code = self .buffer.read_bytes(64 )
847605 token = self .buffer.read_bytes(8 )
848606 server_iteration = self .buffer.read_int32()
849- # 调用_auth_password_message_sha256生成认证消息
607+ # generate authentication message
850608 self .auth_msg = self ._auth_password_message_sha256(random64code, token,
851609 server_iteration)
852610 elif password_stored_method == MD5_PASSWORD:
853- # MD5密码存储方式
611+ # MD5 password storage method
854612 salt = self .buffer.read_bytes(4 )
855613 self .auth_msg = self ._auth_password_message_md5(salt)
856614
@@ -938,19 +696,15 @@ cdef class CoreProtocol:
938696
939697 cdef _auth_password_message_sha256(self , bytes random64code, bytes token,
940698 int32_t server_iteration):
941- """
942- 处理SHA256认证消息
943- """
944699 cdef:
945700 WriteBuffer msg
946701 bytes result
947-
948- # 调用RFC5802算法计算认证结果
949- result = rfc5802_algorithm(
702+ self .sha256 = RFC5802Authentication()
703+ result = self .sha256.authenticate(
950704 self .password,
951705 random64code.decode(' utf-8' ),
952706 token.decode(' utf-8' ),
953- ' ' , # salt为空
707+ ' ' ,
954708 server_iteration,
955709 ' sha256'
956710 )
@@ -959,8 +713,7 @@ cdef class CoreProtocol:
959713 self .result = apg_exc.InterfaceError(
960714 ' Invalid username/password, login denied.' )
961715 return None
962-
963- # 构建认证响应消息
716+
964717 msg = WriteBuffer.new_message(b' p' )
965718 msg.write_bytes(result)
966719 msg.end_message()
0 commit comments