基于C#编程实现的一种自定义的剪切板内容加密解密算法

自定义一种加密算法及其编程实现

1. 加密原理

明文空间 明文长度 密文空间 密文长度
a-z 大于 1 a-z 希尔密码加密矩阵阶数的整数倍
加密顺序 解密顺序
明文 密文
维吉尼亚密码 希尔密码
仿射密码 仿射密码
希尔密码 维吉尼亚密码
密文 明文

1.1. 维吉尼亚密码

加密函数:

e K ( x 1 , x 2 , . . . x m ) = ( x 1 + k 1 , x 2 + k 2 , . . . x m + k m ) e_K(x_1, x_2, ... x_m) = (x_1 + k_1, x_2 + k_2, ... x_m + k_m) eK(x1,x2,...xm)=(x1+k1,x2+k2,...xm+km)

解密函数:

d K ( y 1 , y 2 , . . . y m ) = ( y 1 − k 1 , y 2 − k 2 , . . . y m − k m ) d_K(y_1, y_2, ... y_m) = (y_1 - k_1, y_2 - k_2, ... y_m - k_m) dK(y1,y2,...ym)=(y1k1,y2k2,...ymkm)

加密时,将数据进行分组。每个分组长度为
m m m。如果最后一个分组不足
$$

m
位 , 只 有 位,只有

n
位 位

(n<m)
, 则 只 加 密 这 前 ,则只加密这前

n$$ 位。

1.2. 仿射密码

加密函数:

e ( x ) = ( a x + b ) m o d    m e(x) = (ax + b) \mod m e(x)=(ax+b)modm

解密函数:

d ( y ) = a − 1 ( y − b ) m o d    m d(y) = a^{-1} (y - b) \mod m d(y)=a1(yb)modm

其中
a a a
$$

m
互 素 , 如 果 m = 26 , 则 互素,如果 m = 26, 则 m=26,

a \in {1,3,5,7,9,11,15,17,19,21,23,25}$$

1.3. 希尔密码

加密函数:

e K ( x ) = x K e_K(x) = xK eK(x)=xK

解密函数:

d k ( y ) = y K − 1 dk(y) = yK^{-1} dk(y)=yK1

其中密钥 K 为可逆方阵

1.3.1. 加密矩阵在有限域下求逆

设矩阵
A A A 可逆,
$$

A^-
为 其 逆 矩 阵 , 为其逆矩阵,

D
为 其 行 列 式 , 为其行列式,

A^*$$ 为其伴随矩阵,则有

A − = A ∗ D = A ∗ D − A^- = \frac{A*}{D} = A^* D^- A=DA=AD

其中
D − D^- D


D D D 在模
$$

m
下 的 逆 元 , 以 上 运 算 均 在 模 下的逆元,以上运算均在模

m$$ 下计算。

1.3.2. 加密

假如有如下明文:

明文序号 1 2 3 4 5 6 7 8 9 10
对应的值 12 0 1 6 18 25 6 20 25 25
1.3.2.1. 先对明文进行处理,加上终结符

根据统计,词频最低的为 z = 0.08,z 对应的是 25,即在明文中 z 出现的频率比较低,将采用 25 作为明文的终结符。所以,加密时如果遇到 25,需要将其转义,将其换成 2 个 25。

分析如上明文,将所有的 25 都换成两个 25,得到如下明文:

序号 1 2 3 4 5 6 7 8 9 10 11 12 13
12 0 1 6 18 25 25 6 20 25 25 25 25
在明文的最后加上一个25,作为终结符,得到如下密文:
序号 1 2 3 4 5 6 7 8 9 10 11 12 13 14
12 0 1 6 18 25 25 6 20 25 25 25 25 25
1.3.2.2. 填充分组

对明文进行分组,最后一组不足的补充 0(也可以填充随机值,但是不便于分析,这里就先简单填充相同的字符)。如果分组长度位 8,则得到如下密文:

序号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
12 0 1 6 18 25 25 6 20 25 25 25 25 25 0 0
1.3.2.3. 加密
序号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
12 0 1 6 18 25 25 6 20 25 25 25 25 25 0 0
对每个分组进行矩阵加密
1.3.2.4. 至此,加密结束,只需将数字转换成对应的字母即可

1.3.3. 解密

如果密文分组后,最后一组不是完整的组,说明密文和密钥不匹配,无法解密。如果分组正常,则使用和加密相反的过程。

1.3.3.1. 解密

使用矩阵解密每一个分组。假如解密后得到如下明文:

序号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
12 0 1 6 18 25 25 6 20 25 25 25 25 25 0 0
1.3.3.2. 去除填充数据

从前往后,找到终结符 25 的下标,然后将其本身以及后面的所有数据删除,得到如下明文:

序号 1 2 3 4 5 6 7 8 9 10 11 12 13
12 0 1 6 18 25 25 6 20 25 25 25 25
1.3.3.3. 将两个连续的 25 合并为一个,得到如下明文:
序号 1 2 3 4 5 6 7 8 9 10
12 0 1 6 18 25 6 20 25 25
1.3.3.4. 至此,解密结束,只需将序号

2. 编程实现

使用 C#开发的 winform 程序。

2.1. 界面效果

2.1.1 密钥配置

  • 应用打开后,需要用户配置密钥。如果不想自己输入,可以点击“生成随机密钥”按钮。

  • 生成随机密钥

  • 生成随机密钥后,可以点击“导出密钥”按钮,程序会将密钥保存为“JSON”文件,然后可以将密钥发送给他人。

    • 弹窗提示保存成功

    • 可以打开看一下,格式如下

      {
              
              
        "InvalidIntValue": 2147483647,
        "VigenereKey": [ 1, 15, 22, 24, 22, 9 ],
        "AffineKeyA": 23,
        "AffineKeyB": 6,
        "HillMatrix": [ 
          [   11,   15,    7,   10,    9,   20,   24,   10 ], 
          [   15,   19,   16,    1,   16,    7,   16,   21 ], 
          [   22,    6,   10,   24,    1,   18,    6,   22 ], 
          [    6,   13,    1,   22,   13,   12,    5,   16 ], 
          [   22,   20,   18,   24,   14,    5,   20,   17 ],
          [    2,   15,    2,   17,    2,   17,   18,   7 ], 
          [   18,   14,   13,    8,   21,    1,   22,   17 ], 
          [   10,    9,    5,   20,   20,    2,   21,   3 ]
        ],
        "AllKeysReady": true
      }
      
  • 如果需要解密他人的密文,可以点击“导入密钥”按钮来导入对方的密钥。

2.1.2 加解密文本

  • 如果勾选“将结果复制到剪切板”,当执行加密操作时,会将密文直接复制到剪切板,便于直接粘贴给别人。
  • 如果勾选“从剪切板获取文本”,当执行解密操作时,会从剪切板读取文本解密
  • 开始使用加解密功能,输入待加密的字母,点击“加密”按钮

  • 将密文复制到“数据源”中,点击“解密”按钮即可得到明文。(如果勾选了“从剪切板获取文本”则可以直接点击解密按钮,程序会自动把剪切板中的密文填充到“数据源”中,并执行解密操作)

2.2. 部分源码

2.2.1 维吉尼亚密码

// 加密
public List<char> Decrypt(List<char> cipher)
{
    var result = new List<char>();
    int groupLength = vigenereKey.Length;

    for (int i = 0; i < cipher.Count; i++)
    {
        var _ = cipher[i] - vigenereKey[i % groupLength];
        result.Add((char)((_ % m + m) % m));
    }

    return result;
}

// 解密
public List<char> Encrypt(List<char> plain)
{
    var result = new List<char>();
    int groupLength = vigenereKey.Length;

    for (int i = 0; i < plain.Count; i++)
    {
        var _ = plain[i] + vigenereKey[i % groupLength];
        result.Add((char)(_ % m));
    }

    return result;
}

2.2.2 仿射密码

// 解密
public List<char> Decrypt(List<char> cipher)
{
    int ap = AAP[a]; // a的逆元
    for (int i = 0; i < cipher.Count; i++)
    {
        cipher[i] = (char)(((ap * (cipher[i] - b)) % 26 + 26) % 26);
    }
    return cipher;
}

// 加密
public List<char> Encrypt(List<char> plain)
{
    for (int i = 0; i < plain.Count; i++)
    {
        plain[i] = (char)(((a * plain[i] + b) % 26 + 26) % 26);
    }
    return plain;
}

2.2.3 希尔密码

// 解密
public List<char> Decrypt(List<char> cipher)
{
    // TODO Delete
    //PrintList(cipher, "[解密前]");

    if (cipher.Count % groupLength != 0)
    {
        throw new FormatException("密文的格式出错,请检查是否缺失数据");
    }

    // 解密
    int groupNums = cipher.Count / groupLength;   // 总分组数
    List<char> result = new List<char>();   // 结果

    for (int i = 0; i < groupNums; i++)
    {
        // 使用加密矩阵将分组解密,然后添加到结果中
        result.AddRange(
            MatrixIntGF26.MultiplyMod26(
                cipher.GetRange(i * groupLength, groupLength).ToArray(), 
                DKEY
            )
        );
    }

    // 去冗余,去除终结符之后的数据
    var index = result.LastIndexOf(Transfer_Char);
    if (index == -1)
    {
        throw new Exception("数据出错,或者数据和希尔密码的密钥不匹配");
    }
    result.RemoveRange(index, result.Count - index);

    // 合并连续的两个终结符
    for (int i = 1; i < result.Count; i++)
    {
        if (result[i] == Transfer_Char)
        {
            if (result[i - 1] == Transfer_Char)
            {
                result.RemoveAt(i);
            }
        }
    }

    return result;
}

// 加密
public List<char> Encrypt(List<char> plain)
{
    // 拷贝plain
    var copy = new List<char>();
    for (int i = 0; i < plain.Count; i++)
    {
        copy.Add(plain[i]);
    }

    // 将终结符转义,即将一个终结符换成两个连续的终结符
    for (int i = 0; i < copy.Count; i++)
    {
        if (copy[i] == Transfer_Char)
        {
            copy.Insert(i, Transfer_Char);
            i++;
        }
    }

    // 在数据的最后加上终结符
    copy.Add(Transfer_Char);

    // 检查数据总长度,如果最后一组数量不够,需要填充数据
    int appendLength = copy.Count % groupLength;// 填充数
    if (appendLength != 0)
    {
        appendLength = groupLength - appendLength;
    }

    for (int i = 0; i < appendLength; i++)
    {
        copy.Add(Append_Char);
    }
    
	// 总分组数
    int groupNums = copy.Count / groupLength + ((copy.Count % groupLength) == 0 ? 0 : 1);   

    List<char> result = new List<char>();   // 结果
    for (int i = 0; i < groupNums; i++)
    {
        // 使用加密矩阵将分组加密,然后添加到结果中
        result.AddRange(
            MatrixIntGF26.MultiplyMod26(
                copy.GetRange(
                    i * groupLength, groupLength).ToArray(), 
                	EKEY
            )
        );
    }

    return result;
}

2.2.4 希尔密码辅助类

用来提供 mod26 下矩阵的乘法运算以及矩阵求逆等运算。代码比较多,就不展示了

猜你喜欢

转载自blog.csdn.net/newlw/article/details/125008708