Skip to content

Commit ac2b55a

Browse files
committed
feat: rail fence cipher
1 parent 95aa2e3 commit ac2b55a

File tree

3 files changed

+200
-3
lines changed

3 files changed

+200
-3
lines changed

src/pages/caesar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import MainContent from '@/components/MainContent';
66
import alertActions from '@/components/Alert';
77

88
const encode = (text: string, pwdOffest: number) => {
9-
if (pwdOffest >= 26) pwdOffest = pwdOffest % 26;
9+
if (pwdOffest >= 26) pwdOffest %= 26;
1010
return Array.from(text)
1111
.map((item) => {
1212
const count = item.charCodeAt(0);
@@ -24,7 +24,7 @@ const encode = (text: string, pwdOffest: number) => {
2424
.join('');
2525
};
2626
const decode = (pwd: string, pwdOffest: number) => {
27-
if (pwdOffest > 25) pwdOffest = pwdOffest % 25;
27+
if (pwdOffest >= 26) pwdOffest %= 26;
2828
return Array.from(pwd)
2929
.map((item) => {
3030
const count = item.charCodeAt(0);

src/pages/rail_fence_cipher.tsx

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import React, { useState } from 'react';
2+
import { Container, Grid, TextField, Button, Box } from '@mui/material';
3+
import SendIcon from '@mui/icons-material/Send';
4+
import TranslateIcon from '@mui/icons-material/Translate';
5+
import MainContent from '@/components/MainContent';
6+
import alertActions from '@/components/Alert';
7+
8+
const encode = (text: string, rails: number) => {
9+
// 创建栅栏矩阵
10+
const fence: string[][] = Array.from({ length: rails }, () => []);
11+
12+
// 将字符按照"W"字形排列到栅栏矩阵中
13+
let rail = 0;
14+
let direction = 1;
15+
for (let i of text) {
16+
fence[rail].push(i);
17+
rail += direction;
18+
if (rail === 0 || rail === rails - 1) {
19+
direction = -direction;
20+
}
21+
}
22+
23+
// 按照特定顺序读取字符并拼接成密文
24+
let pwd = '';
25+
for (let i = 0; i < rails; i++) {
26+
pwd += fence[i].join('');
27+
}
28+
29+
return pwd;
30+
};
31+
32+
const decode = (pwd: string, rails: number) => {
33+
// 创建栅栏矩阵
34+
const fence: string[][] = Array.from({ length: rails }, () => []);
35+
36+
// 计算栅栏中每行的字符数
37+
const railCounts = Array.from({ length: rails }, () => 0);
38+
let rail = 0;
39+
let direction = 1;
40+
for (let i = 0; i < pwd.length; i++) {
41+
railCounts[rail]++;
42+
rail += direction;
43+
if (rail === 0 || rail === rails - 1) {
44+
direction = -direction;
45+
}
46+
}
47+
48+
// 将密文中的字符填充到栅栏矩阵中
49+
let index = 0;
50+
for (let i = 0; i < rails; i++) {
51+
for (let j = 0; j < railCounts[i]; j++) {
52+
fence[i].push(pwd[index]);
53+
index++;
54+
}
55+
}
56+
57+
// 按照"山"字形顺序读取字符并拼接成明文
58+
let plaintext = '';
59+
rail = 0;
60+
direction = 1;
61+
for (let i = 0; i < pwd.length; i++) {
62+
plaintext += fence[rail].shift();
63+
rail += direction;
64+
if (rail === 0 || rail === rails - 1) {
65+
direction = -direction;
66+
}
67+
}
68+
69+
return plaintext;
70+
};
71+
const RailFenceCipher = () => {
72+
const [text, setText] = useState('');
73+
const [pwd, setPwd] = useState('');
74+
const [pwdOffest, setPwdOffest] = useState(3);
75+
76+
const onTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
77+
setText(event.target.value);
78+
};
79+
80+
const onPwdChange = (event: React.ChangeEvent<HTMLInputElement>) => {
81+
setPwd(event.target.value);
82+
};
83+
84+
const encodeToMorse = () => {
85+
try {
86+
const encoded = encode(text, pwdOffest);
87+
setPwd(encoded);
88+
} catch (error) {
89+
const err = error as Error;
90+
console.log(err);
91+
alertActions.error('加密失败!');
92+
}
93+
};
94+
95+
const decodeFromMorse = () => {
96+
try {
97+
const decoded = decode(pwd, pwdOffest);
98+
setText(decoded);
99+
} catch (error) {
100+
const err = error as Error;
101+
console.log(err);
102+
alertActions.error('解密失败!');
103+
}
104+
};
105+
106+
return (
107+
<MainContent>
108+
<>
109+
<TextField
110+
fullWidth
111+
label='栏目数'
112+
placeholder='请输入栏目数'
113+
value={pwdOffest}
114+
type='number'
115+
onChange={(e) => {
116+
setPwdOffest(e.target.value as any);
117+
}}
118+
inputProps={{
119+
style: { fontFamily: 'monospace' },
120+
}}
121+
sx={{ width: '200px', ml: 'auto' }}
122+
/>
123+
<Container maxWidth='lg'>
124+
<Box sx={{ my: 4 }}>
125+
<Grid container spacing={2} alignItems='center'>
126+
<Grid item xs={12} md={5}>
127+
<TextField
128+
fullWidth
129+
label='文本'
130+
placeholder='请输入要加密的文本'
131+
value={text}
132+
onChange={onTextChange}
133+
variant='outlined'
134+
multiline
135+
rows={10}
136+
inputProps={{
137+
style: { fontFamily: 'monospace' },
138+
}}
139+
/>
140+
</Grid>
141+
<Grid
142+
item
143+
xs={12}
144+
md={2}
145+
container
146+
direction='column'
147+
alignItems='center'
148+
justifyContent='space-around'
149+
>
150+
<Button
151+
variant='contained'
152+
onClick={encodeToMorse}
153+
startIcon={<SendIcon />}
154+
sx={{ mb: 2 }}
155+
>
156+
加密
157+
</Button>
158+
<Button
159+
variant='contained'
160+
onClick={decodeFromMorse}
161+
startIcon={<TranslateIcon />}
162+
>
163+
解密
164+
</Button>
165+
</Grid>
166+
<Grid item xs={12} md={5}>
167+
<TextField
168+
fullWidth
169+
label='栅栏密码'
170+
placeholder='请输入要解密的凯撒密码'
171+
value={pwd}
172+
onChange={onPwdChange}
173+
variant='outlined'
174+
multiline
175+
rows={10}
176+
inputProps={{
177+
style: { fontFamily: 'monospace' },
178+
}}
179+
/>
180+
</Grid>
181+
</Grid>
182+
</Box>
183+
</Container>
184+
</>
185+
</MainContent>
186+
);
187+
};
188+
189+
export default RailFenceCipher;

src/utils/tools.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,10 +600,18 @@ export const allTools: Tool[] = [
600600
},
601601
{
602602
label: '凯撒密码在线加密解密',
603-
tags: [Tags.SECURITY],
603+
tags: [Tags.ENCRYPT],
604604
path: '/caesar',
605605
key: [],
606606
subTitle:
607607
'凯撒密码最早由古罗马军事统帅盖乌斯·尤利乌斯·凯撒在军队中用来传递加密信息,故称凯撒密码。此为一种位移加密手段,只对26个(大小写)字母进行位移加密,规则相当简单,容易被破解',
608608
},
609+
{
610+
label: '栅栏密码在线加密解密',
611+
tags: [Tags.ENCRYPT],
612+
path: '/rail_fence_cipher',
613+
key: [],
614+
subTitle:
615+
'所谓栅栏密码,就是把要加密的明文分成N个一组,然后把每组的第1个字连起来,形成一段无规律的话。 不过栅栏密码本身有一个潜规则,就是组成栅栏的字母一般不会太多。(一般不超过30个,也就是一、两句话)',
616+
},
609617
];

0 commit comments

Comments
 (0)