We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/scgreenhalgh/nanokvm-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""Authentication utilities for NanoKVM API."""
import base64
import hashlib
import os
import urllib.parse
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
# NanoKVM uses this passphrase for password encryption
NANOKVM_PASSPHRASE = "nanokvm-sipeed-2024"
def _evp_bytes_to_key(
password: bytes,
salt: bytes,
key_len: int = 32,
iv_len: int = 16,
) -> tuple[bytes, bytes]:
"""
Derive key and IV using OpenSSL's EVP_BytesToKey (MD5-based).
This matches CryptoJS's default key derivation when using a passphrase.
"""
d = b""
d_i = b""
while len(d) < key_len + iv_len:
d_i = hashlib.md5(d_i + password + salt).digest()
d += d_i
return d[:key_len], d[key_len:key_len + iv_len]
def encrypt_password(password: str) -> str:
"""
Encrypt password using CryptoJS-compatible AES encryption.
The NanoKVM frontend uses CryptoJS.AES.encrypt with a passphrase,
which uses OpenSSL's EVP_BytesToKey for key derivation and produces
output in the format: "Salted__" + salt + ciphertext (base64 encoded).
Args:
password: Plain text password
Returns:
Base64 encoded string matching CryptoJS output format
"""
# Generate random 8-byte salt (same as CryptoJS)
salt = os.urandom(8)
# Derive key and IV using EVP_BytesToKey (MD5-based, like CryptoJS)
key, iv = _evp_bytes_to_key(NANOKVM_PASSPHRASE.encode('utf-8'), salt)
# Encrypt with AES-256-CBC
cipher = AES.new(key, AES.MODE_CBC, iv)
padded_data = pad(password.encode('utf-8'), AES.block_size)
ciphertext = cipher.encrypt(padded_data)
# Format: "Salted__" + salt + ciphertext (OpenSSL format)
openssl_data = b"Salted__" + salt + ciphertext
# Base64 encode, then URL encode (as the frontend does)
b64_encoded = base64.b64encode(openssl_data).decode('utf-8')
return urllib.parse.quote(b64_encoded, safe='')