# RSA Signature Verification

## Obtain the Public Key - Based on environment

Copy the public key for the environment you're working with from [here](https://docs.elemitech.com/getting-started/elemi-public-keys). This document assumes that the public key would be stored somewhere on your server under the name `elemi.public.key.pem`

## Next Steps

Below is the sample callback data for this demonstration

```json
{
    "event": "transaction.completed",
    "payload": {
        "id": 38314,
        "merchant_reference": "MCTREFC6ZU7CRDZGXMAVNA",
        "internal_reference": "ELEMIYFPMASLD3BW2RQ",
        "transaction_type": "COLLECTION",
        "request_currency": "UGX",
        "request_amount": 20000,
        "transaction_currency": "UGX",
        "transaction_amount": 20000,
        "transaction_charge": 600,
        "transaction_account": "256785908092",
        "customer_name": "JOHN DOE",
        "charge_customer": false,
        "total_credit": 19400,
        "provider_code": "mtn_ug",
        "institution_name": "MTN Mobile Money Uganda",
        "transaction_status": "COMPLETED",
        "status_message": "Transaction Completed Successfully"
    }
}
```

1. Obtain the value of the `rsa-signature` header (if callback) OR the value of the `rsa_signature` query parameter (if redirect).
2. Form the string payload to be used in signature verification. This is obtained by concatenating values of the callback/redirect data in the format; `event:merchant_reference:internal_reference:transaction_type:transaction_status` and these values are obtained from the callback/redirect data. The string payload would therefore be `transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED`
3. Use the public key obtained above to verify the signature as described in the sample source codes below.

{% tabs %}
{% tab title="PHP" %}

```php
<?php

public function isValidSignature() {
    $file = "path-to-file/elemi.public.key.pem";
    $keyContent = file_get_contents($file);
    $publicKey = openssl_get_publickey($keyContent);
    $strPayload = "transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED";
    $signature = base64_decode("value-of-rsa-signature");

    /*true or false*/
    return openssl_verify($strPayload, $signature, $publicKey, "sha256") == 1;
}

?>
```

{% endtab %}

{% tab title="NodeJS" %}

```javascript
const crypto = require("crypto");
const fs = require("fs");

function isValidSignature() {
  const strPayload =
    "transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED";
  const signature = "value-of-rsa-signature";
  const publicKeyFile = "path-to-file/elemi.public.key.pem";
  const publicKey = fs
    .readFileSync(publicKeyFile)
    .toString()
    .replace(/\\n/g, "\n");

  const verify = crypto.createVerify("SHA256");
  verify.write(strPayload);
  verify.end();

  /*true or false*/
  return verify.verify(publicKey, signature, "base64");
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class SignatureVerifier {

    public boolean isValidSignature() throws Exception {
        // Read public key from file
        Path pathToFile = Paths.get("path-to-file/elemi.public.key.pem");
        byte[] keyBytes = Files.readAllBytes(pathToFile);

        // Decode public key
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        // Signature and payload
        String strPayload = "transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED";
        byte[] signatureBytes = Base64.getDecoder().decode("value-of-rsa-signature");

        // Verify signature
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(strPayload.getBytes());
        return signature.verify(signatureBytes);
    }

    public static void main(String[] args) throws Exception {
        SignatureVerifier verifier = new SignatureVerifier();
        System.out.println(verifier.isValidSignature());
    }
}

```

{% endtab %}

{% tab title="C#" %}

```csharp
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class SignatureVerifier
{
    public bool IsValidSignature()
    {
        // Read public key from file
        string pathToFile = @"path-to-file\elemi.public.key.pem";
        string keyContent = File.ReadAllText(pathToFile);

        // Decode public key
        RSA rsa = RSA.Create();
        rsa.ImportFromPem(keyContent);

        // Signature and payload
        string strPayload = "transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED";
        byte[] signatureBytes = Convert.FromBase64String("value-of-rsa-signature");

        // Verify signature
        var verifier = new RSAPKCS1SignatureDeformatter(rsa);
        verifier.SetHashAlgorithm("SHA256");
        byte[] payloadBytes = Encoding.UTF8.GetBytes(strPayload);
        byte[] sha256Hash;

        using (SHA256 sha256 = SHA256.Create())
        {
            sha256Hash = sha256.ComputeHash(payloadBytes);
        }

        return verifier.VerifySignature(sha256Hash, signatureBytes);
    }

    public static void Main(string[] args)
    {
        SignatureVerifier verifier = new SignatureVerifier();
        Console.WriteLine(verifier.IsValidSignature());
    }
}

```

{% endtab %}

{% tab title="Python" %}

```python
import base64
import hashlib
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_public_key

def is_valid_signature():
    # Read public key from file
    with open("path-to-file/elemi.public.key.pem", "rb") as key_file:
        key_content = key_file.read()

    # Decode public key
    public_key = load_pem_public_key(key_content, backend=default_backend())

    # Signature and payload
    str_payload = "transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED"
    signature_bytes = base64.b64decode("value-of-rsa-signature")

    # Verify signature
    verifier = public_key.verifier(
        signature_bytes,
        padding.PKCS1v15(),
        hashlib.sha256
    )
    verifier.update(str_payload.encode())

    try:
        verifier.verify()
        return True
    except Exception as e:
        print("Signature verification failed:", e)
        return False

```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require 'openssl'
require 'base64'

def is_valid_signature
  # Read public key from file
  file = File.read("path-to-file/elemi.public.key.pem")

  # Decode public key
  public_key = OpenSSL::PKey::RSA.new(file)

  # Signature and payload
  str_payload = "transaction.completed:MCTREFC6ZU7CRDZGXMAVNA:ELEMIYFPMASLD3BW2RQ:COLLECTION:COMPLETED"
  signature_bytes = Base64.decode64("value-of-rsa-signature")

  # Verify signature
  sha256 = OpenSSL::Digest::SHA256.new
  result = public_key.verify(sha256, signature_bytes, str_payload)

  result
end

```

{% endtab %}
{% endtabs %}

Below is an example of a generated RSA signature (rsa-signature) on the sandbox environment. Feel free to verify it using the sample payload above and the public key.

{% code overflow="wrap" %}

```
g4qVLomppbP/7gQpRwSAndkYKp5fGEOK16QiNHeGTN+0QKWmptEvnX1nHQxyAEXRU0DNcoL+TWAfEVpc6lODIj2I6uXEWuNIA/CHmdnspLF1eeqcVpoqJ8QW90A0HJvPnVJclQLWFXUa/AeLGjQxmlr496nuIM+AiGeMx3SFfYphP5w+ScVDbNOOL2iS0EH2cyx0xerXRCVNKyTBJXQpADERu1ZzDqVB/RB+qqkfw8K8u/yYYfOTFQrPMjcR8zEKlSUz01OHJinVy/ukixyXXW3yBdUk03i/o+BgDHLQPGpLFKV7baxG4/gZyHgq1Yln5hCsnZso66EjV4kk3dwW7cf3QxiPqoqCkeMV1Qy0FWk/Hz7OE8cQv+n+hgZ2b9JkjKDvj2hDw2VxYLRh2uyJv9pOqwZtpciNf3n0fcIeXBMBHurPHxhjUwbbef5WK/ELSJ1zZ5s0Jh0/ZsxfSkDmWfrC9pL804+M0nge5geG/X6DESMW322GLnCFg/01Wv/86RrxTWFLaZRJvfrdKyJr+BufgtCzcpQ8bPuzUrqUfFuJD/t7KBbw/rEB+9wsaOvvBeuw+KldJRh/sNRsXS3mdqDhlgKNJqgNQWmV51TtoFvjoEjuwtCGQCyfqGcEVqhdqjpN7TeJR5Jwxz+Plev0RNqa5JY4ydS2vE7fQXZaUaM=
```

{% endcode %}
