nichoth/simple-hpke

GitHub: nichoth/simple-hpke

基于 RFC 9180 的轻量级 JavaScript 混合公钥加密库,将密钥封装与 AES-GCM 消息加密简化为 seal/open 和 encrypt/decrypt 等极简接口。

Stars: 0 | Forks: 0

# 简单 HPKE [![tests](https://img.shields.io/github/actions/workflow/status/nichoth/simple-hpke/nodejs.yml?style=flat-square)](https://github.com/nichoth/simple-hpke/actions/workflows/nodejs.yml) [![types](https://img.shields.io/npm/types/@substrate-system/simple-hpke?style=flat-square)](README.md) [![module](https://img.shields.io/badge/module-ESM%2FCJS-blue?style=flat-square)](README.md) [![semantic versioning](https://img.shields.io/badge/semver-2.0.0-blue?logo=semver&style=flat-square)](https://semver.org/) [![Common Changelog](https://nichoth.github.io/badge/common-changelog.svg)](./CHANGELOG.md) [![install size](https://flat.badgen.net/packagephobia/install/@substrate-system/simple-hpke)](https://packagephobia.com/result?p=@substrate-system/simple-hpke) [![gzip size](https://flat.badgen.net/bundlephobia/minzip/@substrate-system/simple-hpke)](https://bundlephobia.com/package/@substrate-system/simple-hpke) [![license](https://img.shields.io/badge/license-Big_Time-blue?style=flat-square)](LICENSE) 混合公钥加密 ([RFC 9180](https://www.rfc-editor.org/rfc/rfc9180.html)) 1 个依赖项 —— `uint8arrays`。

目录

- [安装](#install) - [示例](#example) * [密钥封装](#key-wrapping) * [混合加密](#hybrid-encryption) + [加密 / 解密](#encrypt--decrypt) - [`encrypt`](#encrypt) - [加密为字符串](#encrypt-to-a-string) - [`decrypt`](#decrypt) - [模块](#modules) * [ESM](#esm) * [Common JS](#common-js) * [预构建 JS](#pre-built-js) + [复制](#copy) + [HTML](#html)
## 安装 ``` npm i -S @substrate-system/simple-hpke ``` ## 示例 封装一个 AES 密钥,或加密一条消息。 ### 密钥封装 将一个 AES 密钥加密给你自己,以便日后恢复。 ``` import { seal, open } from '@substrate-system/simple-hpke' // An X25519 keypair. The private key can be non-extractable. // HPKE needs only `deriveBits`. const keypair = await crypto.subtle.generateKey( { name: 'X25519' }, false, // extractable ['deriveBits'] ) // create a new AES key, and encrypt it to your public key. const { wrapped, key } = await seal(keypair) // Or wrap an existing AES key. The supplied key must be extractable. const aesKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, // extractable ['encrypt', 'decrypt'] ) // if you pass in a key, the return value is just the wrapped key const { wrapped } = await seal(keypair, aesKey) // Later, recover the same key with your private key. const recoveredKey = await open(keypair, wrapped) ``` 完整的 API 和原理请参阅 [docs/README.md](./docs/README.md)。 ### 混合加密 封装一个密钥,然后使用它通过 AES-GCM 加密一条消息。 封装后的密钥会与密文以及 IV 拼接在一起。 接收者使用其私钥打开 AES 密钥并解密消息。 ``` import { seal, open } from '@substrate-system/simple-hpke' const recipient = await crypto.subtle.generateKey( { name: 'X25519' }, false, // not extractable ['deriveBits'] ) // Create and seal a fresh AES-GCM key, and encrypt a message with it. const { wrapped, key } = await seal(recipient) const iv = crypto.getRandomValues(new Uint8Array(12)) const ciphertext = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, key, new TextEncoder().encode('attack at dawn') ) // Send `wrapped`, `iv`, and `ciphertext` together. `wrapped` is a fixed // 80 bytes for this suite, and the AES-GCM IV is 12 bytes, so the recipient // can slice the payload back apart at known offsets. const ciphertext = new Uint8Array(ciphertext) const message = new Uint8Array(wrapped.length + iv.length + ciphertext.length) message.set(wrapped, 0) message.set(iv, wrapped.length) message.set(ciphertext, wrapped.length + iv.length) // On the other side, split the payload back into its parts. const wrapped2 = message.subarray(0, 80) const iv2 = message.subarray(80, 80 + 12) const ciphertext2 = message.subarray(80 + 12) // Recover the key, then decrypt the message. const recovered = await open(recipient, wrapped2) const plaintext = await crypto.subtle.decrypt( { name: 'AES-GCM', iv: iv2 }, recovered, ciphertext2 ) new TextDecoder().decode(plaintext) // => 'attack at dawn' ``` #### 加密 / 解密 加密和解密一条消息需要这么多代码…… 这个包暴露了 `encrypt` 和 `decrypt` 函数,它们做的是同样的事情。 `encrypt` 将一个 AES 密钥封装给接收者,使用该密钥加密消息, 并返回一个单一的信封:`wrappedLen + wrapped + iv + ciphertext` (一个 2 字节的长度前缀、封装的密钥、12 字节的 AES-GCM IV, 以及密文)。`decrypt` 执行相反的操作,返回明文字节。 ``` import { encrypt, decrypt } from '@substrate-system/simple-hpke' // need a public key for the recipient const recipient = await crypto.subtle.generateKey( { name: 'X25519' }, false, ['deriveBits'] ) // create a new AES key, encrypt a message, and get back one envelope const encryptedMessage = await encrypt(recipient, 'hello encryption') // the recipient recovers the message with their private key const text = await decrypt.asString(recipient, encryptedMessage) // use `decrypt` to get a Uint8Array const bytes = await decrypt(recipient, encryptedMessage) // // use an existing AES key // const existingKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, // extractable ['encrypt', 'decrypt'] ) const anotherEncryptedMsg = await encrypt( recipient, 'hello again', existingKey ) ``` ##### `encrypt` 接收者可以是一个 crypto 密钥、一个 Uint8Array 或一个字符串形式的公钥。 ``` type RecipientKey = | CryptoKey | CryptoKeyPair | Uint8Array | { publicKey:string; encoding?:Uint8ArrayEncodings } async function encrypt ( recipient:RecipientKey, message:Uint8Array|string, aesKey?:CryptoKey|Uint8Array|null, opts?:{ keysize?:128|256 info?:Uint8Array|string } ):Promise ``` ##### 加密为字符串 `encrypt.asString` 就是 `encrypt`,只不过信封被编码成了字符串,非常适合 传输文本(JSON、URL、headers)的场景。`opts.encoding` 用于设置字符串 编码。默认编码是 `base64url`。 ``` import { encrypt, decrypt } from '@substrate-system/ecies' import { fromString } from 'uint8arrays' // recipient is any RecipientKey; keypair holds the matching private key const encryptedString = await encrypt.asString( recipient, 'message for them', null, // an AES key if you want { encoding: 'base64url' } ) // Decode it back to bytes before decrypting. const message = fromString(encryptedString, 'base64url') const plaintext = await decrypt.asString(keypair, message) // 'message for them' ``` 返回的字符串编码了与 `encrypt` 返回的相同信封,因此 接收者使用匹配的解码器(这里是 `fromString`)对其进行解码,并将这些 字节传递给 `decrypt` / `decrypt.asString`。 ##### `decrypt` ``` async function decrypt ( keypair:CryptoKeyPair, message:Uint8Array, opts?:{ info?:Uint8Array|string } ):Promise ``` ## 模块 这个包通过 [package.json `exports` 字段](https://nodejs.org/api/packages.html#exports) 暴露了 ESM 和 Common JS。 ### ESM ``` import { seal, open, encrypt, decrypt } from '@substrate-system/simple-hpke' ``` ### Common JS ``` require('@substrate-system/simple-hpke') ``` ### 预构建 JS 这个包也暴露了压缩后的 JS 文件。将它们复制到你的 Web 服务器可访问的位置,然后在 HTML 中链接到它们。 #### 复制 ``` cp ./node_modules/@substrate-system/simple-hpke/dist/index.min.js ./public/hpke.min.js ``` #### HTML ``` ```
标签:HPKE, MITM代理, TypeScript, 加密库, 安全插件, 密码学, 密钥封装, 手动系统调用, 数据可视化, 混合加密, 自动化攻击, 蓝队防御