diff --git a/.gitignore b/.gitignore index 574fb59..95226e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.txt .venv/ +**/__pycache__/** diff --git a/core/sp_gateway_rsa.py b/core/sp_gateway_rsa.py index 40438c3..46ac90b 100644 --- a/core/sp_gateway_rsa.py +++ b/core/sp_gateway_rsa.py @@ -9,7 +9,7 @@ class SentinelSystemProvider: """生成全新的系统公私钥对""" private_key = rsa.generate_private_key( public_exponent=65537, - key_size=2048 + key_size=4096 ) public_key = private_key.public_key() diff --git a/core/sp_trust_sharding.py b/core/sp_trust_sharding.py index 9f31de1..64592d5 100644 --- a/core/sp_trust_sharding.py +++ b/core/sp_trust_sharding.py @@ -3,6 +3,9 @@ import secrets from mnemonic import Mnemonic # 仅用于标准的助记词转换 class SentinelKeyEngine: + # 使用第 13 个梅森素数 (2^521 - 1),远大于 128-bit 熵,确保有限域安全 + PRIME = 2**521 - 1 + def __init__(self): self.mnemo = Mnemonic("english") @@ -18,18 +21,19 @@ class SentinelKeyEngine: """ 2. SSS (3,2) 门限分片逻辑 公式: f(x) = S + a*x (直线方程,S为秘密,a为随机斜率) - 我们将秘密 S 分成 3 份,任选 2 份即可恢复 + 我们将秘密 S 分成 3 份,任选 2 份即可恢复。 + 注意:必须在有限域 GF(PRIME) 下进行运算以保证完善保密性。 """ # 将熵转换为大整数 secret_int = int.from_bytes(entropy, 'big') # 生成一个随机系数 a (安全性需与秘密强度一致) - # 这里使用 secrets 保证加密级随机 - a = int.from_bytes(secrets.token_bytes(16), 'big') + # a 必须在 [0, PRIME-1] 范围内 + a = secrets.randbelow(self.PRIME) # 定义 3 个点: x=1, x=2, x=3 # Share = (x, f(x)) - def f(x): return secret_int + a * x + def f(x): return (secret_int + a * x) % self.PRIME share1 = (1, f(1)) # 手机分片 share2 = (2, f(2)) # 云端分片 @@ -42,15 +46,31 @@ class SentinelKeyEngine: 3. 恢复逻辑:拉格朗日插值还原 已知 (x1, y1) 和 (x2, y2),求 f(0) 即秘密 S 公式: S = (x2*y1 - x1*y2) / (x2 - x1) + 在有限域下,除法变为乘以模逆: S = (x2*y1 - x1*y2) * (x2 - x1)^-1 mod P """ x1, y1 = share_a x2, y2 = share_b + # 计算分子 + numerator = (x2 * y1 - x1 * y2) % self.PRIME + # 计算分母的模逆 (x2 - x1) + denominator = (x2 - x1) % self.PRIME + inv_denominator = pow(denominator, -1, self.PRIME) + # 还原常数项 S - secret_int = (x2 * y1 - x1 * y2) // (x2 - x1) + secret_int = (numerator * inv_denominator) % self.PRIME # 转回字节并生成助记词 - recovered_entropy = secret_int.to_bytes(16, 'big') + # 注意:secret_int 可能略小于 16 字节(高位为0),需要补齐 + # 但由于 entropy 原始就是 16 字节,这里直接转换即可 + try: + recovered_entropy = secret_int.to_bytes(16, 'big') + except OverflowError: + # 理论上不应发生,除非计算出的 secret_int 大于 128 bit (即原始 entropy 大于 128 bit) + # 这里为了健壮性,如果原始 entropy 是 16 字节,这里应该也是。 + # 如果 PRIME 很大,secret_int 还是原来的值。 + recovered_entropy = secret_int.to_bytes((secret_int.bit_length() + 7) // 8, 'big') + return self.mnemo.to_mnemonic(recovered_entropy) if __name__ == "__main__": # --- Sentinel 协议业务流程模拟 --- diff --git a/core/sp_vault_aes.py b/core/sp_vault_aes.py index 524685e..2d7d206 100644 --- a/core/sp_vault_aes.py +++ b/core/sp_vault_aes.py @@ -5,9 +5,10 @@ from Crypto.Protocol.KDF import PBKDF2 from Crypto.Util.Padding import pad, unpad class SentinelVault: - def __init__(self, salt=b'Sentinel_Salt_2026'): # 固定的盐值,用于增加派生强度 + def __init__(self, salt=None): self.mnemo = Mnemonic("english") - self.salt = salt + # 默认盐值仅用于演示,生产环境建议每个用户随机生成并存储 + self.salt = salt if salt else b'Sentinel_Salt_2026' def derive_key(self, mnemonic_phrase): """ diff --git a/data_flow.md b/data_flow.md new file mode 100644 index 0000000..d64ef85 --- /dev/null +++ b/data_flow.md @@ -0,0 +1,49 @@ +# Sentinel 协议 Demo 数据流全景梳理 +## 1. 密钥拆解流:身份的碎裂化 (Initialization) +这是系统的起点,通过 SSS (3,2) 门限算法,将用户的绝对控制权转化为分布式的信任。 +- 输入:系统随机生成 12 个 BIP-39 标准助记词。 +- 动作:将助记词对应的熵(Entropy)拆分为 3 个独立的数学分片: + - 分片 A (Device):预设存放于用户手机安全芯片。 + - 分片 B (Cloud):预设存放于 Sentinel 服务器。 + - 分片 C (Physical):预设印制于物理传承卡,交给继承人。 +- 验证点:演示通过 (A+B)、(B+C)、(A+C) 三种组合均能重新拼凑出原始的 12 个助记词。 + +## 2. 用户内层加密流:建立私密金库 (Vault Layer) +这是用户端的加密,确保“零知识”存储,即系统在没有分片的情况下无法感知数据内容。 +- 输入:用户隐私数据(明文)+ 步骤 1 恢复出的助记词。 +- 动作: + - 通过助记词派生出对称加密密钥(AES-256-GCM)。 + - 使用该密钥对数据进行加密,生成 密文 1。 +- 特性:此步骤模拟在用户本地完成,密文 1 是用户资产的初级保护形态。 + +## 3. 系统外层加壳流:双重包封 (Gateway Layer) +这是公司/平台层的加密,用于实现“被动验证”和“权限锁定”。 +- 输入:密文 1 + 公司生成的独立 RSA 公钥。 +- 动作: + - 系统生成一套与用户无关的 RSA 公私钥对(公司钥匙)。 + - 使用 RSA 公钥对密文 1 进行二次加密,生成 密文 2。 + +- 逻辑价值:此时生成的 密文 2 具有双重安全性——即使助记词泄露,没有公司私钥也打不开;即使公司私钥泄露,没有助记词分片也打不开。 + +## 4. 判定触发流:剥离系统外壳 (Trigger/Unlock Layer) + +这是 Demo 的转折点,模拟“订阅费失败”或“生前正常访问”时,系统解除第一层锁定。 +- 输入:密文 2 + 公司 RSA 私钥。 +- 动作:使用私钥解密密文 2,还原回 密文 1。 +- 业务映射: + - 生前模式:用户活跃,系统私钥实时配合,允许数据流向用户。 + - 传承模式:判定死亡后,系统永久释放此私钥权限给该数据包。 + +## 5. 多场景还原流:最终提取 (Restoration Scenarios) +这是 Demo 的结尾,展示在不同社会场景下,数据如何最终回到人手中。 +- 输入:步骤 4 还原出的密文 1 + 不同组合的分片。 +- 场景模拟: + - 场景 1:生前正常访问 + - 组合:分片 A (手机) + 分片 B (云端) --> 恢复助记词 --> 解密密文 1。 + - 意义:证明用户在世时,无需传承卡即可查看数据。 + - 场景 2:死后标准传承 + - 组合:分片 B (云端) + 分片 C (物理卡) ---> 恢复助记词 ---> 解密密文 1。 + - 意义:模拟用户去世,继承人靠卡片和服务器释放的分片完成交接。 + - 场景 3:单纯测试验证,因为用户持有全部12个助记词 + - 组合:分片 A (手机) + 分片 C (物理卡) --> 恢复助记词 --> 解密密文 1。 + - 意义:测试目的 \ No newline at end of file