非对称 API 密钥

  • 更新

非对称密钥涉及使用两个密钥:私钥和公钥,这两个密钥不同,但在密码学上是相互关联的。私钥用于生成签名,而公钥用于签名验证。API 密钥由 Deribit 生成,但私钥和公钥对由用户生成。Deribit 支持 Ed25519 或 RSA 密钥对。Deribit 只需要使用公钥进行签名验证,从而使私钥保持本地和

非对称加密的主要优势在于其增强的安全模型,该模型将用于签名生成和验证的密钥分开。这种分离确保了尽管外部系统可以对签名进行身份验证以确认数据的来源和完整性,但它们无法自己生成签名。此属性对于维护数据的安全性和不可否认性至关重要,因为只有私钥的持有人才能发起

此外,非对称加密通过向私钥添加密码的功能提供了额外的安全层。这意味着,即使未经授权的实体以某种方式访问了私钥,也无法在不知道密码的情况下使用它。

请记住,只有 Deribit 签名凭证认证 适用于非对称 API 密钥。

图 2. 非对称 API 密钥图

非对称 API 密钥图

如何设置非对称 API 密钥?

  1. 创建公钥和私钥对

  2. 在 Deribit 上创建新的 API 密钥

  3. 使用非对称 API 密钥进行身份验证

创建公钥和私钥对

要创建公钥和私钥对,您可以使用下面提供的 Python 脚本,也可以使用 OpenSSL。OpenSSL 是一个开源软件库,为安全通信提供工具和库,实现用于加密、加密功能和数字证书的 SSL 和 TLS 协议

OpenSSL

第 1 步: 确保您的操作系统上安装了 OpenSSL

视窗

检查 OpenSSL 是否已安装:

  1. 打开命令提示符或 PowerShell。

  2. 键入以下命令并按 Enter:openssl version

  3. 如果安装了 OpenSSL,您将看到版本号。如果没有,请继续安装。

安装 OpenSSL:

  1. 从下载安装程序 这个链接

  2. 选择适合您系统的版本(Win32 或 Win64)。

  3. 运行安装程序并按照说明进行操作。

macOS

检查 OpenSSL 是否已安装:

  1. 打开终端。

  2. 键入以下命令并按 Enter:openssl version

  3. 如果安装了 OpenSSL,您将看到版本号。如果没有,请继续安装。

安装 OpenSSL:

  1. 使用 Homebrew 安装 OpenSSL。如果你没有安装 Homebrew,请参阅 他们的官方网站

  2. 安装 Homebrew 后,运行:brew install openssl

  3. 你可能需要将 OpenSSL 添加到你的 PATH 中。安装后,请按照Homebrew给出的说明执行此操作

联想系统

检查 OpenSSL 是否已安装:

  1. 打开终端。

  2. 键入以下命令并按 Enter:openssl version

  3. 如果安装了 OpenSSL,您将看到版本号。如果没有,请继续安装。

安装 OpenSSL:

安装命令可能因您的 Linux 发行版而异。以下是一些常见发行版的命令:

Debian/Ubuntu:

sudo apt update sudo apt install openssl

Fedora:

sudo dnf install openssl

Arch Linux:

sudo pacman -S openssl

第 2 步: 使用 OpenSSL 创建 ED25519 密钥

运行以下命令生成私钥:

openssl genpkey -algorithm ed25519 -out private.pem

第 3 步: 计算公钥(用于 API 密钥注册)

运行以下命令生成相应的公钥:

openssl pkey -in private.pem -pubout -out public.pem

Python 脚

确保你已经安装了密码学: - pip install cryptography

公共和私人 Ed25519 密钥生成器

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization

private_key = Ed25519PrivateKey.generate()

private_pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption()
)

with open('private.pem', 'wb') as private_pem_file:
    private_pem_file.write(private_pem)


public_key = private_key.public_key()

public_pem = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)

with open('public.pem', 'wb') as public_pem_file:
    public_pem_file.write(public_pem)

公共和私有 RSA 密钥生成器

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

# Generate RSA private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)

# Serialize the private key to PEM format
private_pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption()
)

# Write the private key to a file
with open('private.pem', 'wb') as private_pem_file:
    private_pem_file.write(private_pem)

# Get the corresponding public key
public_key = private_key.public_key()

# Serialize the public key to PEM format
public_pem = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)

# Write the public key to a file
with open('public.pem', 'wb') as public_pem_file:
    public_pem_file.write(public_pem)

在 Deribit 上创建新的非对称 API 密钥

您可以使用前端接口或 Deribit API 创建新的 Deribit API 密钥。如果你想使用 API,请前往使用 API 创建非对称 API 密钥

前端接口

asymmetric_keys_api_section.jpeg

按 '添加新密钥'在界面的右侧。

asymmetric_keys_new_key.jpeg

选择 自生密钥 并提供先前生成的公钥。

重要

[en] Paste the entire public key file content, not just the base64 hash. The public key must include the -----BEGIN PUBLIC KEY----- header, the base64-encoded key data, and the -----END PUBLIC KEY----- footer.

asymmetric_keys_self_generated_key.jpeg

声明范围和其他 API 密钥详细信息:

  • 范围: 描述使用给定密钥进行授权的最大访问权限。请前往 官方文档 了解更多详情。

  • 名称字段: 这是您可以输入的自定义输入,用作密钥的标识符。

  • 功能字段: 此 API 密钥相关的其他可选功能。它们可能会在未来的版本中进行扩展。

  • IP 白名单: 此字段是另一项安全功能,限制哪些 IP 可以使用此 IP 进行连接。

asymmetric_key_scopes.jpeg

创建后,您将收到 客户端 ID

客户端 ID:客户端 ID 是 API 密钥的公共标识符。这不是秘密。它可以在网络浏览器、源代码或其他任何地方公开,而无需立即出现安全问题。它主要用于识别密钥,不能单独用于身份验证。

asymmetric_key.jpeg

使用 API 创建非对称 API 密钥

通过公钥进行密钥注册 私钥/创建 api_key:

请求

{
  "method": "private/create_api_key",
  "params": {
    "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA/pQXmQa6m5NigEfu0UrbjDdzRORWYRluJasNiZau2Lo=\n-----END PUBLIC KEY-----",
    "name": "ed25519key",
    "max_scope": "account:read trade:read_write wallet:read"
  },
  "jsonrpc": "2.0",
  "id": 1
}

回应

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "max_scope": "trade:read_write wallet:read account:read",
    "ip_whitelist": [],
    "client_secret": "81:c2:76:35:a7:1a:1c:f8:05:71:e1:42:7c:94:2c:4c",
    "client_id": "GgUXjYUj",
    "enabled_features": [],
    "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA/pQXmQa6m5NigEfu0UrbjDdzRORWYRluJasNiZau2Lo=\n-----END PUBLIC KEY-----",
    "timestamp": 1721816749587,
    "name": "ed25519key",
    "id": 11,
    "enabled": true,
    "default": false
  }
}

使用非对称 API 密钥进行身份验证

只有 Deribit 签名凭证认证 适用于非对称 API 密钥。要使用非对称 API 密钥进行身份验证,必须使用私钥对签名进行签名。以下是如何使用 shell 命令和 Python 代码对签名进行签名的示例。

外壳示例

base_url=

timestamp=$( date +%s000 )
nonce=$( cat /dev/urandom | tr -dc 'a-z0-9' | head -c8 )
verb=GET
uri='/api/v2/private/get_current_deposit_address?currency=eth'

datatosign=$(mktemp)
echo -ne "${timestamp}\n${nonce}\n${verb}\n${uri}\n\n" > ${datatosign}

# client_id received when creating the API key
client_id=xyz
signature=$(openssl pkeyutl -sign -inkey private.pem -rawin -in ${datatosign} | base64 -w 100 | sed 's#+#-#g;s#/#_#g;s#=##g')
rm ${datatosign}

curl -s -X ${verb} -H "Authorization: DERI-HMAC-SHA256 id=${client_id},ts=${timestamp},nonce=${nonce},sig=${signature}" "${base_url}${uri}" | jq

Python 脚

Ed25519 身份验证

import asyncio
from cryptography.hazmat.primitives import serialization
import websockets

import base64
import json
from datetime import datetime

# client_id received when creating the API key
client_id='xyz'

with open('private.pem', 'rb') as private_pem:
    private_key = serialization.load_pem_private_key(private_pem.read(), password=None)

timestamp = round(datetime.now().timestamp() * 1000)
nonce = "abcd"
data = ""

data_to_sign = bytes('{}\n{}\n{}'.format(timestamp, nonce, data), "latin-1")
signature = base64.urlsafe_b64encode(private_key.sign(data_to_sign)).decode('utf-8').rstrip('=')

msg = {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "public/auth",
    "params": {
        "grant_type": "client_signature",
        "client_id": client_id,
        "timestamp": timestamp,
        "signature": signature,
        "nonce": nonce,
        "data": data
    }
}

async def call_api(msg):
    async with websockets.connect('wss://test.deribit.com/ws/api/v2') as websocket:
        await websocket.send(msg)
        while websocket.open:
            response = await websocket.recv()
            # do something with the response...
            print(response)
            await websocket.send(json.dumps({
                "jsonrpc": "2.0",
                "id": 2,
                "method": "private/get_positions",
                "params": {
                    "currency": "btc"
                }
            }))
            response = await websocket.recv()
            print(response)
            exit()

asyncio.get_event_loop().run_until_complete(call_api(json.dumps(msg)))

RSA 身份验证

import asyncio
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
import websockets

import base64
import json
from datetime import datetime

# client_id received when creating the API key
client_id = 'xyz'

# Load the private key from the PEM file
with open('private.pem', 'rb') as private_pem:
    private_key = serialization.load_pem_private_key(private_pem.read(), password=None)

# Generate timestamp, nonce, and data to sign
timestamp = round(datetime.now().timestamp() * 1000)
nonce = "abcd"
data = ""

# Prepare the data to sign
data_to_sign = bytes('{}\n{}\n{}'.format(timestamp, nonce, data), "latin-1")

# Sign the data using the RSA private key with padding and hashing algorithm
signature = private_key.sign(
    data_to_sign,
    padding.PKCS1v15(),
    hashes.SHA256()
)

# Encode the signature to base64
encoded_signature = base64.urlsafe_b64encode(signature).decode('utf-8').rstrip('=')

# Prepare the message
msg = {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "public/auth",
    "params": {
        "grant_type": "client_signature",
        "client_id": client_id,
        "timestamp": timestamp,
        "signature": encoded_signature,
        "nonce": nonce,
        "data": data
    }
}

# Function to call the API
async def call_api(msg):
    async with websockets.connect('wss://test.deribit.com/ws/api/v2') as websocket:
        await websocket.send(msg)
        while websocket.open:
            response = await websocket.recv()
            # do something with the response...
            print(response)
            await websocket.send(json.dumps({
                "jsonrpc": "2.0",
                "id": 2,
                "method": "private/get_positions",
                "params": {
                    "currency": "btc"
                }
            }))
            response = await websocket.recv()
            print(response)
            exit()

# Run the event loop to call the API
asyncio.get_event_loop().run_until_complete(call_api(json.dumps(msg)))

常见问题

  • 我可以使用多个非对称密钥吗?

    是的,您可以为不同的应用程序或系统创建和管理多个非对称密钥。

  • 如果我的私钥被泄露了该怎么办?

    立即从您的 Deribit 账户中撤销相应的公钥并生成新的密钥对。

  • 非对称密钥仍然需要范围和权限吗?

    是的,你必须指定具体的 范围 (权限)创建 API 密钥时,就像使用标准 API 凭据一样。