Message authentication¶
To collect statistics when using Dynamic pages and to perform secure payment notifications the class MessageAuthentication
must be implemented. Implementation examples are in NodeJS, C#, and Java.
Implementation¶
Dynamic page tokens shows examples of how to use this class.
const crypto = require('crypto');
module.exports = (privateKey) => {
if (!privateKey || privateKey.length === 0) {
throw 'Argument privateKey must not be null or empty.';
}
return {
sign(message) {
if (!message || message.length === 0) {
throw 'Argument message must not be null or empty.';
}
return crypto.createHmac('sha256', privateKey).update(message).digest('hex');
}
}
};
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Apptus.ESales.Connector
{
public class MessageAuthentication
{
private readonly string _privateKey;
/// <summary>
/// Creates a new instance with a specific private key, that can then be used to sign messages.
/// </summary>
/// <param name="privateKey">A private key that will be used as a secret in the signature. Must not be null or empty.</param>
/// <exception cref="ArgumentException">If privateKey is null or empty.</exception>
public MessageAuthentication(string privateKey)
{
if (string.IsNullOrEmpty(privateKey))
{
throw new ArgumentException("Argument privateKey must not be null or empty.", "privateKey");
}
_privateKey = privateKey;
}
/// <summary>
/// Signs a message by combining it with a private key, used for prevention of unauthorised changes of the message.
/// </summary>
/// <param name="message">The message that should be signed. Must not be null or empty.</param>
/// <exception cref="ArgumentException">If message is null or empty.</exception>
/// <returns>A string token in hex format.</returns>
public string Sign(string message)
{
return HmacSha256(message);
}
private string HmacSha256(string message)
{
if (string.IsNullOrEmpty(message))
{
throw new ArgumentException("Argument message must not be null or empty.", "message");
}
using (var hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_privateKey)))
{
return hmacSha256
.ComputeHash(Encoding.UTF8.GetBytes(message))
.Aggregate(new StringBuilder(), (sb, b) => sb.AppendFormat("{0:x2}", b))
.ToString();
}
}
}
}
package com.apptus.esales.connector;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* A class that is used for signing messages.
*/
public class MessageAuthentication {
private final String privateKey;
/**
* Creates a new instance with a specific private key, that can then be used to sign messages.
* @param privateKey A private key that will be used as a secret in the signature. Must not be null or empty.
* @throws IllegalArgumentException If privateKey is null or empty.
*/
public MessageAuthentication(String privateKey) {
if (privateKey == null || privateKey.length() == 0) {
throw new IllegalArgumentException("Argument privateKey must not be null or empty.");
}
this.privateKey = privateKey;
}
/**
* Signs a message by combining it with a private key, used for prevention of unauthorised changes of the message.
* @param message The message that should be signed. Must not be null or empty.
* @return A string token in hex format.
* @throws IllegalArgumentException If message is null or empty.
*/
public String sign(String message) {
return hmacSha256(message);
}
private String hmacSha256(String message) {
if (message == null || message.length() == 0) {
throw new IllegalArgumentException("Argument message must not be null or empty.");
}
Mac hmacSHA256;
final String signingAlgorithm = "HmacSHA256";
try {
hmacSHA256 = Mac.getInstance(signingAlgorithm);
} catch (NoSuchAlgorithmException e) {
// This should not happen.
throw new RuntimeException(e);
}
try {
hmacSHA256.init(new SecretKeySpec(privateKey.getBytes(StandardCharsets.UTF_8), signingAlgorithm));
} catch (InvalidKeyException e) {
// This should not happen, currently only an internal argument check that will not happen in the hmac sha256 case.
throw new RuntimeException(e);
}
return toHexString(hmacSHA256.doFinal(message.getBytes(StandardCharsets.UTF_8)));
}
static String toHexString(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
hexString.append(String.format(Locale.ROOT, "%02x", b));
}
return hexString.toString();
}
}