name: wallet-encrypt-decrypt description: 当用户请求"使用BSV密钥加密消息"、“使用私钥解密”、“ECDH加密”、“AES-256-GCM BSV”、“EncryptedMessage”、“BRC-2加密”,或需要使用BSV密钥和@bsv/sdk加密/解密数据时,应使用此技能。
BSV 消息加密
使用 @bsv/sdk 在各方之间加密和解密消息。
推荐:使用 @bsv/sdk 中的 EncryptedMessage
@bsv/sdk 提供 EncryptedMessage 用于安全消息加密。这是首选方法 - 避免自定义加密实现。
import { PrivateKey, EncryptedMessage, Utils } from '@bsv/sdk'
const sender = PrivateKey.fromRandom()
const recipient = PrivateKey.fromRandom()
// 加密:发送方使用其私钥 + 接收方的公钥
const message = Utils.toArray('Secret message', 'utf8')
const encrypted = EncryptedMessage.encrypt(message, sender, recipient.toPublicKey())
// 解密:接收方使用其私钥
const decrypted = EncryptedMessage.decrypt(encrypted, recipient)
const plaintext = Utils.toUTF8(decrypted)
两种加密模式
模式 1:静态-静态 ECDH(双方都有密钥)
当双方都有已建立的密钥对时使用(例如,BAP身份、paymail地址)。
import { PrivateKey, EncryptedMessage, Utils } from '@bsv/sdk'
// Alice 和 Bob 都有持久密钥
const alice = PrivateKey.fromWif('L1...')
const bob = PrivateKey.fromWif('K1...')
// Alice 加密给 Bob
const ciphertext = EncryptedMessage.encrypt(
Utils.toArray('Hello Bob', 'utf8'),
alice,
bob.toPublicKey()
)
// Bob 解密来自 Alice 的消息
const plaintext = EncryptedMessage.decrypt(ciphertext, bob)
使用场景:
- 点对点加密消息传递
- 加密备份到自己的密钥
- 已知身份之间的通信
模式 2:ECIES 风格(临时发送方密钥)
当发送方没有持久身份时使用(例如,浏览器到服务器)。
import { PrivateKey, EncryptedMessage, Utils } from '@bsv/sdk'
// 服务器有持久密钥,客户端生成临时密钥
const serverKey = PrivateKey.fromWif('L1...')
const ephemeralClient = PrivateKey.fromRandom()
// 客户端加密(临时 → 服务器)
const encrypted = EncryptedMessage.encrypt(
Utils.toArray('sensitive data', 'utf8'),
ephemeralClient,
serverKey.toPublicKey()
)
// 包含临时公钥以便服务器解密
const payload = {
ephemeralPub: ephemeralClient.toPublicKey().toString(),
ciphertext: Utils.toHex(encrypted)
}
// 服务器使用临时公钥解密
const clientPub = PublicKey.fromString(payload.ephemeralPub)
// 注意:EncryptedMessage.decrypt 需要密文中嵌入的发送方信息
使用场景:
- 浏览器到服务器加密
- 单向安全通道
- 前向保密(每条消息使用新密钥)
ECDH 密钥协商工作原理
双方推导出相同的共享密钥:
Alice: alicePrivKey × bobPubKey = sharedPoint
Bob: bobPrivKey × alicePubKey = sharedPoint
共享点然后用于推导 AES-256-GCM 加密的对称密钥。
API 参考
EncryptedMessage.encrypt()
static encrypt(
message: number[], // 明文作为字节数组
sender: PrivateKey, // 发送方的私钥
recipient: PublicKey // 接收方的公钥
): number[] // 加密的字节
EncryptedMessage.decrypt()
static decrypt(
ciphertext: number[], // 来自 encrypt() 的加密字节
recipient: PrivateKey // 接收方的私钥
): number[] // 解密的明文字节
实用函数
// 字符串转字节
Utils.toArray('hello', 'utf8') // number[]
// 字节转字符串
Utils.toUTF8([104, 101, 108, 108, 111]) // 'hello'
// 字节转十六进制
Utils.toHex([1, 2, 3]) // '010203'
// 十六进制转字节
Utils.toArray('010203', 'hex') // [1, 2, 3]
安全特性
- 认证加密:AES-256-GCM 提供机密性和完整性
- 密钥协商:ECDH 确保只有目标接收方可以解密
- 无密钥传输:私钥从不离开其所有者
常见错误
不要自定义加密实现
❌ 错误:手动实现 ECDH + AES
// 不要这样做 - 使用 EncryptedMessage 代替
const sharedSecret = myPrivKey.deriveSharedSecret(theirPubKey)
const aesKey = sha256(sharedSecret)
// ... 手动 AES 加密
✅ 正确:使用 SDK 的内置类
const encrypted = EncryptedMessage.encrypt(message, sender, recipient)
不要混淆加密与认证
- 加密(此技能):隐藏消息内容
- 认证(
bitcoin-auth):证明发送方身份
对于认证 + 加密的通信,同时使用:
// 加密载荷
const encrypted = EncryptedMessage.encrypt(payload, sender, recipient)
// 签署请求(证明发送方身份)
const authToken = getAuthToken({ privateKeyWif, requestPath, body })