1 个不稳定版本

使用旧的 Rust 2015

0.3.1 2020年2月5日

#1137 in 密码学

BSD-2-Clause

120KB
2.5K SLoC

[[enprot]]

Engyon: enprot

"Build Status", link="https://github.com/riboseinc/enprot/actions?workflow=tests"

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.1file.2等,并将它们写入目录output(如果存在)。但是

[源代码,sh]

enprot$ ./target/debug/enprot -p output file.*

将生成文件outputfile.1outputfile.2等。

密码学:对称认证加密

由于其最小的消息扩展和数据加密的非顺序性,使用具有关联数据的认证加密(AEAD)机制,该机制具有防重放/误用特性。我们选择使用AES-256在SIV(合成初始化向量)模式下[RFC5297]。SIV密文始终比明文大16字节,16字节的认证标签也充当“synthetic IV”。

所有CAS的哈希函数计算都使用SHA-3 [FIPS202]变体。它也用于从密码中派生密钥材料。

依赖关系

~6MB
~114K SLoC