Skip to content

Latest commit

 

History

History
171 lines (116 loc) · 7.78 KB

File metadata and controls

171 lines (116 loc) · 7.78 KB

utf8-ctc

标准电码,但使用UTF8作为回退编码。

English

什么是标准电码?为什么都20XX年了还要用它?

标准电码原本是用于在电报中传送中文信息的一种编码。它将常用字列表并指派唯一的四字编码。 例如字,它的编码是3352。它提供了一种更紧凑的编码中文的方式: 标准电码只需要2字节(实际取值为0000到9999),而UTF-8则平均使用3字节。

一般来说,UTF-8 是处理所有类型字符的最佳选择,但在讨论长度受限的编码时,标准电码就变得非常有用。

这个程序是做什么的?

这个程序是为明信片上的文本编码而编写的。而我们并不想使用base58来表示加密数据,但又希望获得一定程度的隐私。 因此,该程序将中文编码为标准电码,如果有字符缺失,则使用原始UTF-8编码或压缩UTF-8编码。

手写和输入数字要比base64或base58字符串简单得多。

程序是这样设计的:当书写明信片时,我通过命令行选项、文件或标准输入流将文字编码,这个程序将输出对应的 电码数字,我只需要将这些数字抄写到明信片上。

当其他人收到明信片后,他可以将这些数字原封不动的敲入程序,然后程序就会显示出解码的文字。

使用

这个程序使用jlink构建,搭配zulu 21 jdk,所以从技术上来说,你不需要在电脑上额外安装Java运行环境 就可以使用本程序。 前往发布页面,下载对应的构建版本,然后调用./ctc应该就万事大吉了。

目前还没有可用于作为依赖的发布。这个程序不是作为依赖编写的,我也没有将其作为依赖测试,因此 我不想让别人无意间将其作为依赖使用并造成灾难。你可以尝试使用jitpack,但我无法向你保证结果。

如果呼声很高的话,请创建一个Issue,我会将其作为一个依赖发布的。

编码

你可以使用命令行选项、文件和标准输入流进行编码:

./ctc encode -t "天匠染青红,花腰呈袅娜。"
./ctc encode -f message.txt
echo "天匠染青红,花腰呈袅娜。" | ./ctc encode -c UTF-8

-t-f选项同时出现时,-t <text>会覆盖-f <file>。 当你使用标准输入流时,除非关闭输入流,否则你需要手动告诉程序你写完了。在新的一行中输入EOF然后回车即可。

你也可以使用--eof=EOT选项来修改这个标志。这样你就可以使用EOT来代替EOF了。

你还可以修改每行打印多少个电码。但请务必知悉,这最终会受限于你终端的宽度,如果你设定的值太宽,则终端会断行。 默认情况下将适应你的终端,你可以通过-w 6来设置为每行6个。

当使用标准输入流时,在Windows系统上会有字符集的问题。 默认情况下程序使用UTF-8字符集进行输入输出。 但在Windows上,程序将在默认地区设置为zh-CN时使用GBK字符集; 或者在默认地区设置为zh-TW时使用BIG5字符集。 如果你不想要这个功能,你可以使用-c UTF-8来强制程序使用UTF-8字符集。

虽然程序支持台湾的BIG5字符集,但标准电码使用的是大陆的版本,因此所有字符将会被当成UTF-8编码。

请务必先验证程序的输出,再将数字抄写到明信片上。 有时如果你不仔细检查的话,字符集的问题会无意中打你个措手不及。

解码

解码和编码差不多,但是更简单。 解码时程序只用UTF-8,这在包括Windows在内的系统上的大多数终端都可以正常工作。

解码时有三个命令行选项:-t-f--eof

你可以输入任何字符,程序将会忽略他们并且只留下0到9的数字。所以如果你不小心输入了字母或其他东西, 不用担心,继续敲就好了。

./ctc decode -t "1131  0561  2676  7230  4767  9976  5363  5212  0701  5934  1226  9975   84"

加密

从v1.0.0版本开始,我移除了旧的置换加密,因为它不安全。 作为替代,我加入了使用ChaCha20流密码的加密。

ChaCha20流密码首先生成一系列伪编码,范围在0000到9999之间,记作key。 对于每个CTC编码结果,使用如下公式计算密文:

enc = (code + key) % 10000

解密时,使用同样的密钥和nonce将生成同样的伪编码系列:

code = (enc - key + 10000) % 10000

Nonce将在加密时生成,并必须在解密时通过命令行选项--nonce-n传入。

密钥(-k--key)会根据不同加密模式有不同的解读。

如果使用对称加密,则密钥将被按照utf8编码,并进行SHA3-256运算。 结果将作为ChaCha20流的密钥。

如果使用非对称加密,则密钥将被作为hex字符串解码,并且当作私钥。 公钥则同样按照hex字符串解码,从 --dh hex选项中取得。 然后使用X25519 ECDH算法计算共享密钥,最后应用SHA3-256运算。 结果将作为ChaCha20流的密钥。

对于非对称加密,要生成私钥,请用openssl rand -hex 32。 要查看对应的公钥,请用./ctc pubkey <your private key in hex>

启用加密时,程序会自动生成一个MAC摘要用以确保信息的完整性。 该摘要会在加密时自动生成,并必须在解密时通过命令行选项--mac-m传入。

内部设计

预处理

本程序在简单的查表和替换之上还有更复杂的预处理。 标准电码取自:https://en.wiktionary.org/wiki/Appendix:Chinese_telegraph_code/Mainland_1983

在开始编码之前,我们需要进行如下替换来获得更简短的编码:

  • 换行(\n)将被替换为(电码9999)
  • 类似10日的词将被替换为(电码9910)

这些操作将会减少一些电码,并且这种变换对用户是透明的。 在解码时将会应用它的逆变换来确保解码出来的问题是正确的。

UTF-8回退编码

当遇到标准电码中没有的字符时,程序将其存储在一个缓冲区中,并按批处理。 例如编码大家好,my name is XXX。时,未知缓冲区将是my name is XXX。 随后缓冲区内的数据将会按照UTF-8编码。编码后将会被LZMA2以最大等级压缩(字典大小256KB), 如果压缩后的长度小于原始长度,则使用压缩后的编码。

对于原始UTF-8编码,它将被包括在电码99929993之间。内容则是以0000到9991来表示。 表示的方法类似base9992但以纯数字形式表现。

对于压缩的UTF-8编码,它将被包括在电码99949995之间。内容的表示方法相同。

校验和

为了确保编码后的数据完整性,以及确保打字的时候没有出现错误, 我在编码后的每行输出后面追加了校验和。

比如,输入天匠染青红,花腰呈袅娜。所对应的编码是:

1131  0561  2676  7230
4767  9976  5363  5212
0701  5934  1226  9975

当打印每一行的输出时,程序将会在每行结尾追加ISO 7064 mod 97–10校验和。 因此实际输出是这样的(使用-w 4来指定每行打印4个电码):

1131  0561  2676  7230   17
4767  9976  5363  5212   92
0701  5934  1226  9975   62

***解码时,校验和是必须的。***如果你不知道校验和,或者校验和污损无法分辨,使用00代替(必须是两位)。 同时,换行也是必须的,因为解码时程序独立地校验每行数据,所以你不能将两行数据合并为一行。 你必须照原样输入(空白字符是允许的,他们会被自动忽略)。

贡献

欢迎任何贡献,但我无法保证你的PR会被接受。 如果有任何问题,可以创建一个Issue,但我无法保证一定会解答你的问题。

太长不看:我对于这个程序不给出任何保证,除非你付给我钱。