SOUL密钥交换算法

使用了ecdh算法,非标准椭圆曲线参数。

分析过程懒得写了,直接上demo

python 复制代码
import os
import base64
from util.ENCUtils import ENCUtils
from ecdsa.ellipticcurve import Point, CurveFp
 
 
class SoulCustomCurve:
 
    _INSTANCE = None
 
    def __new__(cls, *args, **kwargs):
        if not cls._INSTANCE:
            cls._INSTANCE = super(SoulCustomCurve, cls).__new__(cls, *args, **kwargs)
        return cls._INSTANCE
 
    @staticmethod
    def get_instance():
        if SoulCustomCurve._INSTANCE is None:
            SoulCustomCurve._INSTANCE = SoulCustomCurve()
        return SoulCustomCurve._INSTANCE
 
    def __init__(self):
        # 自定义的椭圆曲线参数
        self.p = 6277101735386680763835789423207666416102355444459739541047  # p 参数
        self.a = 0  # a 参数
        self.b = 3  # b 参数
        self.Gx = 5377521262291226325198505011805525673063229037935769709693  # G 的 x 坐标
        self.Gy = 3805108391982600717572440947423858335415441070543209377693  # G 的 y 坐标
        self.curve = CurveFp(self.p, self.a, self.b)  # 定义椭圆曲线
        self.G = Point(self.curve, self.Gx, self.Gy)  # 定义椭圆曲线上的基点 G
        self.n = 6277101735386680763835789423061264271957123915200845512077  # n 参数
 
        # 创建私钥和公钥
        self.client_private_key = int.from_bytes(os.urandom(24), byteorder='big')  # 使用 os.urandom 生成私钥
        self.client_public_key = self.point_multiply(self.client_private_key, self.G)
 
        self.server_public_key = (5400262085967213433717992037101256438732384858453335109798,
                                  6167642468723156401569091099299085180686314126654549364092)
 
        self.shared_key = None
        self.shared_key_encoded = None
 
    def get_curve(self):
        # 返回椭圆曲线
        return self.curve
 
    def get_base_point(self):
        # 返回基点 G
        return self.G
 
    def get_order(self):
        # 返回阶数
        return self.n
 
    # 倍点运算:计算 k * P
    def point_multiply(self, k, p: Point):
        """点乘 kP = Q (mod p)"""
        R = (0, 0)  # 零点
        Q = (p.x(), p.y())
        while k:
            if k & 1:
                R = self.point_add(R, Q)
            Q = self.point_add(Q, Q)
            k >>= 1
        return R
 
    def point_add(self, P, Q):
        """点加法 P + Q = R (mod p)"""
        if P == (0, 0):  # 零点,返回 Q
            return Q
        if Q == (0, 0):  # 零点,返回 P
            return P
 
        # 如果 P 或 Q 是 Point 对象,则需要使用 P.x 和 P.y 来获取坐标
 
        if P[0] == 0 and P[1] == 0:
            return Q
        if Q[0] == 0 and Q[1] == 0:
            return P
 
        # 计算斜率 λ
        if P != Q:
            m = (Q[1] - P[1]) * pow(Q[0] - P[0], self.curve.p() - 2, self.curve.p()) % self.curve.p()
        else:
            m = (3 * P[0] ** 2 + self.curve.a()) * pow(2 * P[1], self.curve.p() - 2, self.curve.p()) % self.curve.p()
 
        # 计算新的 x 和 y 坐标
        x_r = (m ** 2 - P[0] - Q[0]) % self.curve.p()
        y_r = (m * (P[0] - x_r) - P[1]) % self.curve.p()
 
        return x_r, y_r
 
    def get_client_public_key(self):
        return b"\x04" + \
               self.client_public_key[0].to_bytes(24, byteorder="big") + \
               self.client_public_key[1].to_bytes(24, byteorder="big")
        # return bytes.fromhex("04cf6b0577c58d70bac18ca92f435620f42712ba76a1ba5dc2552c9df82aff1a0f5a12e3fa08c03c4e5e79032b83fb613f")
 
    def get_server_public_key(self):
        return b"\x04" + \
               self.server_public_key[0].to_bytes(24, byteorder="big") + \
               self.server_public_key[1].to_bytes(24, byteorder="big")
 
    def get_client_private_key(self):
        return self.client_private_key.to_bytes(24, byteorder="big")
 
    def get_shared_key(self):
        if self.shared_key is None:
            pub_key = self.server_public_key
            pub_key_point = Point(self.get_curve(), pub_key[0], pub_key[1])
            shared_key_tuple = self.client_private_key * pub_key_point
            shared_key: int = shared_key_tuple.x()
            self.shared_key = shared_key.to_bytes(24, byteorder="big")
        return self.shared_key
 
    def get_shared_key_encoded(self):
        if self.shared_key_encoded is None:
            shared_key = self.get_shared_key()
            shared_key_base64: str = base64.b64encode(shared_key[0:16]).decode("utf-8")
            salt = ENCUtils.md5("w[" + shared_key_base64[0:4] + "t}")
            self.shared_key_encoded = salt[-2:] + shared_key_base64 + salt[0:2]
        key = self.shared_key_encoded.encode("utf-8")
        if len(key) < 16:
            key = key + ("\x00" * (16 - len(key)))
        return key
        # return bytes.fromhex("343179723633667448627543777366535a34324c4e7635513d3d3664").decode("utf-8")
 
 
class ExchangeKeyUtil:
 
    _COMMON_AES_KEY = b"V0hRuZT+zZmj\x00\x00\x00\x00"
 
    @staticmethod
    def get_shared_key():
        return SoulCustomCurve.get_instance().get_shared_key_encoded()
 
    @staticmethod
    def encrypted_pub_key():
        client_pub_key = SoulCustomCurve.get_instance().get_client_public_key()
        return ExchangeKeyUtil._encrypt(client_pub_key, ExchangeKeyUtil._COMMON_AES_KEY)
 
    @staticmethod
    def encrypt_data(d):
        key = SoulCustomCurve.get_instance().get_shared_key_encoded()
        return ExchangeKeyUtil._encrypt(d, key)
 
    @staticmethod
    def decrypt_data(d):
        key = SoulCustomCurve.get_instance().get_shared_key_encoded()
        return ExchangeKeyUtil._decrypt(d, key)
 
    @staticmethod
    def _decrypt(d, aes_key):
        not_use = d[0:2]
        random = d[2:6]
        zero = d[6:7]
        raw_encrypted = d[7:]
        iv = ENCUtils.sha1(random)[0:16]
        decrypted = ENCUtils.aes_decrypt(raw_encrypted, aes_key[0:16], iv)
        return decrypted
 
    @staticmethod
    def _encrypt(d, aes_key):
        # key = SoulCustomCurve.get_instance().get_shared_key_encoded()
        random = os.urandom(4)
        iv = ENCUtils.sha1(random)[0:16]
        pad_len = 16 - (len(d) & 0xF)
        final_data = d + (pad_len * pad_len.to_bytes(1, byteorder="big"))
        encrypted = ENCUtils.aes_encrypt_no_padding(final_data, aes_key[0:16], iv)
        return bytes.fromhex("0203") + random + b"\x00" + encrypted
 
 
if __name__ == "__main__":
    # 使用自定义曲线
    custom_curve = SoulCustomCurve.get_instance()
    print(custom_curve.get_shared_key_encoded())
    print(ExchangeKeyUtil.encrypted_pub_key().hex())
相关推荐
SomeB1oody23 分钟前
【Rust自学】3.5. 控制流:if else
开发语言·后端·rust
TenniCC1 小时前
python 中使用pip操作flask离线下载(包含依赖包下载)和安装
python·flask·pip
宸码1 小时前
【机器学习】【集成学习——决策树、随机森林】从零起步:掌握决策树、随机森林与GBDT的机器学习之旅
人工智能·python·算法·决策树·随机森林·机器学习·集成学习
Mobius80862 小时前
探索 Seaborn Palette 的奥秘:为数据可视化增色添彩
图像处理·python·信息可视化·数据分析·pandas·matplotlib·数据可视化
星霜旅人2 小时前
【Python】pandas库---数据分析
python
Q之路2 小时前
C++之多态
开发语言·c++
小陈phd2 小时前
深度学习之目标检测——RCNN
python·深度学习·算法·计算机视觉
好奇的菜鸟3 小时前
Rust操作符和符号全解析
开发语言·后端·rust
从以前3 小时前
Python 爱心代码实现动态爱心图案展示
python