Signature is the signed String created at the previous step
As the fifth step, you need to sign the previously created Message with your private key .
The signature should be signed using the rsa-sha256
algorithm and should be encoded in Base64
.
(request-target): post /g_business/v1/payments
host: staging.authservices.satispay.com
date: Mon, 18 Mar 2019 15:10:24 +0000
digest: SHA-256=ZML76UQPYzw5yDTmhySnU1S8nmqGde/jhqOG5rpfVSI=
XyuV4SB3TnwXsPj5d9m/3Ju+QvegeuzDp23IpHEJ18W7gVIVUFBBraDGNSTYk4ohJfx0xsRj2B14PDLZu+z7SVeDuUQVk5mJNZnvf9lbQ0MN1W0qT/lWmsLAusDZ2TabxiDwahPNjA9ZpQOGo6sjoAGK8TSejMxffrQI0EV4mYo6KAl+sk4DGjV7GM7F/imgsw17ji1x8HpRO72slgbOPPHdjADDmGUEgSd0/MhcCHbHH6XIq+VkGSkQ83xNe1t85gQtVYh96oj6q7qz/qEhNbbGj50LhdYGv2tTtUNXU+Zk5NMNIIXwk+OmCq8mK7M/6Dmfd/prklsS7PrCCnRDnpdnRVJeFRjJMnKBc8A/ITS7jjP6vU7GZ9ltmPjPKt6/GgnZWTYjcsnqcCifyoDJt0egLimkkp8HyLWsDke08DAJHR0ylKbYc/kVwabhlZGzkDMb4DyMi4op6xp5+k8pQb6IXuI4YzraPUOblfRi/mWYUDUUfR0GPfkPIht2AjNbdvZ+bbvhsoFY57oofBQaXIcYbecQPH6la4bPADJCM3R+uFeMuMtmg7GUTl7uOOSIEs1VJRhJaBkOsuTIs3d/gk6YGOdff+1MXaopoiBxoA0+1g/9g+jVA3xQnTk9RfRzb8WHB1LkqbATHwt5rQSNQKSpvz/wCejlb566P2Ffc8w=
BewarePlease note that the Message must be signed, not encrypted.
Code sample 3/4
$bodyObject = [
'flow' => 'MATCH_CODE',
'amount_unit' => 100,
'currency' => 'EUR'
];
$body = json_encode($bodyObject);
echo "body:\n";
echo $body . "\n";
$digest = "SHA-256=" . base64_encode(hash("sha256", $body, true));
echo "\ndigest:\n";
echo $digest . "\n";
$date = date('r');
echo "\ndate:\n";
echo $date . "\n";
$message = "(request-target): post /g_business/v1/payments
host: staging.authservices.satispay.com
date: $date
digest: $digest";
echo "\nmessage:\n";
echo $message . "\n";
$privateKey = file_get_contents('private.pem'); // your private key
echo "\nprivate.pem:\n";
echo $privateKey . "\n";
openssl_sign($message, $signatureRaw, $privateKey, OPENSSL_ALGO_SHA256);
$signature = base64_encode($signatureRaw);
echo "\nsignature:\n";
echo $signature . "\n";
const crypto = require('crypto');
const fs = require('fs');
const bodyObject = {
flow: 'MATCH_CODE',
amount_unit: 100,
currency: 'EUR'
};
const body = JSON.stringify(bodyObject);
console.log("\nbody:");
console.log(body);
const digest = "SHA-256=" + crypto.createHash('sha256').update(body).digest('base64');
console.log("\ndigest:");
console.log(digest);
const date = new Date().toUTCString();
console.log("\ndate:");
console.log(date);
const message = "(request-target): post /g_business/v1/payments\n" +
"host: staging.authservices.satispay.com\n" +
"date: " + date + "\n" +
"digest: " + digest;
console.log("\nmessage:");
console.log(message);
const privateKey = fs.readFileSync('private.pem', 'utf-8');
console.log("\nprivate.pem:");
console.log(privateKey);
const sign = crypto.createSign('RSA-SHA256');
sign.update(message);
const signatureRaw = sign.sign(privateKey, 'base64');
const signature = Buffer.from(signatureRaw, 'base64').toString('base64');
console.log("\nsignature:");
console.log(signature);
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONObject;
public class Satispay {
public static void main(String[] args) {
JSONObject bodyObject = new JSONObject()
.put("flow", "MATCH_CODE")
.put("amount_unit", 100)
.put("currency", "EUR");
String body = bodyObject.toString();
System.out.println("body:");
System.out.println(body);
String digest = createDigest(body);
System.out.println();
System.out.println("digest:");
System.out.println(digest);
SimpleDateFormat sdf = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z");
String date = sdf.format(new Date());
System.out.println();
System.out.println("date:");
System.out.println(date);
String message = "(request-target): post /g_business/v1/payments\n" +
"host: staging.authservices.satispay.com\n" +
"date: " + date + "\n" +
"digest: " + digest;
System.out.println();
System.out.println("message:");
System.out.println(message);
String privateKey = readPemKey("private.pem"); // your private key
System.out.println();
System.out.println("private.pem:");
System.out.println(privateKey);
String signature = signData(message, privateKey);
System.out.println();
System.out.println("signature:");
System.out.println(signature);
}
private static String createDigest(String body) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = messageDigest.digest(body.getBytes("UTF-8"));
return "SHA-256=" + Base64.getEncoder().encodeToString(hashBytes);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
System.exit(1);
}
return null;
}
public static String signData(String message, String base64PrivateKey) {
try {
byte[] privateKeyBytes = Base64.getDecoder().decode(base64PrivateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(message.getBytes(StandardCharsets.UTF_8));
byte[] signatureBytes = signature.sign();
return Base64.getEncoder().encodeToString(signatureBytes);
} catch (
NoSuchAlgorithmException |
InvalidKeySpecException |
InvalidKeyException |
SignatureException e
) {
e.printStackTrace();
System.exit(1);
}
return null;
}
private static String readPemKey(String filePath) {
try {
String pemText = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
Pattern pattern = Pattern.compile("-----(?:.*?)-----([^-]*)-----(?:.*?)-----", Pattern.DOTALL);
Matcher matcher = pattern.matcher(pemText);
String base64Key = pemText;
if (matcher.find()) {
base64Key = matcher.group(1).replace("\r", "").replace("\n", "");;
}
return base64Key;
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
return null;
}
private static String readFile(String filePath) {
try {
return new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
return null;
}
}
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
class Satispay
{
static void Main(string[] args)
{
var bodyObject = new Dictionary<string, object>
{
{ "flow", "MATCH_CODE" },
{ "amount_unit", 100 },
{ "currency", "EUR" }
};
var body = JsonSerializer.Serialize(bodyObject);
Console.WriteLine("body:");
Console.WriteLine(body);
var digest = createDigest(body);
Console.WriteLine();
Console.WriteLine("digest:");
Console.WriteLine(digest);
string date = DateTime.UtcNow.ToString("r");
Console.WriteLine();
Console.WriteLine("date:");
Console.WriteLine(date);
string message = "(request-target): post /g_business/v1/payments\n" +
"host: staging.authservices.satispay.com\n" +
$"date: {date}\n" +
$"digest: {digest}";
Console.WriteLine();
Console.WriteLine("message:");
Console.WriteLine(message);
string privateKey = readPemKey("private.pem"); // your private key
Console.WriteLine();
Console.WriteLine("private.pem:");
Console.WriteLine(privateKey);
string signature = signData(message, privateKey);
Console.WriteLine();
Console.WriteLine("signature:");
Console.WriteLine(signature);
}
static string createDigest(string body)
{
var sha256 = SHA256.Create();
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(body));
return "SHA-256=" + Convert.ToBase64String(hashBytes);
}
static string signData(string data, string privateKey)
{
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
using (var rsa = RSA.Create())
{
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
var sha256 = SHA256.Create();
byte[] hash = sha256.ComputeHash(dataBytes);
byte[] signatureBytes = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
string signature = Convert.ToBase64String(signatureBytes);
return signature;
}
}
static string readPemKey(string filePath)
{
string pemText = File.ReadAllText(filePath);
string base64Key = pemText.Replace("-----BEGIN PRIVATE KEY-----", "")
.Replace("-----END PRIVATE KEY-----", "")
.Replace("\r", "")
.Replace("\n", "");
return base64Key;
}
static string readFile(string filePath)
{
return File.ReadAllText(filePath);
}
}
import json
import hashlib
import base64
import time
import datetime
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
body_object = {
'flow': 'MATCH_CODE',
'amount_unit': 100,
'currency': 'EUR'
}
body = json.dumps(body_object)
print("body:")
print(body)
digest = "SHA-256=" + base64.b64encode(hashlib.sha256(body.encode()).digest()).decode()
print()
print("digest:")
print(digest)
date = datetime.datetime.now(datetime.timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
print()
print("date:")
print(date)
message = "(request-target): post /g_business/v1/payments\n\
host: staging.authservices.satispay.com\n\
date: " + date + "\n\
digest: " + digest
print()
print("message:")
print(message)
with open('private.pem', 'rb') as private_key_file:
private_key_file = private_key_file.read()
private_key = serialization.load_pem_private_key(
private_key_file,
password=None,
backend=default_backend()
)
print()
print("private.pem:")
print(private_key_file.decode())
signature = private_key.sign(
message.encode(),
padding.PKCS1v15(),
hashes.SHA256()
)
signature = base64.b64encode(signature).decode()
print()
print("signature:")
print(signature)
#!/bin/bash
body='{
"flow": "MATCH_CODE",
"amount_unit": 100,
"currency": "EUR"
}'
echo "body:"
printf "%s" "$body"
digest="SHA-256=$(printf "%s" "$body" | openssl dgst -sha256 -binary | base64 -w 0)"
echo "\n"
echo "\ndigest:"
echo "$digest"
date=$(date -R)
echo "\ndate:"
echo "$date"
message="(request-target): post /g_business/v1/payments"$'\n'
message+="host: staging.authservices.satispay.com"$'\n'
message+="date: $date"$'\n'
message+="digest: $digest"
echo "\nmessage:"
echo "$message"
private_key=$(cat private.pem)
echo "\nprivate.pem:"
echo "$private_key"
signature=$(printf "%s" "$message" | openssl dgst -sign private.pem -sha256 -binary | base64 -w 0)
echo "\nsignature:"
echo "$signature"
Signature checker
We've designed this tool for you to validate the signature you've generated.
Please make sure that your output matches the result generated by this tool.
https://codesandbox.io/p/sandbox/satispay-signature-test-tgq5ts
BewareEnsure that the output provided by this tool matches your implementation.
If there are differences, it's likely a signature issue.