一、简述
近期在BugkuCTF上碰到了一个栅栏密码的题目,刚开始用了在线的解密工具解密出了flag。但是仅用在线工具直接得到结果肯定是不行的,于是通过AI了解了栅栏密码的原理以及加密和解密思路,并用C语言实现了一下。
二、思路与概括
根据查看的资料,它本质上是一种置换密码 (只改变字符位置,不改变内容),所以按个人理解是只是将内容中的字符或数字打乱了顺序,因此可以尝试通过循环去输出所有的可能性组合,但这会计算爆炸,所以不可行。
按照栅栏密码的加密思路,是将一整段密码分为了多份,再从这个多份里面去挨个抽取值,可以理解为:
将N张牌,按照数量分为两份或多份,然后开始在第一份中抽取一个,再在第二份中抽取一个,循环抽取,每次收取的牌的数量为当前循环的下标值。
破解原理就是:首先要知道密文总长度是多少,这样才能进行分段计算,然后需要根据已知的层数,去对整段密文进行分段,使其符合当初抽牌的时候一样。
用 总长度 / 层数 = 加密时共计抽取了多少次
然后循环 i 控制行数,j 控制列数,i 的值决定了本次要抽牌的次数,而 j 的值决定了本次需要抽那一张牌,然后输出这个排列就是解密后的答案。
三、实现结果

四**、C**源码
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void decrypt_railfence(char* ciphertext, int key) {
int i,j;
int len = strlen(ciphertext); //22
// printf("函数中密文的长度:%d\n",len);
char plaintext[len + 1]; // 23
// printf("函数中plaintext的值是:%s\n",plaintext);
int segment = len / key; // 每组的长度 11
// printf("函数中组的长度:%d\n",segment);
for (i = 0; i < segment; i++) {
for (j = 0; j < key; j++) {
plaintext[i * key + j] = ciphertext[i + j * segment];
}
}
plaintext[len] = '\0';
printf("Key是: %d 结果是: %s\n", key, plaintext);
}
main(){
char text_pwd[100];
int lan_num = 0;
printf("请输入栅栏的密文:");
scanf("%s",&text_pwd);
// printf("这里是输入的栅栏的密文:%s\n\n",text_pwd);
printf("请输入栅栏的层数:");
scanf("%d",&lan_num);
// printf("这里是输入栅栏的层数:%d\n\n",lan_num);
decrypt_railfence(text_pwd,lan_num);
return 0;
}