2
\$\begingroup\$

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?

Strategy

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";
    exit;
}

// 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()

        Try

            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
        myRSA.FromXmlString("<RSAKeyValue><Modulus>SomeLongBase64StringHere</Modulus><Exponent>SomeShortBase64StringHere</Exponent></RSAKeyValue>") 

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

    End Using

End Sub
\$\endgroup\$

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.