# 数据加密

## 传输中数据加密

JuiceFS 在网络上传输时会对数据进行加密，以防止未经授权的用户窃听网络通信。

JuiceFS 客户端始终使用 HTTPS 把数据上传到对象存储服务，以下情况除外：

- 使用内部端点上传至阿里云 OSS
- 使用内部端点上传至 UCloud US3


## 静态数据加密

JuiceFS 支持静态数据加密，即在上传到对象存储之前对数据进行加密。在这种情况下，存储在对象存储中的数据将会被加密，这可以在对象存储本身被破坏时有效地防止数据泄露。

JuiceFS 在客户端加密中采用了行业标准的加密方式（AES-GCM 和 RSA）。加密和解密是在 JuiceFS 客户端进行的。用户唯一需要做的是在 JuiceFS 挂载时提供一个私人密钥或密码，并像普通文件系统一样使用它。它对应用程序是完全透明的。

> **注意**：在客户端缓存的数据是**不**加密的。不过，只有 root 用户或所有者可以访问这些数据。如果要把缓存的数据也加密，你可以把缓存目录放在一个加密的文件系统或块存储中。


### 加密和解密方法

必须为每个加密的文件系统创建一个全局 RSA 密钥 `M`。在对象存储中保存的每个对象都将有自己的随机对称密钥 `S`。数据用对称密钥 `S` 进行 AES-GCM 加密，`S` 用全局 RSA 密钥 `M` 进行加密，RSA 密钥使用用户指定的口令进行加密。

![Encryption At-rest](../images/encryption.png)

数据加密的详细过程如下：

- 在写入对象存储之前，数据块会使用 LZ4 或 ZStandard 进行压缩。
- 为每个块生成一个随机的 256 位对称密钥 `S` 和一个随机种子 `N`。
- 基于 AES-GCM 使用 `S` 和 `N` 对每个块进行加密。
- 使用 RSA 密钥 `M` 对对称密钥 `S` 进行加密得到密文 `K` 。
- 将加密后的数据、密文 `K` 和随机种子 `N` 组合成对象，然后写入对象存储。

数据解密的步骤如下：

- 读取整个加密对象（它可能比 4MB 大一点）。
- 解析对象数据得到密文 `K`、随机种子 `N` 和被加密的数据。
- 用 RSA 密钥解密 `K`，得到对称密钥 `S`。
- 基于 AES-GCM 使用 `S` 和 `N` 解密数据得到数据块明文。
- 对数据块解压缩。


### 密钥管理

在启用加密功能时，RSA 密钥的安全是极其重要的。如果密钥被泄露，可能会导致数据泄露。如果密钥丢失，那么**所有**的加密数据都将丢失，而且无法恢复。

当使用 `juicefs format` 创建一个新卷时，可以通过 `--encrypt-rsa-key` 参数指定 RSA 私钥来启用静态加密，该私钥将会被保存到 Redis。当私钥被密码保护时，可以使用环境变量 `JFS_RSA_PASSPHRASE` 来指定密码。

使用方法：

1. 生成 RSA 密钥

```shell
$ openssl genrsa -out my-priv-key.pem -aes256 2048
```

2. 在格式化时提供该密钥

```shell
$ juicefs format --encrypt-rsa-key my-priv-key.pem META-URL NAME
```

> **注意**：如果私钥受密码保护，在执行 `juicefs mount` 时应使用 `JFS_RSA_PASSPHRASE` 来指定该密码。


### 性能

TLS、HTTPS 和 AES-256 在现代 CPU 中的实现非常高效。因此，启用加密功能对文件系统的性能影响并不大。RSA 算法相对较慢，特别是解密过程。建议在存储加密中使用 2048 位 RSA 密钥。使用 4096 位密钥可能会对读取性能产生重大影响。
