1
zyy
4 days ago c272cabfe3814857218601ae7aa61b5923d7d4ec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package com.yami.trading.huobi.websocket.service.huobi.signature;
 
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Security;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
 
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
 
import com.yami.trading.huobi.websocket.exception.SDKException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
 
public class ApiSignatureED25519 {
 
  public static final String op = "op";
  public static final String opValue = "auth";
  private static final String accessKeyId = "AccessKeyId";
  private static final String signatureMethod = "SignatureMethod";
  private static final String signatureMethodValue = "Ed25519"; // 使用 Ed25519 签名
  private static final String signatureVersion = "SignatureVersion";
  private static final String signatureVersionValue = "2";
  private static final String timestamp = "Timestamp";
  private static final String signature = "Signature";
 
  private static final DateTimeFormatter DT_FORMAT = DateTimeFormatter
          .ofPattern("uuuu-MM-dd'T'HH:mm:ss");
  private static final ZoneId ZONE_GMT = ZoneId.of("Z");
 
  private Ed25519PrivateKeyParameters privateKey;
  private Ed25519PublicKeyParameters accessKey;
 
  // 构造函数接收 Base64 编码的私钥和公钥
  public void ApiSignature(String base64PublicKey,String base64PrivateKey) throws Exception {
 
//    this.privateKey = (Ed25519PrivateKeyParameters) PrivateKeyFactory.createKey(Base64.getDecoder().decode(base64PrivateKey));
 
    Security.addProvider(new BouncyCastleProvider());
    // 从 PEM 格式中提取私钥
    try (PEMParser pemParser = new PEMParser(new StringReader(base64PrivateKey))) {
      Object object = pemParser.readObject();
      if (object instanceof PrivateKeyInfo) {
        PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) object;
        // 使用 JcaPEMKeyConverter 将 PrivateKeyInfo 转换为 Java PrivateKey
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        PrivateKey privateKey = converter.getPrivateKey(privateKeyInfo);
        // 将 Java PrivateKey 转换为 Ed25519PrivateKeyParameters
        this.privateKey = (Ed25519PrivateKeyParameters) PrivateKeyFactory.createKey(privateKey.getEncoded());
      } else {
        throw new IllegalArgumentException("Invalid PEM format: not a private key");
      }
    }
 
  }
 
  public void createSignature(String method, String host, String uri, UrlParamsBuilder builder,String accessKey) {
    StringBuilder sb = new StringBuilder(1024);
 
    // 检查 API 密钥是否为空
    if ( privateKey == null || "".equals(privateKey)) {
      throw new SDKException(SDKException.KEY_MISSING,
              "API key and secret key are required");
    }
 
    sb.append(method.toUpperCase()).append('\n')
            .append(host.toLowerCase()).append('\n')
            .append(uri).append('\n');
 
    builder.putToUrl(accessKeyId, String.valueOf(accessKey))
            .putToUrl(signatureVersion,signatureVersionValue)
            .putToUrl(timestamp, gmtNow())
            .putToUrl(signatureMethod, signatureMethodValue);
 
 
    sb.append(builder.buildSignature());
    System.out.println(sb.toString());
    System.out.println(sb.toString().length());
 
    // 使用 Ed25519 进行签名
    Ed25519Signer signer = new Ed25519Signer();
    signer.init(true, privateKey);
 
    signer.update(sb.toString().getBytes(StandardCharsets.UTF_8), 0, sb.length());
    byte[] signatureBytes = signer.generateSignature();
    String actualSign = Base64.getEncoder().encodeToString(signatureBytes);
 
    builder.putToUrl(signature, actualSign);
  }
 
  private static long epochNow() {
    return Instant.now().getEpochSecond();
  }
 
  static String gmtNow() {
    return Instant.ofEpochSecond(epochNow()).atZone(ZONE_GMT).format(DT_FORMAT);
  }
}