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
|
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
/**
* Snippet to sign message with <strong>PKCS #8 private key</strong>.
* <p><strong>Note: </strong></p> Changes might be required if your private key is in a format different that <strong>PKCS #8</strong>.
*/
public class ZenkiSnippet {
private static final String BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----";
private static final String END_PRIVATE_KEY = "-----END PRIVATE KEY-----";
private static final String EMPTY_STRING = "";
private static final String BREAK_LINE = "\n";
/**
* Sample base64 private key (<strong>PKCS #8</strong>) format.
**/
private static final String BASE_64_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
"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\n" +
"-----END PRIVATE KEY-----";
/**
* Path for sample private key file (<strong>PKCS #8</strong>) format.
**/
private static final String PRIVATE_KEY_FILE_PATH = "/path/to/my/file";
// Sample JSON purchase data.
private static final String JSON_PURCHASE_DATA = "{\"version\":\"v1.1.0\",\"country\":\"US\",\"shopperCartId\":\"l93hyghr9hojqinx\",\"merchantOrderId\":\"l93hyghr4yty9jgm\",\"shopperEmail\":\"hello@zenki.fi\",\"purchaseSummary\":{\"currency\":\"USD\",\"totalItemsAmount\":\"0.5\",\"shipmentAmount\":\"0.25\",\"subtotalAmount\":\"0.75\",\"taxesAmount\":\"0.125\",\"localTaxesAmount\":\"0.125\",\"importCosts\":\"0.125\",\"discountAmount\":\"0.25\",\"additionalCharges\":{\"perquisite\":\"0.125\"},\"grandTotalAmount\":\"1\"},\"serviceType\":\"SERVICE\",\"items\":[{\"itemId\":\"l93hyghr5hp3lxcp\",\"price\":\"0.5\",\"quantity\":\"1\",\"productName\":\"Javascript\",\"thumbnailUrl\":\"https:\/\/tshirts.boutique\/wp-content\/uploads\/2022\/09\/12124-65.jpg\",\"metadata\":{\"size\":\"L\"}}],\"zenkipayKey\":\"e77e5b666253243e9179ff4d33fe364ec88aacf9240e5e7673e474255e4a900c\",\"metadata\":{\"anotherId\":\"l93hyghrcjs78929\"}}";
public static void main(String[] args) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
System.out.println("Signature: " + signMessageWithPkFromFile()); // Snippet to sing message getting private key from file.
System.out.println("Signature: " + signMessageWithPkBase64()); // Snippet to sing message getting private key from base64 string.
}
public static String signMessageWithPkFromFile() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
PrivateKey privateKey = getPKFromFile();
Signature signatureProvider = Signature.getInstance("SHA256withRSA");
signatureProvider.initSign(privateKey); // Private key
signatureProvider.update(JSON_PURCHASE_DATA.getBytes()); // Message to sign (in bytes)
byte[] signature = signatureProvider.sign(); // Signature
return Base64.getEncoder().encodeToString(signature); // Signature encoded in base64
}
public static String signMessageWithPkBase64() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
PrivateKey privateKey = getPKFromBase64String();
Signature signatureProvider = Signature.getInstance("SHA256withRSA");
signatureProvider.initSign(privateKey); // Private key
signatureProvider.update(JSON_PURCHASE_DATA.getBytes()); // Message to sign (in bytes)
byte[] signature = signatureProvider.sign(); // Signature
return Base64.getEncoder().encodeToString(signature); // Signature encoded in base64
}
private static PrivateKey getPKFromFile() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
byte[] privateKey = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILE_PATH)); // Getting file from filesystem
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey, "RSA");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(keySpec);
}
private static PrivateKey getPKFromBase64String() throws NoSuchAlgorithmException, InvalidKeySpecException {
String formattedKeyString = removePrivateKeyHeaders(BASE_64_PRIVATE_KEY);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(formattedKeyString), "RSA");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(keySpec);
}
private static String removePrivateKeyHeaders(String keyString) {
return keyString
.replace(BREAK_LINE, EMPTY_STRING)
.replace(BEGIN_PRIVATE_KEY, EMPTY_STRING)
.replace(END_PRIVATE_KEY, EMPTY_STRING);
}
}
|