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_agent/v1/pagopa/payments
host: staging.authservices.satispay.com
date: Mon, 18 Mar 2019 15:10:24 +0000
digest: SHA-256=K6ST2uNpPQEytbhc5+QWxOyx33VWf5Ui5rkH9q/N53k=
ObKj4eE/V3TWy8Wmr01AHIsMfrclwlp1x+cxMXdillgrtWhyZXo7/fPXRJvCqiombSigCk5P8/tN9gUkATIXkzrAqtaxwFP9iuj2jW2MT93BiFHwl6DZAohvwkP4cyfeKYWnOXMP5E3pxG1T4BwoC8smoU8leKa4HCumY6a351y7XZTRHEb37+NfMEIXfP3f1KkLpUuH3VmdaBBjh96Qm6lnNE45ZH84wq1k5bkYMq+zI8c81qjEdbLAuX0+LzXT12xnkx8/e48WMwGu7R2M5Rd32PFzXVZihIpxlChuGBfSgxzpDb3KY0kYrrG0QMmE93le9bsHhSXQ/8q1OG9GxgblXyFHVgadWA2DHzQ0wmzYvoeyrV4/F/rc4VQLRtuRnOu43z1f4Wy/dZc+h5tkFN+ndwLIANBxfb0PajurxfxDbgXx7K9undBfTkdcwPxMd1l0V4y9SDPo7Nsov6LYzUpQbxA8A8jZUrnMbP/mRHFyKulifRd3ZgX/zKPWKmlcVH5VBNqqrs+REEyjieW0Di7+Ii1Huj+MGolDeTFOQNu0dO7qb8baoZfV5X/iVk5cb7HlmzRrbti35NrR3f5r8uqtV9ZOocv59OWg9j3naTsYPFxHIiWQPsvckdHwODEgBXA+7da8QPJPWA5BMQIaqPKP9ZPC3wDk/RZg2iMCOus=
BewarePlease note that the Message must be signed, not encrypted.
Code sample 3/4
$bodyObject = [
'request_type' => 'MANUAL',
'payment_notice_number' => '001000000027334679',
'domain_id' => '00297960197'
'amount_unit' => 12000
];
$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_agent/v1/pagopa/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 = {
request_type: 'MANUAL',
amount_unit: 100,
payment_notice_number: '001000000027334679',
domain_id: '00297960197'
};
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_agent/v1/pagopa/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("request_type", "MANUAL")
.put("amount_unit", 100)
.put("payment_notice_number", "001000000027334679")
.put("domain_id", "00297960197");
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_agent/v1/pagopa/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>
{
{ "request_type", "MANUAL" },
{ "amount_unit", 100 },
{ "payment_notice_number", "001000000027334679" },
{ "domain_id", "00297960197" }
};
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_agent/v1/pagopa/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 = {
'request_type': 'MANUAL',
'amount_unit': 100,
'payment_notice_number': '001000000027334679',
'domain_id': '00297960197'
}
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_agent/v1/pagopa/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='{
"request_type": "MANUAL",
"amount_unit": 100,
"payment_notice_number": "001000000027334679",
"domain_id": "00297960197"
}'
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_agent/v1/pagopa/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.