Asymmetric keys involve the use of two keys: a private key and a public key, which are different but cryptographically linked. The private key is used for signature generation, while the public key is used for signature verification. The API key is generated by Deribit, but the private key and public key pair is generated by the user. Deribit supports Ed25519 or RSA key pairs. Only the public key needs to be used by Deribit for signature verification, allowing the private key to remain local and secret.
The primary advantage of asymmetric encryption lies in its enhanced security model, which separates the keys used for signature generation and verification. This separation ensures that while external systems can authenticate the signatures to confirm the origin and integrity of data, they are incapable of generating signatures themselves. This attribute is crucial for maintaining the security and non-repudiation of data as only the holder of the private key can originate signatures.
Additionally, asymmetric encryption provides an extra layer of security through the capability to add a password to private keys. This means even if the private key is somehow accessed by an unauthorized entity, it cannot be used without also knowing the password.
Keep in mind that only Deribit Signature Credentials authentication is available for asymmetric API keys.
To create a public and private key pair you can either use Python script provided further below or use OpenSSL. OpenSSL is an open-source software library that provides tools and libraries for secure communication, implementing the SSL and TLS protocols for encryption, cryptographic functions, and digital certificates.
Check if OpenSSL is Installed:
-
Open Command Prompt or PowerShell.
-
Type the following command and press Enter:
openssl version
-
If OpenSSL is installed, you will see the version number. If not, proceed to install it.
Install OpenSSL:
-
Download the installer from this link.
-
Choose the version appropriate for your system (Win32 or Win64).
-
Run the installer and follow the instructions.
Check if OpenSSL is Installed:
-
Open Terminal.
-
Type the following command and press Enter:
openssl version
-
If OpenSSL is installed, you will see the version number. If not, proceed to install it.
Install OpenSSL:
-
Use Homebrew to install OpenSSL. If you don’t have Homebrew installed, please refer to their official website.
-
Once Homebrew is installed, run:
brew install openssl
-
You may need to add OpenSSL to your PATH. Follow the instructions given by Homebrew after installation to do this.
Check if OpenSSL is Installed:
-
Open Terminal.
-
Type the following command and press Enter:
openssl version
-
If OpenSSL is installed, you will see the version number. If not, proceed to install it.
Install OpenSSL:
The installation commands may vary depending on your Linux distribution. Here are the commands for a few common distributions:
Debian/Ubuntu:
sudo apt update sudo apt install openssl
Fedora:
sudo dnf install openssl
Arch Linux:
sudo pacman -S openssl
Run the following command to generate a private key:
openssl genpkey -algorithm ed25519 -out private.pem
Make sure you have cryptography installed: - pip install cryptography
Public and Private Ed25519 key generator
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)
Public and Private RSA key generator
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)
You can create new Deribit API key using front-end interface or by Deribit API. If you want to use the API, please head to Creating the Asymmetric API key using the API.
Press ‘Add new key’ on the right side of the interface.
Select Self-generated key and provide previously generated public key.
Declare scopes and other API key details:
-
Scopes: Describes maximal access for authorization with given key. Please head to official documentation for more details.
-
Name field: This is a custom input you can enter to use as an identifier for the key.
-
Features field: Additional optional features related to this API key. They may be expanded in future releases.
-
IP Whitelisting: An additional security feature, this field restricts which IPs can connect using this IP.
Once created you will receive Client ID
Client ID:The Client ID is a public identifier of the API key. It's not a secret. It can be exposed in web browsers, source code, or wherever else without immediate security concerns. It's mainly used to identify the key and is not used on its own for authentication.
Key registration using the public key via private/create_api_key:
Request
{ "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 }
Response
{ "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 } }
Only Deribit Signature Credidentials authentication is available for asymmetric API keys. To authenticate with an asymmetric API key, the signature must be signed with a private key. Below are examples of how to sign the signature using both shell commands and Python code.
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 Authentication
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 Authentication
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)))
-
Can I use multiple asymmetric keys?
Yes, you can create and manage multiple asymmetric keys for different applications or systems.
-
What should I do if my private key is compromised?
Immediately revoke the corresponding public key from your Deribit account and generate a new key pair.
-
Are scopes and permissions still required for asymmetric keys?
Yes, you must assign specific scopes (permissions) when creating an API key, just like with standard API credentials.