deadblue / elevengo

An API client of 115 Cloud Storage Service in Go.
MIT License
86 stars 26 forks source link

請問大佬是否會python 我已經把加密部分完成一些了 只差在POST 發送的問題 #23

Closed ww9592447 closed 1 year ago

ww9592447 commented 1 year ago

如標題 我已完成 你代碼中的 c.ecc.Encode(data) 可是在POST的時候發現問題了 我發送出去的數據跟你的數據有點差距 弄了很多種方式都不行 headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0; Windows NT/10.0.19045; 115Desktop/2.0.3.6', 'cookie': '', } requests.post(url, data=client.Encode(data), headers=headers) 我發送的時候大概是這樣的發送 想請問大老是否能夠幫我看看問題出在哪.....

deadblue commented 1 year ago

如標題 我已完成 你代碼中的 c.ecc.Encode(data) 可是在POST的時候發現問題了 我發送出去的數據跟你的數據有點差距 弄了很多種方式都不行 headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0; Windows NT/10.0.19045; 115Desktop/2.0.3.6', 'cookie': '', } requests.post(url, data=client.Encode(data), headers=headers) 我發送的時候大概是這樣的發送 想請問大老是否能夠幫我看看問題出在哪.....

POST 的时候,除了加密数据,还要在 URL 里面拼上一个 k_ec 参数,参数值来自ecc.EncodeToken。

我验证加密算法的时候就用的 Python ,以下是代码片段,供你参考:

    def upload_file_v4(self, file_path:str, target_dir_id:str):
        file_id = _hash.sha1_file(file_path)
        file_size = os.path.getsize(file_path)
        target_id = 'U_1_%s' % target_dir_id
        # Form data to POST
        data = {
            'appid': '0',
            'appversion': _app_version,
            'filename': os.path.basename(file_path),
            'filesize': file_size,
            'fileid': file_id,
            'target': target_id,
            'userid': self._user_id,
            'sig': self._calculate_sig_v4(file_id, target_id)
        }
        sign_key, sign_val = '', ''
        while True:
            now = int(time.time())
            data.update({
                't': str(now),
                'token': self._calculate_token_v4(
                    now, file_id, file_size, sign_key, sign_val
                )
            })
            if sign_key != '' and sign_val != '':
                data.update({
                    'sign_key': sign_key,
                    'sign_val': sign_val
                })
            resp = self._session.post(
                url=_api_upload, 
                params={
                    'k_ec': self._ecc.encode_token(now)
                },
                data=self._ecc.encode(
                    urllib.parse.urlencode(data).encode()
                ),
                headers={
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            )
            result = self._ecc.decode(resp.content)
            _logger.debug('Result: %s', result)
            result = json.loads(result)
            if result['status'] == 7:
                sign_key = result['sign_key']
                sign_val = _hash.sha1_file_range(file_path, result['sign_check'])
            else:
                break
ww9592447 commented 1 year ago

如標題我已經完成你代碼中的c.ecc.Encode(data)可是在POST的時候出現問題了我發送出去的數據和你的數據有一點偏差搞了很多類型不同的header-s ': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0; Windows NT/10.0.19045;115Desktop/2.0.3.6', 'cookie': '', } requests.post(url, data=client.Encode(data), headers=headers) 我發送的時候大概念是這樣的發送想請問大老是能不能幫我看問題出在哪.....

POST的時候,除了加了密碼,還要在URL裡面拼上一個k_ec參數,參數值來自ecc.EncodeToken。

我在驗證加密算法的時候就用的Python,以下是代碼片段,供你參考:

    def upload_file_v4(self, file_path:str, target_dir_id:str):
        file_id = _hash.sha1_file(file_path)
        file_size = os.path.getsize(file_path)
        target_id = 'U_1_%s' % target_dir_id
        # Form data to POST
        data = {
            'appid': '0',
            'appversion': _app_version,
            'filename': os.path.basename(file_path),
            'filesize': file_size,
            'fileid': file_id,
            'target': target_id,
            'userid': self._user_id,
            'sig': self._calculate_sig_v4(file_id, target_id)
        }
        sign_key, sign_val = '', ''
        while True:
            now = int(time.time())
            data.update({
                't': str(now),
                'token': self._calculate_token_v4(
                    now, file_id, file_size, sign_key, sign_val
                )
            })
            if sign_key != '' and sign_val != '':
                data.update({
                    'sign_key': sign_key,
                    'sign_val': sign_val
                })
            resp = self._session.post(
                url=_api_upload, 
                params={
                    'k_ec': self._ecc.encode_token(now)
                },
                data=self._ecc.encode(
                    urllib.parse.urlencode(data).encode()
                ),
                headers={
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            )
            result = self._ecc.decode(resp.content)
            _logger.debug('Result: %s', result)
            result = json.loads(result)
            if result['status'] == 7:
                sign_key = result['sign_key']
                sign_val = _hash.sha1_file_range(file_path, result['sign_check'])
            else:
                break

不好意思大佬 我試了一下還是不行 可能是我加密有問題 還有一個小問題 我已經獲取了 伺服器key serverx servery 了 可是不清楚如何交換金鑰 我之前是直接把你的代碼生成exe調用獲取裡面key 進行加密 能否跟我講下你是否如何交換金鑰的嗎? 我寫了我的代碼 能跟我講下問題出在哪嗎? https://github.com/ww9592447/115-/blob/main/115.py

deadblue commented 1 year ago

如標題我已經完成你代碼中的c.ecc.Encode(data)可是在POST的時候出現問題了我發送出去的數據和你的數據有一點偏差搞了很多類型不同的header-s ': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0; Windows NT/10.0.19045;115Desktop/2.0.3.6', 'cookie': '', } requests.post(url, data=client.Encode(data), headers=headers) 我發送的時候大概念是這樣的發送想請問大老是能不能幫我看問題出在哪.....

POST的時候,除了加了密碼,還要在URL裡面拼上一個k_ec參數,參數值來自ecc.EncodeToken。 我在驗證加密算法的時候就用的Python,以下是代碼片段,供你參考:

    def upload_file_v4(self, file_path:str, target_dir_id:str):
        file_id = _hash.sha1_file(file_path)
        file_size = os.path.getsize(file_path)
        target_id = 'U_1_%s' % target_dir_id
        # Form data to POST
        data = {
            'appid': '0',
            'appversion': _app_version,
            'filename': os.path.basename(file_path),
            'filesize': file_size,
            'fileid': file_id,
            'target': target_id,
            'userid': self._user_id,
            'sig': self._calculate_sig_v4(file_id, target_id)
        }
        sign_key, sign_val = '', ''
        while True:
            now = int(time.time())
            data.update({
                't': str(now),
                'token': self._calculate_token_v4(
                    now, file_id, file_size, sign_key, sign_val
                )
            })
            if sign_key != '' and sign_val != '':
                data.update({
                    'sign_key': sign_key,
                    'sign_val': sign_val
                })
            resp = self._session.post(
                url=_api_upload, 
                params={
                    'k_ec': self._ecc.encode_token(now)
                },
                data=self._ecc.encode(
                    urllib.parse.urlencode(data).encode()
                ),
                headers={
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            )
            result = self._ecc.decode(resp.content)
            _logger.debug('Result: %s', result)
            result = json.loads(result)
            if result['status'] == 7:
                sign_key = result['sign_key']
                sign_val = _hash.sha1_file_range(file_path, result['sign_check'])
            else:
                break

不好意思大佬 我試了一下還是不行 可能是我加密有問題 還有一個小問題 我已經獲取了 伺服器key serverx servery 了 可是不清楚如何交換金鑰 我之前是直接把你的代碼生成exe調用獲取裡面key 進行加密 能否跟我講下你是否如何交換金鑰的嗎? 我寫了我的代碼 能跟我講下問題出在哪嗎? https://github.com/ww9592447/115-/blob/main/115.py

以下是我实现的 EC Cipher,需要引入3个第三方库:

__author__ = 'deadblue'

import binascii
import logging
import random
import struct

from Crypto.Cipher import AES
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
import lz4.block

_server_pub_key = bytes([
    0x04, 0x57, 0xa2, 0x92, 0x57, 0xcd, 0x23, 0x20, 
    0xe5, 0xd6, 0xd1, 0x43, 0x32, 0x2f, 0xa4, 0xbb, 
    0x8a, 0x3c, 0xf9, 0xd3, 0xcc, 0x62, 0x3e, 0xf5, 
    0xed, 0xac, 0x62, 0xb7, 0x67, 0x8a, 0x89, 0xc9, 
    0x1a, 0x83, 0xba, 0x80, 0x0d, 0x61, 0x29, 0xf5, 
    0x22, 0xd0, 0x34, 0xc8, 0x95, 0xdd, 0x24, 0x65, 
    0x24, 0x3a, 0xdd, 0xc2, 0x50, 0x95, 0x3b, 0xee, 
    0xba,
])

_crc_salt = b'^j>WD3Kr?J2gLFjD4W2y@'

_logger = logging.getLogger(__name__)

class Cipher:

    _pub_key: bytes = None
    _aes_key: bytes = None
    _aes_iv: bytes = None

    def __init__(self) -> None:
        # Use P-224 curve
        curve = ec.SECP224R1()
        # Parse server key
        server_key = ec.EllipticCurvePublicKey.from_encoded_point(
            curve=curve, data=_server_pub_key)
        # Generate client key
        ec_key = ec.generate_private_key(
            curve=curve, backend=default_backend())
        self._pub_key = b'\x1d' + ec_key.public_key().public_bytes(
            encoding=Encoding.X962, format=PublicFormat.CompressedPoint)
        # ECDH key exchange
        shared_secret = ec_key.exchange(ec.ECDH(), server_key)
        self._aes_key = shared_secret[:16]
        self._aes_iv = shared_secret[-16:]

    def encode_token(self, timestamp: int) -> str:
        token = bytearray(struct.pack(
            '<15sBII15sBI',
            self._pub_key[:15], 0, 115, timestamp,
            self._pub_key[15:], 0, 1
        ))
        r1, r2 = random.randint(0, 0xff), random.randint(0, 0xff)
        for i in range(len(token)):
            if i < 24:
                token[i] = token[i] ^ r1
            else:
                token[i] = token[i] ^ r2
        # Calculate and append CRC32 checksum
        checksum = binascii.crc32(_crc_salt + token) & 0xffffffff
        token += struct.pack('<I', checksum)
        # Base64 encode
        return binascii.b2a_base64(token, newline=False).decode()

    def encode(self, data) -> bytes:
        pad_size = AES.block_size - len(data) % AES.block_size
        if pad_size != AES.block_size:
            data += bytes([0] * pad_size)
        encrypter = AES.new(
            key=self._aes_key,
            mode=AES.MODE_CBC,
            iv=self._aes_iv
        )
        return encrypter.encrypt(data)

    def decode(self, data:bytes) -> bytes:
        ciphertext, tail = data[:-12], bytearray(data[-12:])
        # Decrypt
        decrypter = AES.new(
            key = self._aes_key, 
            mode = AES.MODE_CBC, 
            iv = self._aes_iv
        )
        plaintext = decrypter.decrypt(ciphertext)
        # Decompress
        for i in range(4):
            tail[i] = tail[i] ^ tail[7]
        dst_size, = struct.unpack('<I', tail[:4])
        _logger.debug('Uncompress size: %d', dst_size)
        src_size, = struct.unpack('<H', plaintext[:2])
        plaintext = lz4.block.decompress(plaintext[2:src_size+2], dst_size)
        return plaintext
user1121114685 commented 1 year ago

大佬还会Python。牛

ww9592447 commented 1 year ago

感謝大佬的指點 我根據你的代碼測試了一下 果然是在加密data的地方出現了問題 沒想到我當時抄網路上的cbc加密代碼 抄錯了 多抄了一句代碼
因為返回值差不多 沒檢查仔細 結果數據後面竟然多了一些數據 再次感謝大佬的代碼