字符串加密

#!/usr/bin/python3
# 文件名: 字符串加密
# 作者:巧若拙
# 时间:2019-1-25

'''描述:字符串加密。待加密的n个字符(仅由ASCII码字符构成,最多支持960个字符),加密方式如下:
①产生一个3到6之间的随机整数k, 将十进制数960均分成k份,字符在字符串中的位置除以k的余数决定该字符存放在第几份数据中(余数为1保存在第一份数据中,余数为2保存在第二份数据...余数为0保存在第k份数据中);
②用十进制数127减去每个字符的ASCII码值,得到的差作为该字符的密文,同一段内的密文依次存放;
③将随机产生的数k加64后作为第一个密文存放到数组b中;
④将其他所有有密文按照在数据段中的位置依次逆序存放到数组b中;
⑤将数组b中的每个密文用3位数字保存,不足3位的前面用0补足,然后依次连接成一个新的字符串;
⑥返回密文字符串。
函数名:encrypt (p)
参数表:p –– 待加密的字符串。
返回值:c –– 加密后的字符串。
例1,当p = ”zp123”时,c=” 067078076015077005”;
例2,当p = ”Vb”时,c=” 068029041”。
'''

import random
    
def encrypt(p):
    k = random.choice((3, 4, 5, 6)) #3到6之间的随机整数k
    k = 4
    a = [-1] * 961 #默认均为-1
    t = 960 // k
    for i in range(len(p)):
        r, c = i % k, i // k
        a[r*t+c] = 127 - ord(p[i]) #将密文存储到数组a中
    a[960] = k + 64
    s = ['0'*(3-len(str(i))) + str(i) for i in a[::-1] if i != -1]
    return "".join(s)
'''
解密是加密的逆过程。首先从前3个字符中计算出总行数k,然后每3个字符一组,
把所有的明文字符都翻译出来,依次存储到列表a,再把a翻转,得到顺序排列的明文字符。需要注意的是此时的明文字符是按照行序号排列的,我们需要将其转换成按列序排列才能得到最终的结果。例如,若密文字符串s=” 068071075072076079073077070074078”;解密得到k=4,a= ['1', '5', '9', '2', '6', '0', '3', '7', '4', '8']。将其排列到二维数组中,就是:
 
把明文字符从二维数组中按照列序依次存储到列表p中并转化为字符串,
就得到最终结果”1234567890”。
因为二维数组的最后一列不一定能填满,
为了把列表a的元素存储到二维数组中的正确位置,
我们需要引入两个变量width和rest,其中width = len(a) // k表示最小宽度,
即已经装满的列数rest = len(a) % k表示未满列的行数。若所有的列都是满的,
则width等于总列数,rest=0。
设置好这两个变量以后,我们就可以按照行序把列表a中的元素依次填入二维数组,
再按照列序把元素从二维数组中取出来,就得到了正确排列的明文字符。
'''

#解密算法1:构造一个二维数组,思路较为直观
def decrypt(s):
    k = int(s[:3]) - 64 #总共k行
    a = []
    for i in range(3,len(s),3):
        a.append(chr(127 - int(s[i:i+3])))
    a = a[::-1]
    print(a)
    width = len(a) // k #最小宽度,当所有的列都满时,刚好等于列数
    rest = len(a) % k   #数据未满列也有数据的行数
    b = [[-1 for i in range(width+1)] for j in range(k)]
    c, r, i = 0, 0, 0
    while i < len(a): #按照行序存储明文到二维数组中
        if c < width or (c == width and r < rest):
            b[r][c] = a[i]
            c += 1
            i += 1
        else: #到了右边界,处理下一行
            r += 1
            c = 0
    p = [] #按列序从二维数组提取明文 
    for c in range(width): #先提取排满数据的列
        for r in range(k):
            p.append(b[r][c])
    for r in range(rest): #再提取未排满数据的列
        p.append(b[r][width])
    return "".join(p)

#解密算法2:利用移动数组a的下标,直接生成明文,代码简洁但不够直观
def decrypt2(s):
    k = int(s[:3]) - 64 #总共k行
    a = []
    for i in range(3,len(s),3):
        a.append(chr(127 - int(s[i:i+3])))
    a = a[::-1]
    width = len(a) // k #最小宽度,当所有的列都满时,刚好等于列数
    rest = len(a) % k   #数据未满列也有数据的行数
    p = [] #按列序从二维数组提取明文 
    for c in range(width): #先提取排满数据的列
        i = c  #a的下标指向第一行的下一列位置
        for r in range(k):
            p.append(a[i])
            #a的下标向后跳跃,移动到其在矩阵中的正下方的位置
            if r < rest: 
                i += width + 1
            else:
                i += width
    i = width #再提取未排满数据的列
    for r in range(rest): 
        p.append(a[i])
        i += width + 1 #跳到下一行
    return "".join(p)  

p = "1234567890"
s = encrypt(p)
print(s)
print(decrypt(s))
print(decrypt2(s))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值