> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Crypto —— AT Protocol 加密

> Laravel Bluesky 包的 Crypto 模块。介绍 P-256 / secp256k1 密钥对、DID key、JWT、DPoP，以及签名格式转换。

<Warning>
  Crypto 是较为底层的内部实现。一般的发帖、feed 获取、通知等场景并不需要它。只有当你要构建 AT Protocol 底层签名校验或 OAuth 实现时才需要参考本页。
</Warning>

## AT Protocol 加密体系概览

为了实现分布式社交网络，AT Protocol 全面采用了椭圆曲线加密（ECC）。主要用途如下。

```mermaid theme={null}
graph TD
    A["密钥对<br>(P-256 / secp256k1)"] --> B["用私钥签名"]
    A --> C["把公钥编码为 did:key"]
    B --> D["DPoP token (OAuth)"]
    B --> E["Commit 签名（仓库）"]
    B --> F["Label 签名（Labeler）"]
    C --> G["注册到 DID Document"]
    G --> H["用公钥校验签名"]
```

| 曲线                | 算法     | 主要用途                         |
| ----------------- | ------ | ---------------------------- |
| secp256r1 (P-256) | ES256  | OAuth（DPoP、Client Assertion） |
| secp256k1 (K256)  | ES256K | Feed Generator、Labeler 的签名校验 |

***

## 密钥对类

### AbstractKeypair

`AbstractKeypair` 是 P256 / K256 共同的基类。内部使用 [phpseclib3](https://phpseclib.com/)。

```php theme={null}
// 生成新的密钥对
$keypair = P256::create();
$keypair = K256::create();

// 从 URL-safe Base64 编码的私钥加载
$keypair = P256::load($base64PrivateKey);

// 获取 PEM 格式
$privatePem = $keypair->privatePEM();
$publicPem  = $keypair->publicPEM();

// 转换为 JWK (JSON Web Key)
$jwk = $keypair->toJWK();
```

### P256 (secp256r1)

```php theme={null}
use Revolution\Bluesky\Crypto\P256;

$keypair = P256::create();
```

在 OAuth（DPoP / Client Assertion）中使用。`OAuthKey` 继承自 P256，会从 `config('bluesky.oauth.private_key')` 加载私钥。

包中也提供了用于生成新 OAuth 私钥的 Artisan 命令。

```bash theme={null}
php artisan bluesky:new-private-key
```

### K256 (secp256k1)

```php theme={null}
use Revolution\Bluesky\Crypto\K256;

$keypair = K256::create();
```

用于 Feed Generator 和 Labeler 的认证。Bluesky 的 PDS / Relay 会使用此曲线校验签名。

***

## DidKey

`DidKey` 类负责将公钥在 `did:key` 格式之间进行编解码。

### 什么是 did:key 格式

AT Protocol 用形如 `did:key:z...` 的字符串来表示公钥。它是在公钥之前加上曲线标识后，再用 Base58btc 做 multibase 编码得到的。

```mermaid theme={null}
graph LR
    A["公钥 (PEM)"] --> B["曲线标识 + 压缩公钥"]
    B --> C["Base58btc 编码"]
    C --> D["did:key:z..."]
```

### 将公钥编码为 did:key

```php theme={null}
use Revolution\Bluesky\Crypto\DidKey;
use Revolution\Bluesky\Crypto\K256;

$keypair = K256::create();
$publicPem = $keypair->publicPEM();

// 转为 did:key 格式
$didKey = DidKey::format($publicPem);
// => "did:key:zQ3s..."
```

### 从 DID Document 解析公钥

```php theme={null}
use Revolution\Bluesky\Crypto\DidKey;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Support\DidDocument;

$didDoc = DidDocument::make(
    Bluesky::identity()->resolveDID('did:plc:***')->json()
);

// 从 DID Document 的 publicKey (multibase) 生成 phpseclib3 的公钥对象
$publicKey = DidKey::parse($didDoc->publicKey());
```

***

## JsonWebToken (JWT)

`JsonWebToken` 类提供了 JWT 的编解码。

```php theme={null}
use Revolution\Bluesky\Crypto\JsonWebToken;

// 生成 JWT（用 PEM 私钥签名）
$token = JsonWebToken::encode(
    payload: ['iss' => 'did:plc:***', 'aud' => 'https://bsky.social', 'exp' => time() + 60],
    key: $privatePem,
    alg: 'ES256',
);

// 解码 JWT（不做签名校验）
$payload = JsonWebToken::decode($token);
```

***

## DPoP (Demonstrated Proof of Possession)

DPoP 是一种把 OAuth access token 绑定到特定客户端密钥对上的安全机制，用于防止 token 被重放攻击。

```mermaid theme={null}
sequenceDiagram
    participant App as Laravel 应用
    participant AS as Authorization Server
    participant RS as Resource Server

    App->>AS: PAR 请求（+ DPoP header）
    AS-->>App: request_uri
    App->>AS: token 请求（+ DPoP header）
    AS-->>App: access token (DPoP bound)
    App->>RS: API 请求（+ DPoP header + ath）
    RS-->>App: 响应
```

`DPoP` 类是内部使用的，通常不需要直接调用。`OAuthAgent` 中间件会自动附加 DPoP header。

```php theme={null}
// 生成 DPoP proof（用于 OAuth token 请求）
$proof = DPoP::authProof(
    jwk: $jsonWebKey,
    url: 'https://bsky.social/oauth/token',
    method: 'POST',
    nonce: $nonce,
);

// 生成 DPoP proof（用于 API 请求，包含 ath）
$proof = DPoP::apiProof(
    jwk: $jsonWebKey,
    url: 'https://api.bsky.app/xrpc/...',
    method: 'GET',
    token: $accessToken,
    nonce: $nonce,
);
```

***

## Signature（签名格式转换）

AT Protocol 使用 64 字节的紧凑签名格式，而 phpseclib3 返回的是 ASN.1 DER 格式。`Signature` 类负责它们之间的转换。

```php theme={null}
use Revolution\Bluesky\Crypto\Signature;

// ASN.1 DER → compact（64 字节）
$compact = Signature::toCompact($derSignature);

// compact → ASN.1 DER
$der = Signature::fromCompact($compactSignature);
```

***

## JsonWebKey

`JsonWebKey` 是表示 JWK (JSON Web Key) 的类，用于生成 DPoP proof。

```php theme={null}
use Revolution\Bluesky\Crypto\JsonWebKey;

// 从密钥对生成 JWK
$jwk = $keypair->toJWK();

// 或者直接实例化
$jwk = JsonWebKey::load(['kty' => 'EC', 'crv' => 'P-256', ...]);
```

***

## OAuthKey

`OAuthKey` 是继承自 P256、专门用于 OAuth 的密钥类，会将 `config('bluesky.oauth.private_key')` 的值作为私钥使用。

```php theme={null}
use Revolution\Bluesky\Crypto\OAuthKey;

// 从配置中加载私钥
$oauthKey = OAuthKey::load();

// 用于对 Client Assertion JWT 进行签名
$jwk = $oauthKey->toJWK();
```

一般情况下，这些操作都会由 Bluesky Socialite 内部自动完成。

***

## 参考链接

* [AT Protocol: Identity](https://atproto.com/guides/identity)
* [AT Protocol: Cryptography spec](https://atproto.com/specs/cryptography)
* [phpseclib3](https://phpseclib.com/)

<Info>
  Source: [src/Crypto/](https://github.com/invokable/laravel-bluesky/tree/main/src/Crypto)
</Info>


## Related topics

- [加密（Encryption）](/zh/encryption.md)
- [配置](/zh/configuration.md)
- [教程 - Laravel Console Starter](/zh/packages/laravel-console-starter/tutorial.md)
- [Redis](/zh/redis.md)
- [OAuth 2.0 认证 - Google Sheets API for Laravel](/zh/packages/laravel-google-sheets/oauth.md)
