В настоящее время я работаю в финансовом приложении, использующем php. Так что я интегрирован со сторонним API для извлечения пользовательских данных.
На основе интеграции они проходят аутентификацию с подписью и полезной нагрузкой.
Согласно документу, я все сделал правильно с моей точки зрения, но я получил ответ как
SignatureDoesNotMatch
Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи.
Согласно документу:
Расчет подписи:
Запросы, при необходимости, должны быть подписаны отправителем. Подпись запроса рассчитывается следующим образом:
6) Создайте дайджест SHA1 для сжатой полезной нагрузки.
7) Base16 кодирует сгенерированный дайджест SHA1.
8) Зашифруйте закодированный дайджест с помощью предоставленного Perfios закрытого ключа RSA.
9) Base16 кодирует зашифрованный дайджест.
Вот мой сценарий:
$condense_payload ='<payload><vendorId>test</vendorId><txnId>dummyApplicationId</txnId><emailId>'.$emailid.'</emailId><destination>netbankingFetch</destination><returnUrl>https://www.google.com</returnUrl></payload>';$condense_payload_updated = trim(preg_replace('/(?<=\>)(\r?\n)|(\r?\n)(?=\<\/)/', $condense_payload));$payload ='
<payload>
<vendorId>test</vendorId>
<txnId>dummyApplicationId</txnId>
<emailId>'.$emailid.'</emailId>
<destination>netbankingFetch</destination>
<returnUrl>https://www.google.com</returnUrl>
</payload>';
/* Convert to Sha1 */
$sha1_convert = sha1($condense_payload_updated);
/* Convert to Hex (base16) */
$first_base16_convert=bin2hex($sha1_convert);$fp = fopen("private_key", "r");
$private_key_string = fread($fp, 8192);
fclose($fp);
/* Convert to private key */
$private_key = openssl_get_privatekey($private_key_string);
$encrypted_private="";/* Encrypt digest using key */
openssl_private_encrypt($first_base16_convert, $encrypted_private, $private_key, OPENSSL_PKCS1_PADDING);
/* Convert to Hex (base16) */
$signature=bin2hex($encrypted_private);
поэтому здесь генерируется полезная нагрузка и подпись и отправляется URL с методом post:
<html>
<body onload='document.autoform.submit();'>
<form name='autoform' method='post' action='https://demo.perfios.com/KuberaVault/insights/start'>
<input type='hidden' name='payload' value='<?php echo $payload; ?>' />
<input type='hidden' name='signature' value='<?php echo $signature; ?>'/>
</body>
</html>
Итак, наконец я получил:
SignatureDoesNotMatch
Запрос
рассчитанная нами подпись не соответствует предоставленной вами подписи.
Команда поддержки Api предоставила пример кода Java, я соблюдаю и запускаю Java, его работа.
вот код java:
package javaapplication1;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.security.Key;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import javax.crypto.Cipher;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.util.encoders.Hex;
public class JavaApplication1 {
static String email = "[email protected]";
static String server = "demo.test.com";
public static String vendor = "test";
public static String returnURL = "https://www.google.com";static String privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEpQIBAAKCAQEAx76oeNWYPkAbbSPyvJdfgfdgcPkQvAMvIHCPgY9yNdN/qsYMHytyit\n" +
"xdO0aTatgfS/ig4zmqKFVpC9o2YMyQ7E1FYNcl/ev++r4nV+qVXA1OKcsSv4Kbj/\n" +
fgdfg"iNwxGmnhBsRDswY/dEZZDN9RisRpo9NRSOskGRv+nLEA2dLgj0/f9SSzykz3cxAP\n" +
"bq6bV0unie5C8r6RALj+hTLU7B7QF88SkDsFx0/TYQe4H9QJtFMWJtOnhumY5Ku6\n" +
"CL4OdZrtz71y4ji8IxQxv2nyqdfgfd0JwYQ4rG84uzJQeRQf2RaJLhnSdfQnonDkP7L1z\n" +
"NSizzi8VgHI+GVIo9FrLj7DVo+fFzMucbsvvNQIDAQABAoIBAQCMVKOR+SYzneBm\n" +
"5hmUa2CxW5sVb7qHj54iiwLj4EYY2EnIaljjol+eh56Qrb2fpWiV3FZnQdspn/md\n" +
"i7W3JBngYABjwmN0/20UVL3cErVZN/XqgiFtKp2gfhfgI3BgPI/YYIWyVKRNJGt/z6Rf6\n" +
"0+zImQLMbUGNHkHlxuSjas+CL93sYrXo52TXqZgkfghgf40gEkQVLE+SLrtXTFiOOlX/s\n" +
"WWXyeUY14hl+oVQLmEO6UZd532bxAE0VlIV6Vr2pE3gJqEyaAoGgkT3inxvRPiek\n" +
"swRm9OONWZD9frKXYqabJTsd87623Czg5h2WGimsN4fZ+LfyBXul24KKVeMDELHn\n" +
"GvdRm95lAoGBAPMQRrb3iB8oYJc+4KwbtWR/vTQW++G69CeyIfD7WM0Ix3Gy0wod\n" +
"FwIeKSkYsZ/R5n+9Ucx/RVFv7X86YzYajhH3hl+8/q4c+L1yAGS5hW3m21gIViDt\n" +
"k1h3gKLI5o4EKGhCRX1teSoZ+n4G7KlYbJas8h5MX3u81GhKRmiVItr/AoGBANJg\n" +
"KoIhxKsyNRccULosYZBGc3vpkFtpHeZ5w0qxbXaGveUIKvqzUqonGy0o3yqVNRrH\n" +
"JJREHss+5/HqeuauawKUYLWapCqmVF6IlDc1PxTw+BLDzgzMlX2o43951iTMJXkd\n" +
"80MOujsnyTdZq7wAzR7KNR3U/OjDFlcORxhCGrnLAoGBAONZcgtp9NTP+6j8k0Ho\n" +
"mP5rzRmP9gHp0L3gjIbPUvxVHdhnn6ZyFzdP5sgd5ObMeoE5H+3bjYbi3o6Gmo3c\n" +
"wM5lbDbYnI9XYgIxQ9TzAq8NpFTvV0Btd8jj3lpk9+IWWYVLl5v+bbrHmdmPuIWd\n" +
"w9Qb6EwWu6kNss/pyXnBJV0ZAoGAPj+2VEsppn50tyHpwSzgsZAnG8NAs8umzUu6\n" +
"PZ/ChA/aoKqKDSSCkVaA9Bvj7PW5gPLsH/MIKZuzhiGbvCZgA6Nj+liHuxb8X/yJ\n" +
"3swink+vF95YWfEvSr9ukYm7k6fUbsIt+OmisV5Ua8xcxIR4LWQn02vyae1P7vKK\n" +
"luL4hYECgYEAmSiiHa4bSLF8MT/IbL2YIrxK4yatABvVWZLkAV7hiFJWeEhLCmCd\n" +
"OKcX8QSq9lT6TbS6NCEfHfCR0FFrny4nZMT3YnyDkgrYOiHhZL/YVfr3Izr62Gcy\n" +
"PizNJH/JWoNDonAuFi+eQjgBRNfd894pMeCT4tMu2nE1SOEafzykzPA=\n" +
"-----END RSA PRIVATE KEY-----";
static final String DIGEST_ALGO = "SHA-1";
static final String ENCRYPTION_ALGO = "RSA/ECB/PKCS1Padding";
static String applicationId = "dummyApplicationId";
static String perfiosTransactionId = "PLEASE UPDATE ME";
static String format = "xml";
public static String payloadStatement = "<payload>\n"+ "<vendorId>"+ vendor
+ "</vendorId>\n"+ "<txnId>"+ applicationId
+ "</txnId>\n"+ "<yearMonthFrom>2015-06</yearMonthFrom>\n" +
"<yearMonthTo>2016-02</yearMonthTo>"+ "<emailId>#email#</emailId>\n<destination>statement</destination>\n"+ "<returnUrl>" + returnURL + "</returnUrl>\n" + "</payload>";public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
if (args.length > 1 && args[0] != null) {
if ("encrypt".equals(args[0])) {
if (args[1] != null) {
String encrypt = encrypt(args[1], ENCRYPTION_ALGO,
buildPublicKey(privateKey));
System.out.print(encrypt);
} else {
throw new Exception("Wrong number of arguments provided.");
}
} else if ("signature".equals(args[0])) {
if (args[1] != null) {
String signature = getSignature(ENCRYPTION_ALGO,
DIGEST_ALGO, buildPrivateKey(privateKey), args[1]);
System.out.print(signature);
} else {
throw new Exception("Wrong number of arguments provided.");
}
}
} else {
String argPerfiosTxnId = System.getProperty("perfiosTransactionId");
if (argPerfiosTxnId != null)
perfiosTransactionId = argPerfiosTxnId;
String argTxnId = System.getProperty("applicationId");
if (argTxnId != null)
applicationId = argTxnId;
System.out
.println("This program helps you try out Perfios APIs to initiate and track Perfios online transactions. "+ "\nIt generates HTML files that can be opened in a browser to initiate or track the transaction.");
/** Create a folder for customer */
File folder = new File(vendor);
String message = "\n\nnetbanking and statement APIs are the APIs to start the transaction. \n"+ "Only integration supported to start the transaction is through autopost form as in the netbanking and statement htmls.\n"+ "All other APIs are xml over HTTP and do not need browser to be present.\n"+ "You can directly invoke those APIs using other mechanisms.\n\n"+ "Trying this program:\n"+ "\t(1)First run the program and it will generate the netbanking and statement upload files.\n"+ "\t(2)Depending upon whether you have requested these features to be available, you should be able to start the transactions.\n"+ "\t(3)netbanking and statment HTML start the perfios transaction using browser to browser integration.\n"+ "\t\t(3.1)To start netbanking transaction, open netbanking_* file in your browser..\n"+ "\t\t(3.2)To start statement upload transaction, open statement_* file in your browser..\n"+ "\t(4)You can then check the status of all transactions using txnstatus API.\n"+ "\t\t(4.1)To check the status of transaction, open txnstatus_* file in your browser. \n"+ "\t\t\tThis API could also be accessed without a browser. Without autoform load request\n"+ "\t(5)To retrieve a report, you will need to re-run the program. Change the value of perfiosTransactionId variable in your program.\n"+ "\t\t Compile and run the java program. open retrieve_* file in your browser. This API could also be accessed without a browser.\n"+ "\t\t Without autoform load request\n"+ "\t(5)To delete the transaction related artifacts, you will need to re-run the program. \n"+ "\t\tChange the value of perfiosTransactionId variable in your program. Compile and run the java program. open delete_* \n"+ "\t\tfile in your browser. This API could also be accessed without a browser. Without autoform load request\n"+ "You can pass applicationId and perfiosTransactionId through command line by providing system properties too. "+ "For e.g. java -DperfiosTransactionId=HDJDJ com.perfios.sample.OnlineSampleCapitalInfusionIndia\n"+ "\t(6)For more details please refer the API guide.\n";
System.out.println(message);
if (!folder.exists())
folder.mkdir();
System.out
.println("Your files will be created in the following location: "+ folder.getAbsolutePath());
/** Create files for the customer */
String myHTML = genericCreateHTML(JavaApplication1.payloadStatement);
createFile("statement", myHTML);}
}
private static void createFile(String classification, String myHTML) {
String filename = vendor + "/" + classification + "_" + server
+ ".html";
try {
PrintWriter out = new PrintWriter(filename);
out.print(myHTML);
out.close();
System.out.println("Successfully created file " + filename);
} catch (Exception e) {
System.out.println("Error while creating file " + filename);
e.printStackTrace();
}
}
private static String genericCreateHTML(String payload) {
return genericCreateHTML(payload, null);
}
private static String genericCreateHTML(String payload, String operation) {
String emailEncrypted = encrypt(email, ENCRYPTION_ALGO,
buildPublicKey(privateKey));
payload = payload.replaceAll("\n", "");
payload = payload.replaceAll("#email#", emailEncrypted);
String signature = getSignature(ENCRYPTION_ALGO, DIGEST_ALGO,
buildPrivateKey(privateKey), payload);
if (operation == null)
operation = "start";
String myHTML = "<html>\n"+ " <body onload='document.autoform.submit();'>\n"+ " <form name='autoform' method='post' action='https://"+ server + "/KuberaVault/insights/" + operation + "'>\n"+ " <input type='hidden' name='payload' value='" + payload
+ "'>\n" + " <input type='hidden' name='signature' value='"+ signature + "'>\n" + " </form>\n" + " </body>\n"+ "</html>\n";
return myHTML;
}
public static String getSignature(String encryptAlgo, String digestAlgo,
Key k, String xml) {
String dig = makeDigest(xml, digestAlgo);
return encrypt(dig, encryptAlgo, k);
}
private static PrivateKey buildPrivateKey(String privateKeySerialized) {
StringReader reader = new StringReader(privateKeySerialized);
PrivateKey pKey = null;
try {
PEMReader pemReader = new PEMReader(reader);
KeyPair keyPair = (KeyPair) pemReader.readObject();
pKey = keyPair.getPrivate();
pemReader.close();
} catch (IOException i) {
i.printStackTrace();
}
return pKey;
}
private static PublicKey buildPublicKey(String privateKeySerialized) {
StringReader reader = new StringReader(privateKeySerialized);
PublicKey pKey = null;
try {
PEMReader pemReader = new PEMReader(reader);
KeyPair keyPair = (KeyPair) pemReader.readObject();
pKey = keyPair.getPublic();
pemReader.close();
} catch (IOException i) {
i.printStackTrace();
}
return pKey;
}
public static String makeDigest(String payload, String digestAlgo) {
String strDigest = "";
try {
MessageDigest md = MessageDigest.getInstance(digestAlgo);
md.update(payload.getBytes("UTF-8"));
byte[] digest = md.digest();
byte[] encoded = Hex.encode(digest);
strDigest = new String(encoded);
} catch (Exception ex) {
ex.printStackTrace();
}
return strDigest;
}
public static String encrypt(String raw, String encryptAlgo, Key k) {String strEncrypted = "";
try {
Cipher cipher = Cipher.getInstance(encryptAlgo);
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] encrypted = cipher.doFinal(raw.getBytes("UTF-8"));
byte[] encoded = Hex.encode(encrypted);
strEncrypted = new String(encoded);
} catch (Exception ex) {
ex.printStackTrace();
}
return strEncrypted;
}
}
С моей точки зрения, я создал подпись и полезную нагрузку, но я не знаю, где не так с моим сценарием. Кто-нибудь может мне помочь?
Он пытался исправить некоторые возможные проблемы в вашем коде. Может быть, попробовать что-то подобное в качестве основы.
<?php
$email = "[email protected]";
$server = "demo.perfios.com";
$vendor = "finmomenta";
$returnURL = "https://www.google.com";
$applicationId = "dummyApplicationId";
$perfiosTransactionId = "PLEASE UPDATE ME";
$format = "xml";
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
"MIIEpQIBAAKCAQEAx76oeNWYPkAbbSPyvJcPkQvAMvIHCPgY9yNdN/qsYMHytyit\n" .
"xdO0aTatgfS/ig4zmqKFVpC9o2YMyQ7E1FYNcl/ev++r4nV+qVXA1OKcsSv4Kbj/\n" .
"iNwxGmnhBsRDswY/dEZZDN9RisRpo9NRSOskGRv+nLEA2dLgj0/f9SSzykz3cxAP\n" .
"bq6bV0unie5C8r6RALj+hTLU7B7QF88SkDsFx0/TYQe4H9QJtFMWJtOnhumY5Ku6\n" .
"CL4OdZrtz71y4ji8IxQxv2nyq0JwYQ4rG84uzJQeRQf2RaJLhnSdfQnonDkP7L1z\n" .
"NSizzi8VgHI+GVIo9FrLj7DVo+fFzMucbsvvNQIDAQABAoIBAQCMVKOR+SYzneBm\n" .
"5hmUa2CxW5sVb7qHj54iiwLj4EYY2EnIaljjol+eh56Qrb2fpWiV3FZnQdspn/md\n" .
"i7W3JBngYABjwmN0/20UVL3cErVZN/XqgiFtKp2I3BgPI/YYIWyVKRNJGt/z6Rf6\n" .
"0+zImQLMbUGNHkHlxuSjas+CL93sYrXo52TXqZgk40gEkQVLE+SLrtXTFiOOlX/s\n" .
"WWXyeUY14hl+oVQLmEO6UZd532bxAE0VlIV6Vr2pE3gJqEyaAoGgkT3inxvRPiek\n" .
"swRm9OONWZD9frKXYqabJTsd87623Czg5h2WGimsN4fZ+LfyBXul24KKVeMDELHn\n" .
"GvdRm95lAoGBAPMQRrb3iB8oYJc+4KwbtWR/vTQW++G69CeyIfD7WM0Ix3Gy0wod\n" .
"FwIeKSkYsZ/R5n+9Ucx/RVFv7X86YzYajhH3hl+8/q4c+L1yAGS5hW3m21gIViDt\n" .
"k1h3gKLI5o4EKGhCRX1teSoZ+n4G7KlYbJas8h5MX3u81GhKRmiVItr/AoGBANJg\n" .
"KoIhxKsyNRccULosYZBGc3vpkFtpHeZ5w0qxbXaGveUIKvqzUqonGy0o3yqVNRrH\n" .
"JJREHss+5/HqeuauawKUYLWapCqmVF6IlDc1PxTw+BLDzgzMlX2o43951iTMJXkd\n" .
"80MOujsnyTdZq7wAzR7KNR3U/OjDFlcORxhCGrnLAoGBAONZcgtp9NTP+6j8k0Ho\n" .
"mP5rzRmP9gHp0L3gjIbPUvxVHdhnn6ZyFzdP5sgd5ObMeoE5H+3bjYbi3o6Gmo3c\n" .
"wM5lbDbYnI9XYgIxQ9TzAq8NpFTvV0Btd8jj3lpk9+IWWYVLl5v+bbrHmdmPuIWd\n" .
"w9Qb6EwWu6kNss/pyXnBJV0ZAoGAPj+2VEsppn50tyHpwSzgsZAnG8NAs8umzUu6\n" .
"PZ/ChA/aoKqKDSSCkVaA9Bvj7PW5gPLsH/MIKZuzhiGbvCZgA6Nj+liHuxb8X/yJ\n" .
"3swink+vF95YWfEvSr9ukYm7k6fUbsIt+OmisV5Ua8xcxIR4LWQn02vyae1P7vKK\n" .
"luL4hYECgYEAmSiiHa4bSLF8MT/IbL2YIrxK4yatABvVWZLkAV7hiFJWeEhLCmCd\n" .
"OKcX8QSq9lT6TbS6NCEfHfCR0FFrny4nZMT3YnyDkgrYOiHhZL/YVfr3Izr62Gcy\n" .
"PizNJH/JWoNDonAuFi+eQjgBRNfd894pMeCT4tMu2nE1SOEafzykzPA=\n" .
"-----END RSA PRIVATE KEY-----";$payloadStatement = "<payload>\n" .
"<vendorId>" . $vendor . "</vendorId>\n" .
"<txnId>" . $applicationId . "</txnId>\n" .
"<yearMonthFrom>2017-06</yearMonthFrom>\n" .
"<yearMonthTo>2017-12</yearMonthTo>" .
"<emailId>#email#</emailId>\n<destination>statement</destination>\n" .
"<returnUrl>" . $returnURL . "</returnUrl>\n" .
"</payload>";echo genericCreateHTML($payloadStatement, 'start', $email, $server, $privateKey);
function genericCreateHTML($payload, $operation, $email, $server, $privateKey)
{
$email = encryptData($email, $privateKey);
$payload = str_replace("#email#", $email, $payload);
// Remove all line breaks
$payload = str_replace("\n", "", $payload);
$signature = getSignature($payload, $privateKey);
$html = "<html>\n" . " <body onload='document.autoform.submit();'>\n" .
" <form name='autoform' method='post' action='https://" . $server . "/KuberaVault/insights/" . $operation . "'>\n" .
" <input type='hidden' name='payload' value='" . $payload . "'>\n" .
" <input type='hidden' name='signature' value='" . $signature . "'>\n" .
" </form>\n" . " </body>\n" .
"</html>\n";
return $html;
}
function getSignature($data, $privateKey)
{
// Make digest
$digest = sha1($data);
// Encrypt
return encryptData($digest, $privateKey);
}
function encryptData($raw, $privateKey)
{
$privateKey = openssl_pkey_get_private($privateKey);
if (!$privateKey) {
throw new RuntimeException('Invalid private key or passphrase');
}
// Encrypt digest using the key
$encrypted = "";
openssl_private_encrypt($raw, $encrypted, $privateKey, OPENSSL_PKCS1_PADDING);
// Convert to Hex (base16)
$result = bin2hex($encrypted);
return $result;
}
Других решений пока нет …