Skip to content

Commit bdfd770

Browse files
committed
v1.5.0 Morse code
1 parent 1e878b5 commit bdfd770

File tree

11 files changed

+239
-108
lines changed

11 files changed

+239
-108
lines changed

src/locale/components/setting.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module.exports = {
1313
remark: {
1414
1: 'Fixed and short',
1515
2: 'Random and short',
16-
3: 'One natural language'
16+
3: 'Morse code'
1717
}
1818
}
1919
},
@@ -31,7 +31,7 @@ module.exports = {
3131
remark: {
3232
1: '等长唯一',
3333
2: '等长随机',
34-
3: '自然语言'
34+
3: '摩斯码'
3535
}
3636
}
3737
},

src/locale/components/version.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module.exports = {
2525
},
2626
"1_3_0": {
2727
"0": "Change the logo",
28-
"1": "Support Ctrl+Q to quickly encrypt and decrypt the selected text"
28+
"1": "Support Ctrl+, to quickly encrypt and decrypt the selected text"
2929
},
3030
"1_3_1": {
3131
"0": "Fix manual decription bug caused by FireFox's bug"
@@ -36,8 +36,9 @@ module.exports = {
3636
"1_4_1": {
3737
"0": "Optimize package size."
3838
},
39-
"1_4_2": {
40-
"0": "Fix bugs on www.tumblr.com"
39+
"1_5_0": {
40+
"0": "Support new ciphertext format: morse code",
41+
"1": "Needn't refresh pages any more after settings changed"
4142
}
4243
},
4344
zh_CN: {
@@ -65,7 +66,7 @@ module.exports = {
6566
"1": "修复已知 bug"
6667
},
6768
"1_3_0": {
68-
"0": "支持Ctrl+Q快捷加解密选中的明文/密文",
69+
"0": "支持Ctrl+,快捷加解密选中的明文/密文",
6970
"1": "更改图标和 Logo"
7071
},
7172
"1_3_1": {
@@ -79,6 +80,10 @@ module.exports = {
7980
},
8081
"1_4_2": {
8182
"0": "修复 www.tumblr.com 上的一些 bug"
83+
},
84+
"1_5_0": {
85+
"0": "支持新的密文风格:摩斯码",
86+
"1": "修改设置信息后不用再刷新页面"
8287
}
8388
}
8489
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Translate string 2 unicode array
3+
*/
4+
function toUnicodeArray(str: string): number[] {
5+
const result: Array<number> = []
6+
for (let i = 0; i < str.length; i++) {
7+
result.push(str.charCodeAt(i))
8+
}
9+
return result
10+
}
11+
12+
/**
13+
* Translate the password 2 number
14+
*
15+
* @param password
16+
* @returns number
17+
*/
18+
export function password2Number(password: string): number {
19+
let pn: number = 0
20+
toUnicodeArray(password).forEach((n: number) => pn ^= n)
21+
return pn
22+
}
23+
24+
function unicodes2Str(unicodes: number[]): string {
25+
return unicodes.map(cn => String.fromCharCode(cn)).join("")
26+
}
27+
28+
/**
29+
* Ring with XOR
30+
*
31+
* @param source source text
32+
*/
33+
export function ring(passwordNumber: number, source: string) {
34+
return unicodes2Str(ringToUnicodes(passwordNumber, source))
35+
}
36+
37+
/**
38+
* Ring with XOR
39+
*
40+
* @param source source text
41+
*/
42+
export function ringToUnicodes(passwordNumber: number, source: string): number[] {
43+
return toUnicodeArray(source).map(mn => mn ^ passwordNumber)
44+
}
45+
46+
/**
47+
* Ring with XOR
48+
*
49+
* @param source source text
50+
*/
51+
export function ringFromUnicodes(passwordNumber: number, source: number[]): string {
52+
return unicodes2Str(source.map(mn => mn ^ passwordNumber))
53+
}

src/zero/cryptor/cryptor1.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ICryptor } from '.'
2-
import { password2Number, toUnicodeArray } from './util'
2+
import { password2Number, ring } from './algorithm/string-process'
33

44
/**
55
* The first cryptor
@@ -23,13 +23,8 @@ export default class Cryptor1 implements ICryptor {
2323
return this.ring(cipher, password)
2424
}
2525

26-
/**
27-
* Ring with XOR
28-
*
29-
* @param msg msg
30-
*/
3126
private ring(msg: string, psw: string): string {
3227
const pn = password2Number(psw)
33-
return toUnicodeArray(msg).map(mn => mn ^ pn).map(cn => String.fromCharCode(cn)).join("")
28+
return ring(pn, msg)
3429
}
3530
}

src/zero/cryptor/cryptor2.ts

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ICryptor } from ".";
22
import Cryptor1 from "./cryptor1";
3-
import Salt from "./salt";
4-
import { password2Number, toUnicodeArray } from "./util";
3+
import { password2Number, ring } from "./algorithm/string-process";
54

65
/**
76
* The second version of cryptor
@@ -23,26 +22,85 @@ export default class Cryptor2 extends Cryptor1 implements ICryptor {
2322
}
2423

2524
encript(plain: string, password: string): string {
26-
const charArr: Array<number> = toUnicodeArray(plain)
27-
2825
let pn: number = password2Number(password)
2926
const salt: Salt = new Salt()
3027
salt.calcSalt(pn)
3128
pn = salt.getNewPn()
3229

33-
const cipher = charArr.map(value => value ^ pn).map(c => String.fromCharCode(c)).join("")
34-
return salt.getPrefix() + cipher
30+
const cipher = ring(pn, plain)
31+
return String.fromCharCode(salt.getPrefixUnicode()) + cipher
3532
}
3633

3734
decrypt(cipher: string, password: string): string {
3835
let pn: number = password2Number(password)
3936

4037
const salt: Salt = new Salt()
41-
salt.parseSalt(pn, cipher)
38+
salt.parseSalt(pn, cipher.charCodeAt(0))
4239
pn = salt.getNewPn()
4340

44-
const charArr: Array<number> = toUnicodeArray(cipher.substring(1))
41+
return ring(pn, cipher.substring(1))
42+
}
43+
}
44+
45+
46+
/**
47+
* Salt for ramdon cipher
48+
*
49+
* @since 1.1.1
50+
*/
51+
class Salt {
52+
private static ZERO_BASE = 0x4e00
53+
private static MASK_SEGMENT = [7, 15, 31, 63, 127, 255]
54+
private static ZH_LENGTH = 1 << 10 // = 1024
55+
56+
mask: number
57+
salt: number
58+
pn: number
59+
60+
/**
61+
* Generate salt
62+
*
63+
* @param pn
64+
*/
65+
calcSalt(pn: number): void {
66+
this.pn = pn
67+
this.calcMask()
68+
while (!this.isValid()) {
69+
this.circle()
70+
}
71+
}
72+
73+
parseSalt(pn: number, cipherSaltCode: number) {
74+
this.pn = pn
75+
this.calcMask()
76+
this.salt = (cipherSaltCode - Salt.ZERO_BASE) * (this.mask + 1) / Salt.ZH_LENGTH
77+
}
78+
79+
private isValid(): boolean {
80+
return !!this.getNewPn() // newPn != 0
81+
}
82+
83+
private circle() {
84+
this.salt = new Date().getTime() & this.mask
85+
}
86+
87+
private calcMask() {
88+
let mask: number
89+
for (let i = 0; i < Salt.MASK_SEGMENT.length; i++) {
90+
mask = Salt.MASK_SEGMENT[i]
91+
if (this.pn < mask) {
92+
this.mask = mask
93+
break
94+
}
95+
}
96+
this.mask = mask
97+
}
98+
99+
getNewPn(): number {
100+
return this.pn + this.salt
101+
}
45102

46-
return charArr.map(value => value ^ pn).map(c => String.fromCharCode(c)).join("")
103+
getPrefixUnicode(): number {
104+
return (this.salt * Salt.ZH_LENGTH / (this.mask + 1)) + Salt.ZERO_BASE
47105
}
48106
}

src/zero/cryptor/cryptor3.ts

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,97 @@
11
import { ICryptor } from "."
2+
import { password2Number, ringFromUnicodes, ringToUnicodes } from "./algorithm/string-process"
23

4+
const WORD_LEN_LEN = 4
35
/**
46
*
57
* The second version of cryptor with morse code
68
*
9+
* Format:
10+
* 4-digits-max-word-length + cipher
11+
*
712
* @since 1.5.0
813
*/
914
export default class Cryptor3 implements ICryptor {
15+
1016
version(): number {
1117
return 3
1218
}
19+
1320
prefix(): string {
14-
return 'z03'
21+
return '-'
1522
}
23+
1624
encript(plain: string, password: string): string {
17-
throw new Error("Method not implemented.")
25+
let pn = password2Number(password)
26+
27+
const cipherUnicodes: number[] = ringToUnicodes(pn, plain)
28+
29+
const unicodeLength: number = this.maxUnicodeLength(cipherUnicodes)
30+
31+
return this.number2MorseCode(unicodeLength, WORD_LEN_LEN) + cipherUnicodes.map(unicode => this.number2MorseCode(unicode, unicodeLength)).join("")
1832
}
33+
1934
decrypt(cipher: string, password: string): string {
20-
throw new Error("Method not implemented.")
35+
if (cipher.length < WORD_LEN_LEN) {
36+
return cipher
37+
}
38+
const lenthMorse = cipher.substring(0, 4)
39+
let length = this.morse2Number(lenthMorse)
40+
if (length < 0) {
41+
return cipher
42+
}
43+
if (length === 0) {
44+
length = 16
45+
}
46+
const unicodes: number[] = []
47+
for (let i = WORD_LEN_LEN; i + length <= cipher.length; i += length) {
48+
const unicode = this.morse2Number(cipher.substr(i, length))
49+
if (unicode === -1) {
50+
return cipher
51+
}
52+
unicodes.push(unicode)
53+
}
54+
const pn = password2Number(password)
55+
return ringFromUnicodes(pn, unicodes)
56+
}
57+
58+
/**
59+
* Translate unicode 2 morse code
60+
* @param code unicode
61+
* @returns the length of morse code
62+
*/
63+
private number2MorseCode(code: number, length: number) {
64+
let result = ''
65+
for (let mask = 1 << (length - 1); mask > 0; mask >>= 1) {
66+
result += (code & mask) ? '-' : '·'
67+
}
68+
return result
69+
}
70+
71+
private morse2Number(morse: string) {
72+
let result = 0
73+
for (let i = 0; i < morse.length; i++) {
74+
result <<= 1
75+
const char = morse.charAt(i)
76+
if (char === '-') {
77+
result += 1
78+
} else if (char !== '·') {
79+
return -1
80+
}
81+
}
82+
return result
83+
}
84+
85+
private maxUnicodeLength(cipherUnicodes: number[]) {
86+
let length = 1
87+
let max = 1
88+
cipherUnicodes.forEach(unicode => {
89+
while (max < unicode) {
90+
max <<= 1
91+
max += 1
92+
length++
93+
}
94+
})
95+
return length
2196
}
2297
}

src/zero/cryptor/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cryptorConfig from "../cryptor-config"
22
import Cryptor1 from './cryptor1'
33
import Cryptor2 from './cryptor2'
4+
import Cryptor3 from "./cryptor3"
45

56
/**
67
* The set of cryptors with different version
@@ -15,7 +16,8 @@ class CryptorComposite {
1516

1617
constructor() {
1718
this.register(new Cryptor1())
18-
this.latest = this.register(new Cryptor2())
19+
this.register(new Cryptor2())
20+
this.latest = this.register(new Cryptor3())
1921
}
2022

2123
private register(cryptor: ICryptor): ICryptor {

0 commit comments

Comments
 (0)