RSA
RSA Signature Demo Code
- Java
- Python
- JS
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.management.RuntimeErrorException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
@Slf4j
public class CheckSign {
    
    public static void main(String[] args) throws Exception {
        //GET sign example
//        String timestamp = "1684814440729";
//        String queryString = "marginCoin=usdt&symbol=btcusdt"; // Need to be sorted in ascending alphabetical order by key
//        String signContent = timestamp + "GET" + "/api/v2/spot/account/account?" + queryString;
//        String sign = generate(signContent);
//        log.info("sign:{}",sign);
        //POST sign example
        String timestamp = "1684814440729";
        String preContent = timestamp + "POST" + "/api/v2/spot/trade/place-order";
        String body = "{\"symbol\":\"btcusdt\",\"quantity\":\"8\",\"side\":\"buy\",\"price\":\"1\",\"orderType\":\"limit\",\"clientOid\":\"channel1233456\"}";
        String signContent = preContent + body;
        String sign = generate(signContent);
        log.info("sign:{}",sign);
    }
  /**
   *
   * @param content: the string to be signed
   * @return
   */
  private String generate(String content) {
    String privateKey = "-----BEGIN PRIVATE KEY-----\n" +
            "xxxxxxxxxxxxxxxxxxxx9w0BAQEFAASCBKgwggSkAgEAAoIBAQD5C1iP01MC9fh5\n" +
            "xxxxxxxxxxxxxxx9Tcqfz6HzoSg+zd8HVxKXRTXBwMDBfLxfQXobptz1tDlPUs+g\n" +
            "xxxxxxxxxxxxxxxBaZ5qHxArBTimyNXX6WNL6hTw0MI238cGKiW0WvWd9v6Z6/LX\n" +
            "xxxxxxxxxxxxxxxcO7EKGuvBrVIRl57FzvOPD5QKfhVxcHr63NfEViAEQfQH4IN2\n" +
            "xxxxxxxxxxxxxxx4jILUP+LXvHN7ZMiWP9bouw3r4l6v0NJ4XyucSYJL9fJ81rsI\n" +
            "xxxxxxxxxxxxxxx4RSsFZKFyurE1c8XiU2aZ2qq+6vjby0ncE4dKVu5x/iJZ4gsL\n" +
            "xxxxxxxxxxxxxxxCggEAD6cF5uw6QGpjNo30emMd6aXKsUbpbyYvgQHUxPIxDFl2\n" +
            "xxxxxxxxxxxxxxxJjhcYbJp9MrgkDfc/c23+HomKbXqIkcVMy2DvAu523q1SVTE0\n" +
            "xxxxxxxxxxxxxxxs6BdIDWDWJRp8AAKTXba6jgOOrg/Xbwq25aOeyerNPHv/N3m3\n" +
            "xxxxxxxxxxxxxxx2UdX7NkvV4qmRi8se47OXUT9aypzpvGbSukkqXuE4GtKGoybR\n" +
            "xxxxxxxxxxxxxxxNshn2QJnRd3GN2UENDvZS3ZvSY6f/Cq7K/EAmrsstOdUB2Ihn\n" +
            "xxxxxxxxxxxxxxx3ekuArWc54bDai0deKFl9KvI2oQKBgQD9ekRFMB6ueRCCeoyg\n" +
            "xxxxxxxxxxxxxxxKL1xKhrg6mYh65hfQaxbihfOcrneFOoc3BgZwnbAZpF+hlq9J\n" +
            "xxxxxxxxxxxxxxxF3PGj5vPln9/rd6/gcFFE9o7zZhI166PsmlxQ7/N0SCnlao7y\n" +
            "xxxxxxxxxxxxxxxlNsTR+XZ88QKBgQD7hckVvGxIftcZsHChP8TFcDAn1IsaVbyt\n" +
            "xxxxxxxxxxxxxxx8YPtFr9afiCJ4b2NqRe8gCpUCUi+urnoMMsqMxTUMopiLPh2S\n" +
            "xxxxxxxxxxxxxxxWx06krbOOyXVZ8RtgYLMpMhFCsRyzovqe8/LZQfQKWfQGTAXS\n" +
            "xxxxxxxxxxxxxxx7DMDYdbwOcFRYlOq1WEarExTCUoHdfZfIrc5jSKsmwynN14H3\n" +
            "xxxxxxxxxxxxxxxKzO1vqU3Mfln7umC73/9FJgZQfOh7TRpW4saGduXAq4voDTiC\n" +
            "xxxxxxxxxxxxxxxsozRAnfF/+8i+/TVjQaSVgetYPB63uXw4JoRzlq1zYQKBgQDJ\n" +
            "xxxxxxxxxxxxxxxGaNBKhR9TypEFylDXreTbDaMtTzg3Mcwa/qyarGiL2Fl8AEh6\n" +
            "xxxxxxxxxxxxxxxUFO6BBozpINt/5ZUN7NL7w92qi25qkAQt4sGi+QQOnHMGisak\n" +
            "xxxxxxxxxxxxxxxzsXqDqiwF52M9bui5zthbWfkj4wKBgEFVT+jf235aihaS88Oj\n" +
            "xxxxxxxxxxxxxxxHlYCIef7/a+gt7N1u9sEGlPspY3HuPamA39201BuItD9X83VR\n" +
            "xxxxxxxxxxxxxxxZn1O8/l+ItSNUzQhX6T0cSdCo6KtmZLBQ6Zaw7r63GcdvSdR2\n" +
            "xxxxxxxxxxxxxxxxxxxxxxx\n" +
            "-----END PRIVATE KEY-----\n";
    try {
      String parsedPem = privateKey.replace("\n", "").trim();
      parsedPem = parsedPem
              .replace("-----BEGIN PRIVATE KEY-----", "")
              .replace("-----END PRIVATE KEY-----", "");
      PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Utils.decodeFromString(parsedPem));
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      PrivateKey priKey = keyFactory.generatePrivate(priPKCS8);
      Signature signature = Signature.getInstance("SHA256WithRSA");
      signature.initSign(priKey);
      signature.update(content.getBytes(StandardCharsets.UTF_8));
      String sign = Base64Utils.encodeToString(signature.sign());
      return sign;
    } catch (Exception ex) {
      throw new RuntimeException("create sign  failed", ex);
    }
  }
}
import base64
import json
import time
import base64
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA
def get_timestamp():
    return int(time.time() * 1000)
def rsa_sign(message, private_key):
  pri_key = RSA.importKey(private_key)
  encoded_param = SHA256.new(bytes(message, encoding='utf-8'))
  sign_str = PKCS1_v1_5.new(pri_key).sign(encoded_param)
  return base64.b64encode(sign_str).decode()
def pre_hash(timestamp, method, request_path, body):
    return str(timestamp) + str.upper(method) + request_path + body
def parse_params_to_str(params):
    params = [(key, val) for key, val in params.items()]
    params.sort(key=lambda x: x[0])
    from urllib.parse import urlencode
    url = '?' +urlencode(params);
    if url == '?':
        return ''
    return url
if __name__ == '__main__':
    private_key = '''-----BEGIN PRIVATE KEY-----
XXXXXXXXXXANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdTR5gmwGH77wE
xxxxxxxxxxiw7fPXWhMh7gZwurQQ8M/I9/VA8lDjwwoGuuJ6enurdfwhpZxeZH
xxxxxxxxxxSEXVuxJv5hdpI9m6ydInK9SA8IbaF4yYWp0l4N2mA44MzadA7QZq
xxxxxxxxxxa5q/NZHFWCrCbW2lGAAWwrhQq9LceVIW75e213xtnps0pGlII7Ye
xxxxxxxxxxYNSxlCdLOiz1GvOeVSeiSZx31o/O+rj7tDFpSgZJEXRmtGRoJkJy
xxxxxxxxxxVSOcb1hCExg4osK6rBKnDjFjwQvwvNNZq0JG+CkfH8eHAa7gSK50
xxxxxxxxxxAAECggEAEvYk30hQGu7PH0stQX3UhlVsR6HXnRlvgIrmJe7F/VLO
xxxxxxxxxx/heYY1nsX8+mIyjmvEOayqPgdkEmXevVlcuQf38Zbduynr3vlRCX
xxxxxxxxxxSxFBODuu/EAZc3mm27C2wUV7w6SAy9g0g6Os97ehZsSGAwHl4aye
xxxxxxxxxxEh5Ptq4YAfCYiUO7j10pQ+DJKqN9N1eyjyw5eixEgCpudcbpCc9X
xxxxxxxxxxANX8/LwvokqgYBK1UIL6ear0dtKmeFU+KwrmkKZfXk8/Amr/O8Ot
xxxxxxxxxxzq3La149LMmNkUYxaMSV/KGTEV7ukQKBgQDQl/fA3mxXtQg2IjTB
xxxxxxxxxxECWcP7TQWJDb30vxOKeq1k9YPUfegZga5zlyV28PAZnb0m5x07+0
xxxxxxxxxxe9OhQxfkAY6AtJaiIqhCcw5ew8Go/Ja1ML0jZESWG1MWBJtCcFTm
xxxxxxxxxxe0adilYmyu7zwwKBgQDBDPJZgSj7YssPyRmo3bO0MjknfYBqXvwi
xxxxxxxxxxJ9Rc2WXGfEm3DEn7TO/Wv0t7Yqm6/sXg5HzriN/PHlaVtE6wlXe7
xxxxxxxxxx7KKWYqP812mASl6ydLX9QWozlOXjVhWMuSGqMWjut4J3P8jlkOJ6
xxxxxxxxxxgQCxwvAl8ubNj78hsuDWgsddKIMkwvKrfdsvXrMOYouAdLjZJvjs
xxxxxxxxxxs9km8g/479pYlOn+Iv/Z7Lqke8/HdOFASoQ9h1nSuujgEgXUwkg1
xxxxxxxxxx2BY3FPnGGh8iQma1pdkUVn35fAq/m7e/S+kP1JY6lPIx1QKBgQCS
xxxxxxxxxxpot+ceGt2bseSd8l4jqU3nDZ0oW8+4Qnnu9QFhN4Hn9wIjpAOGaU
xxxxxxxxxxVbior98JxMSDHsHmuXKPA8DishumGlqV+vxsIzLQD1Ge/dbqsERB
xxxxxxxxxxiyUNqjk5kcPQeHIyJk5qQaF21udoTQKBgDOMbtM0Nq7cd/SAHISR
xxxxxxxxxxLJW7DRJGxw3AEwxKG+nxNLeG7GsQDyPCvZSKwRpdpXRTh+6mzXqe
xxxxxxxxxxz8Cwo6tgyKRi6QPObQk00vbrKEBTihP30m81rwBPzjwj7iKXxWgA
DJoVsaqGOaIf4qXXXXXXXXXX
-----END PRIVATE KEY-----'''
    timestamp = get_timestamp()
    request_path = "/api/v2/mix/order/place-order"
    # POST
    params = {"symbol": "TRXUSDT", "marginCoin": "USDT", "price": 0.0555, "size": 551, "side": "buy", "orderType": "limit", "force": "normal"}
    body = json.dumps(params)
    sign = rsa_sign(pre_hash(timestamp, "POST", request_path, str(body)), private_key)
    print(sign)
    # GET
    body = ""
    request_path = "/api/v2/mix/account/account"
    params = {"symbol": "TRXUSDT", "marginCoin": "USDT"}
    request_path = request_path + parse_params_to_str(params) # Need to be sorted in ascending alphabetical order by key
    sign = rsa_sign(pre_hash(timestamp, "GET", request_path, str(body)), private_key)
    print(sign)
export function sign() {
    
    const private_key = '-----BEGIN PRIVATE KEY-----\n' +
        'XXXXXXXXXXANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdTR5gmwGH77wE\n' +
        'XXXXXXXXXXVhiw7fPXWhMh7gZwurQQ8M/I9/VA8lDjwwoGuuJ6enurdfwhpZxeZH\n' +
        'XXXXXXXXXXLESEXVuxJv5hdpI9m6ydInK9SA8IbaF4yYWp0l4N2mA44MzadA7QZq\n' +
        'XXXXXXXXXXeia5q/NZHFWCrCbW2lGAAWwrhQq9LceVIW75e213xtnps0pGlII7Ye\n' +
        'XXXXXXXXXXX8YNSxlCdLOiz1GvOeVSeiSZx31o/O+rj7tDFpSgZJEXRmtGRoJkJy\n' +
        'XXXXXXXXXXzCVSOcb1hCExg4osK6rBKnDjFjwQvwvNNZq0JG+CkfH8eHAa7gSK50\n' +
        'XXXXXXXXXXMBAAECggEAEvYk30hQGu7PH0stQX3UhlVsR6HXnRlvgIrmJe7F/VLO\n' +
        'XXXXXXXXXXtU/heYY1nsX8+mIyjmvEOayqPgdkEmXevVlcuQf38Zbduynr3vlRCX\n' +
        'XXXXXXXXXXucSxFBODuu/EAZc3mm27C2wUV7w6SAy9g0g6Os97ehZsSGAwHl4aye\n' +
        'XXXXXXXXXX10Eh5Ptq4YAfCYiUO7j10pQ+DJKqN9N1eyjyw5eixEgCpudcbpCc9X\n' +
        'XXXXXXXXXXr0ANX8/LwvokqgYBK1UIL6ear0dtKmeFU+KwrmkKZfXk8/Amr/O8Ot\n' +
        'XXXXXXXXXXKRzq3La149LMmNkUYxaMSV/KGTEV7ukQKBgQDQl/fA3mxXtQg2IjTB\n' +
        'XXXXXXXXXXhaECWcP7TQWJDb30vxOKeq1k9YPUfegZga5zlyV28PAZnb0m5x07+0\n' +
        'XXXXXXXXXXpje9OhQxfkAY6AtJaiIqhCcw5ew8Go/Ja1ML0jZESWG1MWBJtCcFTm\n' +
        'XXXXXXXXXX1Ze0adilYmyu7zwwKBgQDBDPJZgSj7YssPyRmo3bO0MjknfYBqXvwi\n' +
        'XXXXXXXXXX5BJ9Rc2WXGfEm3DEn7TO/Wv0t7Yqm6/sXg5HzriN/PHlaVtE6wlXe7\n' +
        'XXXXXXXXXXKO7KKWYqP812mASl6ydLX9QWozlOXjVhWMuSGqMWjut4J3P8jlkOJ6\n' +
        'XXXXXXXXXXKBgQCxwvAl8ubNj78hsuDWgsddKIMkwvKrfdsvXrMOYouAdLjZJvjs\n' +
        'XXXXXXXXXXl3s9km8g/479pYlOn+Iv/Z7Lqke8/HdOFASoQ9h1nSuujgEgXUwkg1\n' +
        'XXXXXXXXXX0k2BY3FPnGGh8iQma1pdkUVn35fAq/m7e/S+kP1JY6lPIx1QKBgQCS\n' +
        'XXXXXXXXXXNmpot+ceGt2bseSd8l4jqU3nDZ0oW8+4Qnnu9QFhN4Hn9wIjpAOGaU\n' +
        'XXXXXXXXXXh+Vbior98JxMSDHsHmuXKPA8DishumGlqV+vxsIzLQD1Ge/dbqsERB\n' +
        'XXXXXXXXXXyfiyUNqjk5kcPQeHIyJk5qQaF21udoTQKBgDOMbtM0Nq7cd/SAHISR\n' +
        'XXXXXXXXXXAjLJW7DRJGxw3AEwxKG+nxNLeG7GsQDyPCvZSKwRpdpXRTh+6mzXqe\n' +
        'XXXXXXXXXXtez8Cwo6tgyKRi6QPObQk00vbrKEBTihP30m81rwBPzjwj7iKXxWgA\n' +
        'XXXXXXXXXXIf4qXXXXXXXXXX\n' +
        '-----END PRIVATE KEY-----\n'
    
    const ts = Date.now();
    const NodeRSA = require('node-rsa')
    const pri_key = new NodeRSA(private_key)
    //GET
    const ts = Date.now();
    const params = 'clientOid=123&coin=USDT&endTime=1659076670000&pageNo=1&pageSize=20&startTime=1659036670000' // Need to be sorted in ascending alphabetical order by key
    const endpoint = '/api/v2/spot/wallet/withdrawal-records'
    const method = "GET"
    const pre_hash = String(ts) + method + endpoint + '?' + params
    const sign = pri_key.sign(pre_hash, 'base64', 'UTF-8')
    //POST
    const endpoint_post = '/api/v2/spot/trade/unfilled-orders'
    const params_post = '{"symbol": "BTCUSDT"}'
    const method_post = "POST"
    const pre_hash_post = String(ts) + method_post + endpoint_post + params_post
    const sign_post = pri_key.sign(pre_hash_post, 'base64', 'UTF-8')
    
    return sign
}