背包密码 + python代码

背包密码加密原理

明文001101
公钥5812182336

密文:12 + 18 + 36 = 66

密钥的产生
私钥的产生

(1)以超递增序列构建背包 eg. {2, 8, 18, 33, 65, 144}

(2)选定 m ,n,满足 m 大于递增背包所有元素之和,且 m 与n 互素。

公钥的产生

背包密码的公钥由私钥产生。

私钥: { a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3, a 4 a_4 a4, a 5 a_5 a5, a 6 a_6 a6}, m m m, n n n .
d n = a n ⋅ n   m o d   m d_n = a_n\cdot n\ mod\ m dn=ann mod m
公钥: { d 1 d_1 d1, d 2 d_2 d2, d 3 d_3 d3, d 4 d_4 d4, d 5 d_5 d5, d 6 d_6 d6}

加密过程

(1) 将明文按照公钥序列的长度分组

(2)将序列位置对应为 1 的元素依次取出并求和,每一组皆如此

(3)得到密文c

解密过程

(1)先求出 n 在模 m 下的逆元 n − 1 n^{-1} n1 n − 1 ⋅ n   m o d   m = 1 n^{-1}\cdot n\ mod\ m = 1 n1n mod m=1

(2)求 c ⋅ n − 1   m o d   m c\cdot n^{-1}\ mod\ m cn1 mod m

(3)根据递增背包的性质,则很容易求出二进制明文

代码部分:

判断互质
def judgeCoPrime(a, b):
    # 求最大公因数
    def maxCommonFactor(m, n):
        result = 0
        while  m % n > 0:
            result = m % n
            m = n
            n = result
        return result
    if maxCommonFactor(a, b) == 1:
        return True
    return False
求逆元
def getInverse(a, b):
    # 扩展的欧几里得算法
    def extGcd(a_, b_, arr):
        if b_ == 0:
            arr[0] = 1
            arr[1] = 0
            return a_
        g = extGcd(b_, a_ % b_, arr)
        t = arr[0]
        arr[0] = arr[1]
        arr[1] = t - int(a_ / b_) * arr[1]
        return g
    # 求a模b的乘法逆x
    arr = [0,1,]
    gcd = extGcd(a, b, arr)
    if gcd == 1:
        return (arr[0] % b + b) % b
    else:
        return -1
初始化
# 初始化
def init(length, interval):
    listV = []  # 超递增向量
    listV_b = []  # 每个元素对应的乘数
    bagCapacity = 1000  # 背包容积
    # 初始化超递增向量与listV_b
    for i in range(length):
        listV.append(sum(listV) + random.randrange(1, interval))
        listV_b.append(0)
    # 求超递增背包的解
    bagCapacityTmp = bagCapacity
    for i in range(len(listV)-1, -1, -1):
        if bagCapacityTmp >= listV[i]:
            bagCapacityTmp -= listV[i]
            listV_b[i] = 1  # listV_b 表示每个元素是否被选入背包
    return listV  # listV是超递增向量
生成密钥函数
def creatPKey(listV):
    # listV = init()
    while True:
        k = int(input("输入私钥k(大于%d):" % (sum(listV))))
        if k <= sum(listV):
            print("输入的k值不合法,请重新设置")
            continue
        while True:
            t = int(input("输入私钥t(与k互素):"))
            if not judgeCoPrime(k, t):
                print("输入的t与k值不互素,请重新输入")
                continue
            break
        break
    inverse_t = getInverse(t, k)
    return k, t, inverse_t

# 产生公钥:
def creatSKey(listV, t, k):
    sKeyList = []  # 公钥序列
    for i in listV:
        sKeyList.append(i * t % k)
    return sKeyList
加密函数
# 加密
def encrypt(massage, sKeyList):
    massageList = []    # 明文分组后的列表
    ciphertextList = []  # 存储密文的列表
    # 扩充明文消息串
    while len(massage) % len(sKeyList) != 0:
        massage = "0" + massage
    # 对明文进行分组
    for i in range(int(len(massage) / len(sKeyList))):
        start = (i * len(sKeyList))
        end = ((i + 1) * len(sKeyList))
        massageList.append(massage[start : end])
    # 采用内积和的方法加密
    for i in massageList:
        # 此处使用lambda时,要注意类型转换
        multiplyList = list(map(lambda x, y: int(x) * int(y), list(i), sKeyList))
        ciphertextList.append(sum(multiplyList))
    return ciphertextList

解密函数
# 解密
def decrypt(massage, sKeyList, k, inverse_t):
    pliantextList = []  # 存储明文的列表
    reductListV = []  # 还原后的初始超递增向量
    # 还原超递增向量
    for i in sKeyList:
        reductListV.append(int(i) * inverse_t % k)
    # 计算出用于解密的临时背包容积
    bagCapacityList = []
    for i in massage:
        bagCapacityList.append(int(i) * inverse_t % k)
    # 利用求出的临时背包容积求解背包问题,结果即明文
    for bagCap in bagCapacityList:
        pliantextTmp = []   # 存储密文列表中每个密文解密后的序列
        for i in range(len(reductListV)):
            pliantextTmp.append(0)
        for i in range(len(reductListV) - 1, -1, -1):
            if bagCap >= reductListV[i]:
                bagCap -= reductListV[i]
                pliantextTmp[i] = 1
        pliantextList += pliantextTmp
    # 去除扩充的0并转换为字符串
    start, end = 0, 0
    for i in range(len(pliantextList)):
        if pliantextList[i] != 0:
            break
        end = i + 1
    del pliantextList[start : end]
    pliantextList = map(str, pliantextList)
    pliantext = "".join(pliantextList)
    return pliantext
    
实验测试
if __name__ == "__main__":
    # listV = [1, 3, 7, 13, 26, 65, 119, 267]
    length = int(input("输入超递增向量元素个数:"))
    interval = int(input("输入随机增量:"))
    # length, interval = 8, 4
    listV = init(length, interval)
    print("初始向量:", listV)
    k, t, inverse_t = creatPKey(listV)
    print("\n私钥验证成功,分别为  <k:%d>, <t:%d>,<t逆元:%d>" %(k, t, inverse_t))
    sKeyList = creatSKey(listV, t, k)
    print("公钥向量为:", sKeyList, "\n")
    while True:
        choice = input("1、加密    2、解密\n请选择:")
        if choice == "1":
            massage = input("输入明文(01序列):")
            ciphertextList = encrypt(massage, sKeyList)
            print("加密结果:", ciphertextList)
        elif choice == "2":
            ciphertextList = list(map(int, list(input("输入密文:").split(","))))
            sKeyList = list(map(int, list(input("输入公钥向量:").split(","))))
            k = int(input("输入密钥k:"))
            inverse_t = int(input("输入密钥t逆:"))
            pliantext = decrypt(ciphertextList, sKeyList, k, inverse_t)
            print("解密结果:", pliantext)
            
完整代码:
import random

# 判断互质
def judgeCoPrime(a, b):
    # 求最大公因数
    def maxCommonFactor(m, n):
        result = 0
        while  m % n > 0:
            result = m % n
            m = n
            n = result
        return result
    if maxCommonFactor(a, b) == 1:
        return True
    return False

# 求逆元
def getInverse(a, b):
    # 扩展的欧几里得算法
    def extGcd(a_, b_, arr):
        if b_ == 0:
            arr[0] = 1
            arr[1] = 0
            return a_
        g = extGcd(b_, a_ % b_, arr)
        t = arr[0]
        arr[0] = arr[1]
        arr[1] = t - int(a_ / b_) * arr[1]
        return g
    # 求a模b的乘法逆x
    arr = [0,1,]
    gcd = extGcd(a, b, arr)
    if gcd == 1:
        return (arr[0] % b + b) % b
    else:
        return -1

# 初始化
def init(length, interval):
    listV = []  # 超递增向量
    listV_b = []  # 每个元素对应的乘数
    bagCapacity = 1000  # 背包容积
    # 初始化超递增向量与listV_b
    for i in range(length):
        listV.append(sum(listV) + random.randrange(1, interval))
        listV_b.append(0)
    # 求超递增背包的解
    bagCapacityTmp = bagCapacity
    for i in range(len(listV)-1, -1, -1):
        if bagCapacityTmp >= listV[i]:
            bagCapacityTmp -= listV[i]
            listV_b[i] = 1  # listV_b 表示每个元素是否被选入背包
    return listV  # listV是超递增向量

def creatPKey(listV):
    # listV = init()
    while True:
        k = int(input("输入私钥k(大于%d):" % (sum(listV))))
        if k <= sum(listV):
            print("输入的k值不合法,请重新设置")
            continue
        while True:
            t = int(input("输入私钥t(与k互素):"))
            if not judgeCoPrime(k, t):
                print("输入的t与k值不互素,请重新输入")
                continue
            break
        break
    inverse_t = getInverse(t, k)
    return k, t, inverse_t

# 产生公钥:
def creatSKey(listV, t, k):
    sKeyList = []  # 公钥序列
    for i in listV:
        sKeyList.append(i * t % k)
    return sKeyList

# 加密
def encrypt(massage, sKeyList):
    massageList = []    # 明文分组后的列表
    ciphertextList = []  # 存储密文的列表
    # 扩充明文消息串
    while len(massage) % len(sKeyList) != 0:
        massage = "0" + massage
    # 对明文进行分组
    for i in range(int(len(massage) / len(sKeyList))):
        start = (i * len(sKeyList))
        end = ((i + 1) * len(sKeyList))
        massageList.append(massage[start : end])
    # 采用内积和的方法加密
    for i in massageList:
        # 此处使用lambda时,要注意类型转换
        multiplyList = list(map(lambda x, y: int(x) * int(y), list(i), sKeyList))
        ciphertextList.append(sum(multiplyList))
    return ciphertextList

# 解密
def decrypt(massage, sKeyList, k, inverse_t):
    pliantextList = []  # 存储明文的列表
    reductListV = []  # 还原后的初始超递增向量
    # 还原超递增向量
    for i in sKeyList:
        reductListV.append(int(i) * inverse_t % k)
    # 计算出用于解密的临时背包容积
    bagCapacityList = []
    for i in massage:
        bagCapacityList.append(int(i) * inverse_t % k)
    # 利用求出的临时背包容积求解背包问题,结果即明文
    for bagCap in bagCapacityList:
        pliantextTmp = []   # 存储密文列表中每个密文解密后的序列
        for i in range(len(reductListV)):
            pliantextTmp.append(0)
        for i in range(len(reductListV) - 1, -1, -1):
            if bagCap >= reductListV[i]:
                bagCap -= reductListV[i]
                pliantextTmp[i] = 1
        pliantextList += pliantextTmp
    # 去除扩充的0并转换为字符串
    start, end = 0, 0
    for i in range(len(pliantextList)):
        if pliantextList[i] != 0:
            break
        end = i + 1
    del pliantextList[start : end]
    pliantextList = map(str, pliantextList)
    pliantext = "".join(pliantextList)
    return pliantext

if __name__ == "__main__":
    # listV = [1, 3, 7, 13, 26, 65, 119, 267]
    length = int(input("输入超递增向量元素个数:"))
    interval = int(input("输入随机增量:"))
    # length, interval = 8, 4
    listV = init(length, interval)
    print("初始向量:", listV)
    k, t, inverse_t = creatPKey(listV)
    print("\n私钥验证成功,分别为  <k:%d>, <t:%d>,<t逆元:%d>" %(k, t, inverse_t))
    sKeyList = creatSKey(listV, t, k)
    print("公钥向量为:", sKeyList, "\n")
    while True:
        choice = input("1、加密    2、解密\n请选择:")
        if choice == "1":
            massage = input("输入明文(01序列):")
            ciphertextList = encrypt(massage, sKeyList)
            print("加密结果:", ciphertextList)
        elif choice == "2":
            ciphertextList = list(map(int, list(input("输入密文:").split(","))))
            sKeyList = list(map(int, list(input("输入公钥向量:").split(","))))
            k = int(input("输入密钥k:"))
            inverse_t = int(input("输入密钥t逆:"))
            pliantext = decrypt(ciphertextList, sKeyList, k, inverse_t)
            print("解密结果:", pliantext)
            

个人博客:qinquanquan.com

  • 40
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qinquanquan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值