API invocation method
...
Signature algorithm
Signature demonstration
Java language demo
1min
Java
1import cn.hutool.core.util.HexUtil;
2
3import javax.crypto.Mac;
4import javax.crypto.spec.SecretKeySpec;
5import javax.xml.bind.DatatypeConverter;
6import java.nio.charset.Charset;
7import java.nio.charset.StandardCharsets;
8import java.security.MessageDigest;
9import java.text.SimpleDateFormat;
10import java.time.LocalDateTime;
11import java.util.Date;
12import java.util.TimeZone;
13
14public class SignatureDemo {
15 private final static String PARTNER_CODE = "AKIDz8krbsJ5yKBZQpn74WFkmLPx3*******";
16 private final static String PARTNER_TOKEN = "Gu5t9xGARNpq86cd98joQYCN3*******";
17 private final static Charset UTF8 = StandardCharsets.UTF_8;
18 private final static String SECRET_ID = PARTNER_CODE;
19 private final static String SECRET_KEY = PARTNER_TOKEN;
20
21 // prod
22// private final static String HOST = "api.klavi.ai";
23
24 // dev
25 private final static String HOST = "api-testing.klavi.ai";
26
27 public static void main(String[] args) throws Exception {
28// buildCreateConsentSignature();
29// buildGetInstitutionListSignature();
30 buildSubmitCredentialsSignature();
31// buildCheckStatusSignature();
32// buildSubmitMFAInfoSignature();
33// buildUpdateProductsSignature();
34// buildDeleteAccountSignature();
35 }
36
37 private static void buildCreateConsentSignature() throws Exception {
38 String httpRequestMethod = "POST";
39 String canonicalUri = "/link/external/v3/createConsent";
40 String canonicalQueryString = "";
41 String canonicalHeaders = "content-type:application/json;charset=UTF-8\n" + "host:" + HOST + "\n";
42 String signedHeaders = "content-type;host";
43 String payload = "{\"email\":\"jyNRPSqqXaGuhBWlgh1ErMoiaiEPSODaja3Jiz1GWUPKhD8zSMXub/MeRZRkLHe" +
44 "/2VLqHaGBilY6Da02lJb8ibdTFGK1d0LN63FeE5/0f5Ysih3D5eMNL13I4XMHMwZ+ZK0lJSiWUxLq+5tDVcgoZScuv4pa" +
45 "/WPXlcZI9VD+410=\",\"phone\":\"e6m4qEIaqVDA7o33e8NrBahBjpzdUZYSnLYjDcoeKq56lrxPR9Snkyn50r" +
46 "+L7jQ3mY6AiTE/z0gornvxxRBjeiQqOpYNUlHrq2H6XM2cDSexsziO6ZKL2PVawM2Sbf5sezVuRYACEdytUvry" +
47 "/AhsegyNUPMPbWTYMdOUx2ffq3c=\"," +
48 "\"isKi\":\"kvG6zBoklC8LCpnJ25HtcPc7acYuLk0yUWMS0I8mgLAinP5BJIWAKFqLDwQcJP7UZMYE7Gb8ufz9Rbu3gzygiI" +
49 "+KzyirEpOwUDNYpYdkH+rbXbsQlNKSiriIizBL6FtQYg/LUeYtAFBAUXWQh1M33cTNYcK9DfclDaj7ye5Pzkw=\"}";
50 String timestamp = getTimestamp();
51 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
52 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
53 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
54
55 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
56 payload, date, timestamp);
57 }
58
59 private static void buildGetInstitutionListSignature() throws Exception {
60 String httpRequestMethod = "GET";
61 String canonicalUri = "/link/external/v3/getInstitutionList";
62 String canonicalQueryString = "";
63 String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n" + "host:" + HOST + "\n";
64 String signedHeaders = "content-type;host";
65 String payload = "";
66 String timestamp = getTimestamp();
67 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
68 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
69 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
70
71 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
72 payload, date, timestamp);
73 }
74
75 private static void buildSubmitCredentialsSignature() throws Exception {
76 String httpRequestMethod = "POST";
77 String canonicalUri = "/link/external/v3/submitCredentials";
78 String canonicalQueryString = "";
79 String canonicalHeaders = "content-type:application/json;charset=UTF-8\n" + "host:" + HOST + "\n";
80 String signedHeaders = "content-type;host";
81 String payload = "{\"consentId\":\"202cb962ac59075b964b07152d234b70\"," +
82 "\"email\":\"aw/6B0KMZRVbBIdUp0uB/pZz97ZJfJgO4LaBRm7bBvRTo25HNwW0GkcELlFuMuw0krXDQO9gLqat49LA" +
83 "/tgofERQrOJe0saTJt0bgue3FLSgjPP06HLdCHMgY2ApwUlIO/1otGuNYMa+m7zeT7+Cs3zEscPfwU3bC4pz39zLwNM=\"," +
84 "\"agency\":\"DvZXoz6wMQHfys81ak4GHK+A2/F3ClQ7rV2JxXEGDDBjenQG3rb/MvX" +
85 "+PKTLaUCiL92ym2bEkfEzvkzJTvdQuZV1dXwyVjbsSByFA" +
86 "+JbOcRdn0LtyFxcJzYLmPUwnwAVarWhKiwguE2cNbKqpdxmxkGVAN6g2ghnC4zNPpXFsYA=\"," +
87 "\"account\":\"evltwIAmaE12SPDKwKspH9D9PDA9HbAXq1xkaMShZflWPCIwODyXZx6alFAz7U443ZZX0wfuMc" +
88 "+IHcFBKYvjDFoVds0NfQjVfBvx2lcj/WXx9ZQpUjkUsOfbZnfUg2SW79Y5Y7PEaPFxsKgYXb1yZNRQwvmLLrbRZyDDxNnDnIA" +
89 "=\",\"password\":\"XfGzloZbejN+S/4+be31aJr8HWdImYuMUZkn1nudYHwVvzvM4se6CH89gekXOUFvn1w" +
90 "/VFWHu1JHBEIoiP57Qc3eJ1YbnddKl0Px1QqwVVW/+9shxbPmNoM36WY6Uebn/kxB0iGlsyhNytyBwVPyjow298" +
91 "/UMuNw0PRe7esZKSo=\",\"institutionCode\":\"237\"," +
92 "\"accountLevel\":\"VmWC5cxnerhoiEAD4sYNEmjEmG87XYymV6f1MSULPY8ETnRN" +
93 "+SQM3eUAKUshL6k05JGtkkKfou52RsCYa7Mtec8ZurRdx6k6C1+dRNyZmsrVl9OtQBtvwxgtdlENgzRaombKH" +
94 "/18kxnDPEBXCBf3FV7dtRaXL7j6CXFq3O86a4g=\"}";
95 String timestamp = getTimestamp();
96 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
97 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
98 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
99
100 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
101 payload, date, timestamp);
102 }
103
104 private static void buildCheckStatusSignature() throws Exception {
105 String httpRequestMethod = "GET";
106 String canonicalUri = "/link/external/v3/checkStatus";
107 String canonicalQueryString = "traceId=kJuktDQkvHezWtYyiPYOKwxr2ddByeb8";
108 String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n" + "host:" + HOST + "\n";
109 String signedHeaders = "content-type;host";
110 String payload = "";
111 String timestamp = getTimestamp();
112 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
113 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
114 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
115
116 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
117 payload, date, timestamp);
118 }
119
120 private static void buildSubmitMFAInfoSignature() throws Exception {
121 String httpRequestMethod = "POST";
122 String canonicalUri = "/link/external/v3/submitMFAInfo";
123 String canonicalQueryString = "";
124 String canonicalHeaders = "content-type:application/json;charset=UTF-8\n" + "host:" + HOST + "\n";
125 String signedHeaders = "content-type;host";
126 String payload = "{\"traceId\":\"kJuktDQkvHezWtYyiPYOKwxr2ddByeb8\"," +
127 "\"code\":\"mb6kW19VXYU9ZvRb3TzUJ0jeei2ACETOZkt67J5zBTIbDW" +
128 "+7Y3qnq7WI3gHckFCsebGxArhobZ78ZhTVOZpApiJ9fBUXA7AX3b9LK8daCHtAodQquT6TcW0Flt2v305ELB4HGNwLFR3EO9L" +
129 "/vX5UU1VjSe3+pGGJFl7y554nwmM=\"}";
130 System.out.println(payload);
131 String timestamp = getTimestamp();
132 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
133 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
134 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
135
136 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
137 payload, date, timestamp);
138 }
139
140 private static void buildUpdateProductsSignature() throws Exception {
141 String httpRequestMethod = "POST";
142 String canonicalUri = "/link/external/v3/updateProducts";
143 String canonicalQueryString = "";
144 String canonicalHeaders = "content-type:application/json;charset=UTF-8\n" + "host:" + HOST + "\n";
145 String signedHeaders = "content-type;host";
146 String payload = "{\"connectionKey\":\"1033b652e0c84acab018a9482cae3176\"}";
147 String timestamp = getTimestamp();
148 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
149 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
150 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
151
152 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
153 payload, date, timestamp);
154 }
155
156 private static void buildDeleteAccountSignature() throws Exception {
157 String httpRequestMethod = "POST";
158 String canonicalUri = "/link/external/v3/deleteAccount";
159 String canonicalQueryString = "";
160 String canonicalHeaders = "content-type:application/json;charset=UTF-8\n" + "host:" + HOST + "\n";
161 String signedHeaders = "content-type;host";
162 String payload = "{\"connectionKey\":\"1033b652e0c84acab018a9482cae3176\"}";
163 String timestamp = getTimestamp();
164 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
165 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
166 String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
167
168 buildSignature(httpRequestMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders,
169 payload, date, timestamp);
170 }
171
172 private static void buildSignature(String httpRequestMethod, String canonicalUri, String canonicalQueryString,
173 String canonicalHeaders,
174 String signedHeaders, String payload, String date, String timestamp) throws Exception {
175 String algorithm = "K1-HMAC-SHA256";
176 String service = "cbms";
177
178 // step 1: build canonical request string
179 System.out.println(payload);
180 String hashedRequestPayload = sha256Hex(payload);
181 String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
182 + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
183 System.out.println("**********canonicalRequest**********");
184 System.out.println(canonicalRequest);
185
186 // step 2: build string to sign
187 String credentialScope = date + "/" + service + "/" + "k1_request";
188 String hashedCanonicalRequest = sha256Hex(canonicalRequest);
189 String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
190 System.out.println("\n\n**********stringToSign**********");
191 System.out.println(stringToSign);
192
193 // step 3: sign string
194 byte[] secretDate = hmac256(("K1" + SECRET_KEY).getBytes(UTF8), date);
195 System.out.println("secretDate:" + HexUtil.encodeHexStr(secretDate));
196 byte[] secretService = hmac256(secretDate, service);
197 System.out.println("secretService:" + HexUtil.encodeHexStr(secretService));
198 byte[] secretSigning = hmac256(secretService, "k1_request");
199 System.out.println("secretSigning:" + HexUtil.encodeHexStr(secretSigning));
200 String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
201 System.out.println("\n\n************signature:" + signature);
202
203 // step 4: build authorization
204 String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "
205 + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
206 System.out.println("************authorization:" + authorization);
207 }
208
209 private static byte[] hmac256(byte[] key, String msg) throws Exception {
210 Mac mac = Mac.getInstance("HmacSHA256");
211 SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
212 mac.init(secretKeySpec);
213 return mac.doFinal(msg.getBytes(UTF8));
214 }
215
216 private static String sha256Hex(String s) throws Exception {
217 MessageDigest md = MessageDigest.getInstance("SHA-256");
218 byte[] d = md.digest(s.getBytes(UTF8));
219 return DatatypeConverter.printHexBinary(d).toLowerCase();
220 }
221
222 private static String getTimestamp() {
223 return String.valueOf(System.currentTimeMillis() / 1000);
224 }
225}
Updated 06 Dec 2023
Did this page help you?