1 个不稳定版本
使用旧的 Rust 2015
0.3.1 | 2020年2月5日 |
---|
#1137 in 密码学
120KB
2.5K SLoC
[[enprot]]
Engyon: enprot
Enprot 是用于文本和源代码文件的机密性处理器。
介绍和教程
Engyon 保护文本 (EPT) 是一种人类可编辑的注释方法,允许文本格式文档包含细粒度的密码学机密性和完整性特性。
Enprot 需要 botan 的最新版本。使用 cargo build --release
构建发布二进制文件 target/release/enprot
或使用 cargo run --
构建和运行调试版本。某些依赖项可能需要最新的编译器。
内置了简单的帮助,带有 -h
标志
[源代码,sh]
enprot$ cargo run -- -h
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/enprot -h`
enprot
USAGE:
enprot [FLAGS] [OPTIONS] <FILE>...
FLAGS:
-v, --verbose Produce more verbose output
-q, --quiet Suppress unnecessary output
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-l, --left-separator <SEP> Specify left separator in parsing
-r, --right-separator <SEP> Specify right separator in parsing
-s, --store <WORD>... Store (unencrypted) WORD segments to CAS
-f, --fetch <WORD>... Fetch (unencrypted) WORD segments to CAS
-k, --key <WORD=PASSWORD>... Specify a secret PASSWORD for WORD
-e, --encrypt <WORD>... Encrypt WORD segments
-E, --encrypt-store <WORD>... Encrypt and store WORD segments
-d, --decrypt <WORD>... Decrypt WORD segments
-c, --casdir <DIRECTORY> Directory for CAS files (default "cas" if exists, else ".")
-p, --prefix <PREFIX> Use PREFIX for output filenames
-o, --output <FILE>... Specify output file for previous input
ARGS:
<FILE>... The input file(s)
enprot$
所有命令也有长版本;请参阅 src/main.rs
。
一个简单的示例包含在 sample/test.ept
hello, this is a test file
// <( BEGIN GEHEIM )>
Secret line 1
Secret line 2
// <( BEGIN Agent_007 )>
James Bond
// <( END Agent_007 )>
// <( END GEHEIM )>
// <( BEGIN Agent_007 )>
Super secret line 3
// <( END Agent_007 )>
如所见,最基础的 EPT 标记位于 "host
" 语言(在这种情况下是 C 或 AsciiDoc)的注释中,并由 BEGIN..END 段组成。每个此类段都有一个与之关联的关键字(或 WORD)。关键字可以用于其他关键字内部,以形成树状结构。
当在语法正确的文件上调用 enprot
时,没有任何操作
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept
enprot$
实际上,标记已被特别选择,以便大多数输入文件无需修改即可语法正确。标记位于可以与 -l
和 -r
标志指定的左右分隔符之间。以下是不同语言的注释隐藏建议
|=== | 格式 | LEFT_SEP
| RIGHT_SEP
| 原始文本格式 | "<("
, | ")>"
| AsciiDoc 和 C++ 代码 | "// <("
| ")>"
| MarkDown、XML、HTML | "<-- <("
| ")> -->"
| (La)TeX 及其类似 | "\n% <("
| ")>"
|===
请注意,左侧分隔符必须从行首开始(在空白之后)。右侧分隔符目前也必须在同一行上。使用 -v
添加冗余可以显示系统正在做什么
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -v
LEFT_SEP='// <(' RIGHT_SEP=')>' casdir = 'cas'
Reading sample/test.ept
Transforming sample/test.ept
Writing sample/test.ept
enprot$
我们看到左右分隔符的默认设置。此外,我们还可以看到文件被读取(解析),转换(在本例中为空操作),然后写回(合成),覆盖原始文件。这种转换行为由多个标志控制(如前所述)。
内容寻址存储
在上面的例子中我们看到 casdir = 'cas'
。这意味着 CAS(内容寻址存储)的默认目录是当前目录下的 cas
。如果您还没有设置 cas
目录,这些工作文件将被写入当前目录。这本身并不是问题,但会产生杂乱。我们建议您执行 mkdir cas
。
CAS 的操作可以通过使用 -s
(存储)标志来简单演示,它将文本文件的一部分隐藏(清理)起来。
enprot$ ./target/debug/enprot sample/test.ept -s GEHEIM
enprot$ cat sample/test.ept
hello, this is a test file
// <( STORED GEHEIM cea67c3ef34ff899793b557e9178c1b97bbcfe9722df2f6d35d2d0c91d2c1fe4 )>
// <( BEGIN Agent_007 )>
Super secret line 3
// <( END Agent_007 )>
enprot$ ls cas
cea67c3ef34ff899793b557e9178c1b97bbcfe9722df2f6d35d2d0c91d2c1fe4
enprot$
我们可以看到 BEGIN GEHEIM 和 END GEHEIM 之间的整个部分已经消失,并被单个 STORED GEHEIM 替换。实际上,这些内容被存储在一个具有长十六进制文件名的文件中。加密函数的性质保证了不同的内容不可能具有相同的哈希值。这解决了版本控制的大部分问题,因为可以通过内容直接引用文件。
现在可以发送此文件进行编辑,并可以在 GEHEIM 部分周围添加新文本。如果原始 CAS 文件仍然存在,可以通过简单的 -f
(获取)指令恢复隐藏的部分
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -f GEHEIM
现在 test.ept
的内容与之前完全相同,GEHEIM 部分再次包含在 BEGIN.. END 封闭中。
使用所有参数,多个关键词可以通过逗号连接
[源代码,sh]
enprot sample/test.ept -s Agent_007,GEHEIM
enprot$ cat sample/test.ept
hello, this is a test file
// <( STORED GEHEIM cea67c3ef34ff899793b557e9178c1b97bbcfe9722df2f6d35d2d0c91d2c1fe4 )>
// <( STORED Agent_007 575d69f5b0034279bc3ef164e94287e6366e9df76729895a302a66a8817cf306 )>
enprot$
我们看到第一个 GEHEIM 再次存储在相同的文件名下。实际上,系统检查到 CAS 目录中已经存在同名文件,因此没有必要进行覆盖。
这种确定性是 CAS 的一个重要特性。即使您失去了与文档某些清理版本相关的 CAS 文件,如果您有原始的非清理文档,您也可以重新生成完全相同的文件。
现在可以使用以下命令恢复原始文档
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -f Agent_007 -f notexistent,GEHEIM
您可以看到-f
参数可以多次给出。事实上,如果要在保留某些关键字的同时清理其他关键字,甚至可以在同一个命令中混合使用-s
和-f
语句。但是,对于相同的关键字同时指定-s
和-f
并不是很有帮助;该关键字将在交替运行中被清理和重新清理。
加密和解密
我们可以以保持密文完全位于文档本身的方式加密部分。假设sample/test.ept
处于原始状态
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -e Agent_007
Password for Agent_007:
Repeat password for Agent_007:
enprot$ cat sample/test.ept
hello, this is a test file
// <( BEGIN GEHEIM )>
Secret line 1
Secret line 2
// <( ENCRYPTED Agent_007 )>
// <( DATA lEsVpN3ES6rj0sbxrDm30EgMpYCc+yKM2i2Z )>
// <( END Agent_007 )>
// <( END GEHEIM )>
// <( ENCRYPTED Agent_007 )>
// <( DATA C0nBhV6V5yVExLOgvpK8xzUluc08lsr7wwBhx4ENMDrJU3pA )>
// <( END Agent_007 )>
enprot$
在上面的示例中,我在两个密码提示中输入了“bond”。密钥也可以通过带有-k
标志的命令行传递
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -e GEHEIM -k GEHEIM=james
enprot$ cat sample/test.ept
hello, this is a test file
// <( ENCRYPTED GEHEIM )>
// <( DATA 4reYea85vTqNzzf7eon3x/LHs6iLy3GPgSZvsX7l0MhqdVnuIe5y3poxqvQxFqYT )>
// <( DATA B1np55+m8WlPDtzMt+SMPEyfPIKAeqo+tAWS7ftfJmAqSswibIqRJh0jXO6nBDvK )>
// <( DATA 4EclPifsb89G2i5vu8dfFkmQT8uj2o71UAohLPeY8vX2qksDJGm99pzZwm5hoXUm )>
// <( DATA VVYf )>
// <( END GEHEIM )>
// <( ENCRYPTED Agent_007 )>
// <( DATA C0nBhV6V5yVExLOgvpK8xzUluc08lsr7wwBhx4ENMDrJU3pA )>
// <( END Agent_007 )>
enprot$
可以使用-
命令以完全相同的方式执行解密
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -d Agent_007,GEHEIM -k GEHEIM=james -k Agent_007=bond
enprot$ cat sample/test.ept
hello, this is a test file
// <( BEGIN GEHEIM )>
Secret line 1
Secret line 2
// <( ENCRYPTED Agent_007 )>
// <( DATA lEsVpN3ES6rj0sbxrDm30EgMpYCc+yKM2i2Z )>
// <( END Agent_007 )>
// <( END GEHEIM )>
// <( BEGIN Agent_007 )>
Super secret line 3
// <( END Agent_007 )>
enprot%
我们看到,从GEHEIM中移除了仅一层加密。您可以使用完全相同的命令进行第二次迭代,以显示原始文件。
源代码工作
系统允许在文本格式文档上进行工作,也可以在程序源代码上进行工作。例如,Enprot的源代码在其帮助信息中有一个加密的部分
[源代码,sh]
enprot$ ./target/debug/enprot -d AUTHOR -k AUTHOR=markku src/lib.rs
enprot$ cargo run -- -h
Compiling enprot v0.1.0 (file:///home/mjos/Desktop/lab/enprot)
Finished dev [unoptimized + debuginfo] target(s) in 2.17s
Running `target/debug/enprot -h`
Written 2018 by Markku-Juhani O. Saarinen <mjos@iki.fi>
[...]
enprot$
注意,当cargo重新编译源代码时(因为它已被“触摸”),作者信息出现在帮助文本的末尾。这是因为一些源行最初是
// <( ENCRYPTED AUTHOR )>
// <( DATA X417HVMRRAs6Z1xGo5yY4TxUQ2tpAHEKQ1sg9+kfku5uUikK3y2tODtsUiGqfRGW )>
// <( DATA xUCGYFu02BCdqPM7uuX5UNvbfrLvKkj6gLYwg/cr42PJmr4o5xnw1qo= )>
// <( END AUTHOR )>
这被解密为
// <( BEGIN AUTHOR )>
println!("Written 2018 by Markku-Juhani O. Saarinen <[email protected]>");
// <( END AUTHOR )>
没有修改源代码中的其他内容。
加密存储
如果我们结合加密-WORD
和CAS存储-WORD
,则密文以加密形式存储到CAS中。可以使用-
标志同时指定这两个谓词。
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -E GEHEIM
Password for GEHEIM:
Repeat password for GEHEIM:
enprot$ cat sample/test.ept
hello, this is a test file
// <( ENCRYPTED GEHEIM 12d24bf3dbebfe5feb7684efdb1d98391c4b0afd809a8bc87f3f8e6f75e59651 )>
// <( BEGIN Agent_007 )>
Super secret line 3
// <( END Agent_007 )>
enprot$
我省略了-
定义,因此Enprot让我输入密码。当密文在CAS或本地DATA子句中时,-
标志将以相同的方式工作。
[源代码,sh]
enprot$ ./target/debug/enprot sample/test.ept -d GEHEIM
Password for GEHEIM:
enprot$
多文件处理
由于文件在原地转换,因此您可以使用通配符一次处理大量文件。您只需输入一次密码。
要处理文件并将其输出到不同的文件名,请使用-
[源代码,sh]
enprot$ ./target/debug/enprot input.ept -o output.ept
要将输出重定向到另一个目录或添加前缀标志-PREFIX
。前缀将直接添加到每个输出文件之前。请注意,如果输入文件名具有相对路径,则保持不变。
enprot$ ./target/debug/enprot -p output/ file.*
将读取文件file.1
、file.2等,并将它们写入目录
output
(如果存在)。但是
[源代码,sh]
enprot$ ./target/debug/enprot -p output file.*
将生成文件outputfile.1
、outputfile.2等。
密码学:对称认证加密
由于其最小的消息扩展和数据加密的非顺序性,使用具有关联数据的认证加密(AEAD)机制,该机制具有防重放/误用特性。我们选择使用AES-256在SIV(合成初始化向量)模式下[RFC5297]。SIV密文始终比明文大16字节,16字节的认证标签也充当“synthetic IV
”。
所有CAS的哈希函数计算都使用SHA-3 [FIPS202]变体。它也用于从密码中派生密钥材料。
依赖关系
~6MB
~114K SLoC