I would like to achieve something I believe is pretty standard:

A) My VB.NET client (ideally targetting Framework 4.0) sends a text string to my Apache/PHP Server via an HTTPS POST request.

B) My Server responds with a Signature of that text string. Private key used by the Server is always the same, and public key used by Client is already embeded within the source code.

After investigating and reading through a lot of documentation, I came up with the following strategy. Is it efficient?


Server Side

  • Apache/PHP: Because that is the only server language I am familiar with, but I could switch if recommended.
  • OpenSSL: Because I use PHP
  • PEM files: Because I use OpenSSL
  • RSA key size is 2048 bits: Recommended minimum in 2019
  • Algorythm is SHA256: Because everyone seems to use that one
  • Header text/plain, UTF8: Why not?

Client Side

  • VB.Net Framework 4.0 Client Profile: Because I want to maximise legacy (VSTO 2013)
  • System.Security.Cryptography.RSACryptoServiceProvider
  • PEM public key info loaded via XML string
  • HTTPS should be TLS1.0 or higher: Because I target .Net Framework 4.0 (TLS1.1 is recommended if possible)

Source Code

Server Side (generate .pem key files, only once)


// Create new Keys Pair
$new_key_pair = openssl_pkey_new(array(
    "private_key_bits" => 2048,
    "private_key_type" => OPENSSL_KEYTYPE_RSA,

//Save Private Key
openssl_pkey_export($new_key_pair, $private_key_pem, "my passphrase to protect my private key; add random characters like $, ?, #, & or ! for improved security");
file_put_contents('private_key.pem', $private_key_pem);

//Save Public Key
$details = openssl_pkey_get_details($new_key_pair);
$public_key_pem = $details['key'];
file_put_contents('public_key.pem', $public_key_pem);


Server Side (target of POST requests)


header('Content-Type: text/plain; charset=utf-8');

// Verify connection is secure
if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS']=="off")
    echo "Unauthorized Access";

// Data to Sign
$data = base64_decode(file_get_contents('php://input'));

//Load Private Key
$private_key_pem = openssl_pkey_get_private('file:///path/protected/by/dotHtaccess/private_key.pem', "my passphrase to protect my private key; add random characters like $, ?, #, & or ! for improved security");

//Create Signature
openssl_sign($data, $signature, $private_key_pem, OPENSSL_ALGO_SHA256);
echo base64_encode($signature);


Client Side

imports System.Diagnostics

Sub mySignatureTest()

    Dim oURI As Uri = New Uri("https://www.example.com/targetpage.php")
    Dim sData As String = "myStringToSign"
    Dim sResponse As String

    '# Get POST request Response

    Using oWeb As New System.Net.WebClient()


            System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol And Not System.Net.ServicePointManager.SecurityProtocol.Ssl3 'Override defautl Security Protocols: Prohibit SSL3
            oWeb.Encoding = Encoding.UTF8
            Debug.Print("SSL version is " & System.Net.ServicePointManager.SecurityProtocol.ToString)
            Debug.Print("Sending " & sData)
            Debug.Print("To " & oURI.ToString)
            Debug.Print("Encoding is " & oWeb.Encoding.ToString)
            sResponse = oWeb.UploadString(oURI, "POST", Convert.ToBase64String(Encoding.UTF8.GetBytes(sData)))
            Debug.Print("Server reponse = " & sResponse)

        Catch ex As Exception
            MsgBox("Connection with server failed: " & ex.ToString, vbCritical | vbOKOnly, "Add-In")
        End Try

    End Using

    '#Verify RSA SHA256 Signature

    Dim sDataToSign As String = sData
    Dim sSignatureToVerify As String = sResponse

    Using myRSA As New System.Security.Cryptography.RSACryptoServiceProvider
        'XML format obtain from PEM file by hand copy/paste here: https://superdry.apphb.com/tools/online-rsa-key-converter

        Debug.Print("Signature verification = " & myRSA.VerifyData(Encoding.UTF8.GetBytes(sDataToSign), _
                                                                   System.Security.Cryptography.CryptoConfig.MapNameToOID("SHA256"), _

    End Using

End Sub
  • \$\begingroup\$ Your code looks OK-ish, but are you sure you are not signing everything that anybody sends to you? Anybody can setup an TLS session unless you use either TLS client authentcation or authentication later on. \$\endgroup\$ – Maarten Bodewes Mar 3 '20 at 0:13
  • \$\begingroup\$ With this test code, yes, definitely. In practice, the client provides a means of authentication (token, etc), then the server runs a DB lookup and signs the data only if the light is green. \$\endgroup\$ – Ama Mar 3 '20 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.