非对称密钥涉及使用两个密钥:私钥和公钥,这两个密钥不同,但在密码学上是相互关联的。私钥用于生成签名,而公钥用于签名验证。API 密钥由 Deribit 生成,但私钥和公钥对由用户生成。Deribit 支持 Ed25519 或 RSA 密钥对。Deribit 只需要使用公钥进行签名验证,从而使私钥保持本地和
非对称加密的主要优势在于其增强的安全模型,该模型将用于签名生成和验证的密钥分开。这种分离确保了尽管外部系统可以对签名进行身份验证以确认数据的来源和完整性,但它们无法自己生成签名。此属性对于维护数据的安全性和不可否认性至关重要,因为只有私钥的持有人才能发起
此外,非对称加密通过向私钥添加密码的功能提供了额外的安全层。这意味着,即使未经授权的实体以某种方式访问了私钥,也无法在不知道密码的情况下使用它。
请记住,只有 Deribit 签名凭证认证 适用于非对称 API 密钥。
要创建公钥和私钥对,您可以使用下面提供的 Python 脚本,也可以使用 OpenSSL。OpenSSL 是一个开源软件库,为安全通信提供工具和库,实现用于加密、加密功能和数字证书的 SSL 和 TLS 协议
检查 OpenSSL 是否已安装:
-
打开终端。
-
键入以下命令并按 Enter:
openssl version -
如果安装了 OpenSSL,您将看到版本号。如果没有,请继续安装。
安装 OpenSSL:
-
使用 Homebrew 安装 OpenSSL。如果你没有安装 Homebrew,请参阅 他们的官方网站。
-
安装 Homebrew 后,运行:
brew install openssl -
你可能需要将 OpenSSL 添加到你的 PATH 中。安装后,请按照Homebrew给出的说明执行此操作
确保你已经安装了密码学: - 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 密钥。如果你想使用 API,请前往使用 API 创建非对称 API 密钥
按 '添加新密钥'在界面的右侧。
选择 自生密钥 并提供先前生成的公钥。
重要
[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.
声明范围和其他 API 密钥详细信息:
-
范围: 描述使用给定密钥进行授权的最大访问权限。请前往 官方文档 了解更多详情。
-
名称字段: 这是您可以输入的自定义输入,用作密钥的标识符。
-
功能字段: 此 API 密钥相关的其他可选功能。它们可能会在未来的版本中进行扩展。
-
IP 白名单: 此字段是另一项安全功能,限制哪些 IP 可以使用此 IP 进行连接。
创建后,您将收到 客户端 ID
客户端 ID:客户端 ID 是 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
}
}
只有 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
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)))