门限密码

在网上看到一篇讲门限密码的blog,讲挺好的,但个人感觉有一些细节部分缺失,自己再补充一些。
链接
(如何有条件的话,动手画个图会帮助自己理清思路。)

背景

大家都看过谍战片,传递消息的时候为了防止线人叛变,往往会将消息切分成多部分进行传递,即使有个别内鬼,也无法解析出消息的含义。当然,这样的坏处也是显而易见的,如果内鬼叛变,自己人也无法或者消息的内容。

基于此,门限密码也应运而生了,其目的在于保证只有收到m个消息及以上接收方才能正确的计算出消息。
换句话说,老大发出n个消息,只有m个以上特工叛变,敌方才能得到的秘密;同理,只要有m个以上的特工顺利到达,消息就能够被顺利的解析。
这样的问题就被称做(m,n)门限。

解决方案

有了这个idea,如何实现它呢?
首先,我们有n个特工,门限为m,则存在如下约束:

  • 约束1:只要收到m个以上的消息就能解析出加密数据。
  • 约束2:收到不足m个消息则不能解析出加密数据。

那么,我们有以下几个待求解问题:

  • 一个完整的数据应该切成几片?
  • 每个数据片应该分给几个特工?

从简单的开始,假定所有特工携带相同数目的数据块且不能有两个不同的数据分块由相同的特工们投递。
根据约束1,每个数据片只需要放在n-m+1个特工上即可实现。
(此时有m-1个特工没有数据片,此时无论m怎么取,总能获得一个带有数据片的特工。

满足了约束1、下一步我们将尝试用上述规则满足约束2。
对于n个特工,n-m+1个碎片,总共有C(n-m+1,n)种分配方法。
我们暂时假定,分配方法的数量就表示着完整数据的切片数量。

  • 首先证明C(n-m+1,n)符合约束2:
    因为C(n-m+1,n)覆盖了所有的排列组合方式,所以对于m-1及以下,总存在一个秘钥分片是m-1个特工所没有的。(例如存在分块k,其分配方式是第m号特工携带,1~m-1不携带,此时不违反约束1.
    故约束2满足。
  • 随后证明数据块数目不能大于C(n-m+1,n):
    很显然,如果切片数量大于C(n-m+1,n),则系统必会出现两个不同的数据块,以同样的方式被n个特工携带,失去了数据分片的意义。
    以下图门限(5,3)为例子,倘若数据块数量大于20时必然存在数据块的分配方式与之前20块相同。
    (如图所示,第21块数据块的携带方式与第1块相同)
    携带数据块
特工
	1  2  3       21
1   1  1  1        1
2   1  1  0        1
3   1  0  1        1
4   0  1  1        0
5   0  0  0.....   0
  • 最后,尝试证明不能小于C(n-m+1,n):
    缺少的那个数据分片B的携带方式将成为一个bug。假设B规定1~m-1号特工不携带数据,则选取1到m-1这m-1个特工即可覆盖所有的数据块。与约束二矛盾。
    (道理也不复杂,因为只有B这个数据块是m-1个特工都不具有的。
    (约束1规定某一个数据块最多只有m-1个特工不携带。

至此,我们就完美解决了(m,n)门限的问题了.做法是只需要把密钥分成C(m-1,n)份,每份拥有n-m+1份拷贝。

实现

有了以上基础,下一步的问题就是如何切分秘钥呢?

空间几何

这是一个十分美的解决办法.还是先从个上面的(3,5)门限的例子来说把,只要把密钥编码成空间中的一个点,每个特工手上拿着一个平面方程.所有特工所持有的平面方程全部都交于一个点.因为只有三个或以上的平面才能交于一个点,所以,只要有三个特工到达,拿出他们手里的平面方程一解,答案就是密钥.用这种解决办法,对于(m,n)门限,只要把空间的维数相应的改变成m就可以了。

中国剩余定理

todo

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
门限密码是指将一个秘密分成多个部分,只有当这些部分汇聚在一起时,才能重构出原来的秘密。在密码学中,门限密码被广泛应用于多方安全计算,数据解密和认证等领域。下面我们将简要介绍如何使用Python来实现门限密码。 首先,我们需要安装必要的库。可以使用pip命令安装pycryptodome,它提供了实现门限密码所需的密钥生成和数据加密等函数。 ``` pip3 install pycryptodome ``` 之后,我们要设置门限,假设我们需要将秘密分成5份,每份至少需要3份才能还原出秘密。我们可以使用Shamir的门限密码方案来生成密钥,Shamir方案的实现可以使用pycryptodome库中的函数。 ```python from Crypto.Util.number import getRandomInteger, GCD, inverse from Crypto.Util import number # 参数k表示有k个份秘密,n表示至少需要n份秘密才能还原原始秘密 def generate_shamir_key(k, n): p = number.getPrime(512) a = getRandomInteger(512) b = getRandomInteger(512) % p # 检查p,b是否互质,如果不是,重新生成随机数 while GCD(a, p) != 1 or GCD(b, p) != 1: p = number.getPrime(512) a = getRandomInteger(512) b = getRandomInteger(512) % p shares = [] for i in range(1, k + 1): x = i y = (a * x + b) % p shares.append((x, y)) return shares ``` 在生成密钥的过程中,我们首先生成一个512位的素数p,随机选择两个512位的整数a和b。然后检查a和p,b和p是否互质,确保生成的密钥是安全的。最后我们用x在1到k之间的数值求出对应的y值,并将x和y保存在一个元组中加入密钥列表中。 当我们需要还原秘密时,可以使用Lagrange插值法计算密钥: ```python from collections import Iterable # 参数shares是一个元组列表,表示秘密分成了多少份,以及每份的x和y值 # 参数x是需要还原秘密的x值 def lagrange_interpolation(shares, x): def product(nums): # 计算序列中所有元素的乘积 p = 1 for num in nums: p *= num return p # 检查shares是否为一个可迭代的序列 if isinstance(shares, Iterable): sss = 0 for j, share_j in enumerate(shares): x_j, y_j = share_j p = [(x - x_j) / (j - x_j) for j, share_j in enumerate(shares) if x_j != j] # p 的极限为 -x / j,分母为0时,不做计算 sss += (y_j * product(p)) sss % p[0] return sss ``` Lagrange插值法的实现较为简单,我们首先检查输入的shares参数是否为可迭代序列,然后依次根据每个元组计算Lagrange插值多项式的乘积,最后得出密钥。 使用门限密码对数据进行加密时,我们首先将原始数据切分成n份,并将每份数据分别使用不同的密钥进行加密。当需要解密时,至少需要收集到n份密文才能还原出原始数据。 ```python from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA def encrypt_data(data, keys): encrypted_data = [] for i in range(len(keys)): key = keys[i] message = data[i].to_bytes(16, byteorder="big") rsa_key = RSA.construct(key) cipher = PKCS1_OAEP.new(rsa_key) encrypted_data.append(cipher.encrypt(message)) return encrypted_data def decrypt_data(data, keys): decrypted_data = [] for i in range(len(keys)): key = keys[i] rsa_key = RSA.construct(key) cipher = PKCS1_OAEP.new(rsa_key) decrypted_data.append(int.from_bytes(cipher.decrypt(data[i]), byteorder="big")) return decrypted_data ``` 在进行加密时,我们首先将原始数据分成n份,并对每份数据使用一个不同的密钥进行加密。在进行解密时,我们需要指定解密的密钥,将收到的密文使用相应的密钥进行解密,并将解密后的数据保存在一个列表中。 综上所述,我们可以使用Python编写一个完整的门限密码程序。该程序首先生成密钥,然后将原始数据进行切分并使用不同的密钥进行加密。当需要解密数据时,至少收集到n份密文即可还原出原始数据。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值