sk_dkim

Crates.iosk_dkim
lib.rssk_dkim
version0.1.7
created_at2025-12-01 12:53:07.997975+00
updated_at2025-12-04 07:58:17.523768+00
descriptionDeterministic DKIM key generation based on secret key / 基于密钥的确定性 DKIM 密钥生成
homepagehttps://github.com/js0-site/rust/tree/main/sk_dkim
repositoryhttps://github.com/js0-site/rust.git
max_upload_size
id1959745
size59,275
i18n.site (i18nsite)

documentation

README

English | 中文


sk_dkim : Deterministic DKIM Key Generation

Table of Contents

Introduction

sk_dkim is a Rust library designed to generate DomainKeys Identified Mail (DKIM) keys and DNS TXT records deterministically. Instead of managing and storing private key files for every domain, you can derive the necessary RSA 2048 keys on-the-fly using a single secret seed (Secret Key) combined with the domain name and selector.

This approach simplifies key management, especially for services managing DKIM for multiple domains, as it eliminates the need for stateful storage of private keys.

Why RSA? (The Sad State of Ed25519 Support)

Technically, Ed25519 is superior to RSA in almost every way for DKIM:

  • Size: Ed25519 public keys are tiny (32 bytes), fitting easily into a single DNS TXT record. RSA 2048 keys are huge and often require splitting across multiple strings in a TXT record.
  • Performance: Ed25519 signing and verification are incredibly fast.
  • Security: Ed25519 offers high security with smaller key sizes.

RFC 8463, published in 2018, explicitly states that verifiers MUST implement Ed25519 verification. However, the reality of the email ecosystem in 2024/2025 is a disappointing display of non-compliance by the industry giants:

  • Gmail: Support is inconsistent at best. While they claim some support, verification frequently fails for inbound emails signed with Ed25519.
  • Outlook / Microsoft 365: They consistently fail to verify Ed25519 signatures. If you send an email to an Outlook/Hotmail address with only an Ed25519 signature, it will likely be treated as unsigned or fail authentication.
  • Yahoo: Similar to Microsoft, Yahoo Mail typically fails to verify inbound Ed25519 DKIM signatures.

Despite the standard being over 6 years old, these major providers have effectively ignored the "MUST implement" clause for verification. While some experts recommend "dual signing" (signing with both RSA and Ed25519), this adds significant complexity and bloat to headers.

Because of this widespread lack of support, sk_dkim was forced to switch from Ed25519 to RSA 2048. We had to compromise on elegance and efficiency to ensure deliverability in the real world. It's a step backward in technology, but a necessary one for practical usage.

Usage

Add sk_dkim to your Cargo.toml:

[dependencies]
sk_dkim = { version = "0.1.5", features = ["pk"] }

Note: The pk feature is required to generate the formatted TXT record string.

Example

use sk_dkim::Sk;

fn main() {
    // Your secret seed (keep this safe!)
    let secret_seed = "your_secret_seed_string";
    
    // Initialize the generator with the seed
    let sk = Sk::new(secret_seed);

    let selector = "default";
    let domain = "example.com";

    // Generate the DKIM struct for the specific domain and selector
    let dkim = sk.dkim(selector, domain);

    // Get the DNS TXT record value
    // Output format: v=DKIM1; k=rsa; p=...
    println!("DKIM Record: {}", dkim.txt());
}

Design

The core philosophy of sk_dkim is determinism.

  1. Initialization: The Sk struct is initialized with a base secret seed. This seed initializes a BLAKE3 hasher.
  2. Derivation: When dkim(selector, domain) is called, the hasher is cloned and updated with the selector and domain.
  3. Key Generation: The final hash digest is used to seed a ChaCha20Rng, which then generates a deterministic RSA 2048 key pair.
  4. Output: The public part of the key is encoded in Base64 (SPKI format) and formatted into a standard DKIM TXT record.

This process ensures that as long as the secret seed remains constant, the generated DKIM keys for any given domain will always be the same.

API Reference

struct Sk

The main entry point for key generation.

  • Sk::new(sk: impl AsRef<[u8]>) -> Self Creates a new Sk instance using the provided secret seed.

  • Sk::dkim(&self, selector: impl AsRef<str>, domain: impl AsRef<str>) -> Dkim Derives a Dkim instance for the specified selector (selector) and domain (domain).

struct Dkim

Represents the generated DKIM key pair.

  • pub sk: rsa::RsaPrivateKey The underlying RSA private key.

  • Dkim::txt(&self) -> String (Requires pk feature) Returns the formatted DKIM DNS TXT record string (e.g., v=DKIM1; k=rsa; p=...).

Tech Stack

  • Rust: Core language.
  • rsa: Pure Rust implementation of RSA.
  • rand_chacha: Cryptographically secure random number generator (ChaCha20) used for deterministic key generation from the seed.
  • blake3: Cryptographic hashing for deterministic seed derivation.
  • base64: Encoding the public key for DNS records.

Directory Structure

.
├── Cargo.toml      # Project configuration and dependencies
├── readme/         # Documentation
│   ├── en.md       # English README
│   └── zh.md       # Chinese README
├── src/            # Source code
│   └── lib.rs      # Library entry point and implementation
├── tests/          # Integration tests
│   └── main.rs     # Usage demonstration and testing
└── test.sh         # Test execution script

About

This project is an open-source component of js0.site ⋅ Refactoring the Internet Plan.

We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:


sk_dkim : 基于密钥的确定性 DKIM 密钥生成

目录

简介

sk_dkim 是一个 Rust 库,用于确定性地生成 DomainKeys Identified Mail (DKIM) 密钥和 DNS TXT 记录。无需为每个域名单独管理和存储私钥文件,只需使用一个主密钥种子 (Secret Key),结合域名和选择器 (Selector),即可实时派生出所需的 RSA 2048 密钥。

这种方法极大地简化了密钥管理,特别是对于需要为大量域名提供 DKIM 签名的服务,彻底消除了对私钥状态存储的需求。

为什么是 RSA?(Ed25519 的悲惨现状)

从技术角度来看,Ed25519 在 DKIM 应用中几乎全方位优于 RSA:

  • 体积小:Ed25519 公钥仅 32 字节,可以轻松放入单条 DNS TXT 记录中。而 RSA 2048 公钥非常庞大,通常需要分割成多个字符串才能存入 TXT 记录。
  • 高性能:Ed25519 的签名和验证速度极快。
  • 安全性:Ed25519 在较小的密钥尺寸下提供了极高的安全性。

RFC 8463 早在 2018 年 就已发布,其中明确规定验证者 必须 (MUST) 实现 Ed25519 验证。然而,到了 2024/2025 年,电子邮件生态系统的现状却是行业巨头们集体违规的失望展示:

  • Gmail: 支持情况极不稳定。虽然声称支持,但对于使用 Ed25519 签名的入站邮件,验证经常失败。
  • Outlook / Microsoft 365: 它们 始终无法 验证 Ed25519 签名。如果你只用 Ed25519 签名发送邮件给 Outlook/Hotmail 用户,邮件很可能会被视为未签名或验证失败。
  • Yahoo: 与微软类似,Yahoo 邮箱通常也无法验证入站的 Ed25519 DKIM 签名。

尽管该标准已经发布超过 6 年,这些主要服务商实际上完全无视了验证方面的 "MUST implement" 条款。虽然一些专家建议 "双重签名"(同时使用 RSA 和 Ed25519 签名),但这会显著增加复杂性和邮件头的臃肿程度。

正是由于这种广泛的缺乏支持,sk_dkim 被迫从 Ed25519 切换回 RSA 2048。为了确保邮件在现实世界中的可达性,我们不得不牺牲优雅和效率。这是技术的倒退,但在当前环境下却是无奈且必须的选择。

使用方法

Cargo.toml 中添加 sk_dkim

[dependencies]
sk_dkim = { version = "0.1.5", features = ["pk"] }

注意:生成格式化的 TXT 记录字符串需要开启 pk 特性。

演示代码

use sk_dkim::Sk;

fn main() {
    // 主密钥种子 (请务必妥善保管)
    let secret_seed = "your_secret_seed_string";
    
    // 使用种子初始化生成器
    let sk = Sk::new(secret_seed);

    let selector = "default";
    let domain = "example.com";

    // 为特定域名和选择器生成 DKIM 结构
    let dkim = sk.dkim(selector, domain);

    // 获取 DNS TXT 记录值
    // 输出格式: v=DKIM1; k=rsa; p=...
    println!("DKIM Record: {}", dkim.txt());
}

设计思路

sk_dkim 的核心理念是确定性

  1. 初始化Sk 结构体使用基础的主密钥种子进行初始化。该种子用于初始化一个 BLAKE3 哈希器。
  2. 派生:调用 dkim(selector, domain) 时,克隆哈希器并利用 selectordomain 更新哈希状态。
  3. 密钥生成:最终的哈希摘要作为种子,用于初始化 ChaCha20Rng,进而生成确定性的 RSA 2048 密钥对。
  4. 输出:公钥部分经过 Base64 编码 (SPKI 格式),并格式化为标准的 DKIM TXT 记录。

此流程确保只要主密钥种子保持不变,对于给定的域名,生成的 DKIM 密钥将始终一致。

API 参考

struct Sk

密钥生成的主要入口点。

  • Sk::new(sk: impl AsRef<[u8]>) -> Self 使用提供的主密钥种子创建一个新的 Sk 实例。

  • Sk::dkim(&self, selector: impl AsRef<str>, domain: impl AsRef<str>) -> Dkim 为指定的选择器 (selector) 和域名 (domain) 派生一个 Dkim 实例。

struct Dkim

表示生成的 DKIM 密钥对。

  • pub sk: rsa::RsaPrivateKey 底层的 RSA 私钥。

  • Dkim::txt(&self) -> String (需要 pk 特性) 返回格式化的 DKIM DNS TXT 记录字符串 (例如 v=DKIM1; k=rsa; p=...)。

技术栈

  • Rust: 核心开发语言。
  • rsa: 纯 Rust 实现的 RSA 算法。
  • rand_chacha: 加密安全的随机数生成器 (ChaCha20),用于从种子生成确定性密钥。
  • blake3: 用于确定性密钥派生的加密哈希算法。
  • base64: 用于 DNS 记录的公钥编码。

目录结构

.
├── Cargo.toml      # 项目配置与依赖
├── readme/         # 文档目录
│   ├── en.md       # 英文说明文档
│   └── zh.md       # 中文说明文档
├── src/            # 源代码
│   └── lib.rs      # 库入口与实现
├── tests/          # 集成测试
│   └── main.rs     # 使用演示与测试
└── test.sh         # 测试执行脚本

关于

本项目为 js0.site ⋅ 重构互联网计划 的开源组件。

我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注:

Commit count: 1

cargo fmt