简介
置换密码是一种通过一定规则改变字符串中字符的顺序从而实现加密的密码算法。常见的是将明文字符串按照n个一行形成矩阵,然后再按列读出,矩阵的列数(n)和按列读出的顺序便是密钥。
加密
我们以字符串“hello-my-cipher”为例来演示加密过程
-
选择密钥,我们这里使用“4213”作为密钥。该密钥共4位,表示中间结果的矩阵共4列,4213表示按照第四列,第二列,第一列,第三列的顺序读出形成密文
-
生成中间结果矩阵(该行不够4个则用明文中不包含的固定字符填充,这里使用‘@’)
h e l l
o - m y
- c i p
h e r @
-
按照密钥所示的列顺序读出
lyp@e-ceho-hlmir
-
至此加密完成
解密
解密过程即按照密钥所示的长度顺序恢复出矩阵,再按行读取即可。
已知明文破解
根据置换密码算法的特点,破解的主要难点是确定密钥的长度。我们可以根据密文的第一个和第二个字符在明文中的位置之差得出密钥的长度,但这中方法并不总是有效,例如helloeye用密钥1234加密后密文前两个字符是he,而h,e在明文中的位置有1和4,再例如helloeye用3124加密后前两个字符是ly,而l,y在明文中的位置有4和5,所以这个方法无法完全确定密钥长度。假如我们确定了密钥长度,就可以把明文形成矩阵,然后比对密文和明文矩阵的列,便能确定按列读出的顺序,也就得到了密钥。(这里还有碰到明文矩阵中两列完全一样情况,这样就得不到完整的密钥)
举个栗子:
明文:abcdefgh
密钥:2143
加密结果:bfaedhcg(8个字符)
根据bf在明文中的位置,第2和第6,得到密钥长度为4,则每列长度为8/4=2,然后生成矩阵
a b c d
e f g h
密文中前2个字符为bf,找到矩阵中bf列为第二列,密钥第一位是2,密文中接下来2个字符是ae,找到矩阵中ae
列为第一列,密钥第二位是1,按这个方法,就可以得到密钥为2143了
当面对密钥长度有多种可能的时候,目前在我看来只能全部试过,所以这个破解不算完全。
代码实现
/*置换密码编码
*permutation_encode(plain_text,len,key,key_len,&result)
*@para1:字符串明文
*@para2:该明文的长度
*@para3:以字符串数字表示的密钥,即读取列的顺序
*@para4:密钥的长度,也是置换中矩阵行的长度
*@para5:用来接收结果的二级指针(传入参数时使用&+一级指针)
*返回加密后字符串的长度
*
*permutation_decode(cipher_text,len,key,key_len,&result)
*参数与加密函数类似,区别是第一个为密文字符串
*返回解密后明文的长度
*/
/*编码*/
int permutation_encode(const char* plain_text,int len,const char* key,int key_len,char** result)
{
//读取密文的指示
int p_cipher = 0;
//读取密钥的指示
int p_key = 0;
//读取明文的指示
int p_plain = key[p_key]-'1';
//密文的长度(需要分配的空间)
int space;
//按密钥长度分组后余下的部分长度(不足矩阵一行)
int stuff_len = len%key_len;
//密文
char* cipher_text;
//分配空间
if(stuff_len==0)
space = len;
else
space = (len/key_len+1)*key_len;
cipher_text = (char*)malloc(space+1);
for(;p_cipher<space;p_cipher++)
{
if(p_plain<len)/*正常读取*/
cipher_text[p_cipher] = plain_text[p_plain];
else if(p_plain>=space)/*该列已经读取完毕*/
{
p_key++;
p_plain = key[p_key]-'1';
cipher_text[p_cipher] = plain_text[p_plain];
}
else/*该列最后一行没有字符,则填充@*/
{
p_key++;
p_plain = key[p_key]-'1';
cipher_text[p_cipher] = '@';
continue;
}
/*取该列下一个字符*/
p_plain = p_plain + key_len;
}
cipher_text[space] = '\0';
*result = cipher_text;
return space;
}
int permutation_decode(char* cipher_text,int len,char* key,int key_len,char** result)
{
int p_cipher = 0;
int p_key = 0;
int p_plain = key[p_key]-'1';
int plain_text_len = len;
char* plain_text;
plain_text = (char*)malloc(len);
for(;p_cipher<len;p_cipher++)
{
if(p_plain>=len)/*该列已经读取完毕*/
{
p_key++;
p_plain = key[p_key]-'1';
plain_text[p_plain] = cipher_text[p_cipher];
}
else/*正常读取*/
{
if(cipher_text[p_cipher] == '@')
plain_text_len--;
plain_text[p_plain] = cipher_text[p_cipher];
}
p_plain = p_plain + key_len;
}
plain_text[plain_text_len] = '\0';
*result = plain_text;
return plain_text_len;
}