As you might know, I do a lot of apps which communicate with my Apache servers via httputils and php. For a longer time I was missing some strong encryption. I knew that there was agrahams encryption library which can do RSA but I didn't know how I can fit the OpenSSL/php side. After some time I got a working example which I want to publish to the community.
Basics:
Simple (symetric) encryption systems are build like "the letter A will encrypted like 1, B like 2, C like 3", etc. Easy to hack and both sides use the same decryption key. If someone gets the key, all messages can be decrypted.
An then there's RSA, an asymetric enryption with a pair of keys. One is the "public key", the other the "private key" (which must me kept secret).
With the public key anyone can encrypt messages to you, but only with the private key they can be decrypted. Details see here: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
For our B4A example you'll need a Apache Server where OpenSSL is installed. I prefer Xampp for my test environment. Get it from here: https://www.apachefriends.org/de/index.html It comes "ready to run" with OpenSSL installed.
See my other tutorial to get a quick start: https://www.b4x.com/android/forum/t...hp-mysql-server-xampp-with-b4a.48635/#content
1. Create the keys
Make a new folder called "rsa" in xampp's htdocs' folder -> C:/xampp/htdocs/rsa/
To create a new *.bat file (WIN Batch file) in that folder, too and copy these lines into it:
I've namend it "RSA_Keys.bat". With a double click it starts the script and creates the keys. Usually the private key must be encrypted with a passphrase, but for my example I did not use it. Very important for agrahams encryption lib is to set the padding to pkcs8.
In the folder we now have two new files:
PrivateKey.pem and PublicKey.pem
To check if everything is ok so far, create a new *.php file in the rsa folder (C:\xampp\htdocs\rsa\SSLTest.php) with this content:
Open your browser (Apache must be started) and type http://127.0.0.1/rsa/ssltest.php
It will load the keys and en- and decrypt a small message. You should see something similar to this in your browser:
Well done. RSA is working fine on your system. Check for typo's when you get other results.
2. Use the keys in B4A
We will use httputils to get the keys we've created by the script earlier via php. Create a new *.php file called "GetKeys.php" in "C:\xampp\htdocs\rsa\":
In B4a we will create a job to call that php script (and yes, I was lazy. I put it in Activity_Create with no check if first time):
With this, the php script will be called, both keys (files) will be read, Base64 encoded and then put in a list with maps (in php an array in an array) and send back as a JSON string to our app.
In JobDone:
we will parse the JSON from the script, put the answer in a list and then get the maps out of it. Each map has both keys in it.
The next step is to initialize the RSA cryption:
As you can see, the headers and footers must be removed. After that the Keys can be loaded in the KeyPairGenerator of agrahams library. With it you can create new keys, export AND import keys. Our keys are imported (coming from the server). Important is to decode them from Base64.
Now we're ready to en- and decrypt a message. This is the reason why I use both keys. Usually this is a no go (because the private key has to be kept secret!). So it's just for the prove that the OpenSSL keys work in B4A.
The message has to be converted to bytes, then en- and decrypted. You see the decrypted message in the logs now
Nice, but now we want to let the server decrypt the message:
Important: Convert the message from bytes to hex and Base64 encode it. After that just send it to the script "DeCryptRSA.php" in the same folder as the scripts above:
That's it... You should see the encrypted message after the job returns to JobDone.
All the needed files are included.
Libs used:
ByteConverter
Encryption
Httputils2
JSON
StringUtils
Basics:
Simple (symetric) encryption systems are build like "the letter A will encrypted like 1, B like 2, C like 3", etc. Easy to hack and both sides use the same decryption key. If someone gets the key, all messages can be decrypted.
An then there's RSA, an asymetric enryption with a pair of keys. One is the "public key", the other the "private key" (which must me kept secret).
With the public key anyone can encrypt messages to you, but only with the private key they can be decrypted. Details see here: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
For our B4A example you'll need a Apache Server where OpenSSL is installed. I prefer Xampp for my test environment. Get it from here: https://www.apachefriends.org/de/index.html It comes "ready to run" with OpenSSL installed.
See my other tutorial to get a quick start: https://www.b4x.com/android/forum/t...hp-mysql-server-xampp-with-b4a.48635/#content
1. Create the keys
Make a new folder called "rsa" in xampp's htdocs' folder -> C:/xampp/htdocs/rsa/
To create a new *.bat file (WIN Batch file) in that folder, too and copy these lines into it:
B4X:
cd C:\xampp\apache\bin
openssl genrsa -out PrivateKey.pem 2048
openssl pkcs8 -topk8 -inform pem -in PrivateKey.pem -outform pem -nocrypt -out C:/xampp/htdocs/rsa/PrivateKey.pem
openssl rsa -pubout -in PrivateKey.pem -out C:/xampp/htdocs/rsa/PublicKey.pem
pause
I've namend it "RSA_Keys.bat". With a double click it starts the script and creates the keys. Usually the private key must be encrypted with a passphrase, but for my example I did not use it. Very important for agrahams encryption lib is to set the padding to pkcs8.
In the folder we now have two new files:
PrivateKey.pem and PublicKey.pem
To check if everything is ok so far, create a new *.php file in the rsa folder (C:\xampp\htdocs\rsa\SSLTest.php) with this content:
B4X:
<?php
$pub = file_get_contents('PublicKey.pem');
$pri = file_get_contents('PrivateKey.pem');
echo "<br><br>";
var_dump($pub);
echo "<br><br>";
var_dump($pri);
$plain = 'Hello RSA';
echo "<br><br>Plaintext: $plain";
openssl_public_encrypt($plain, $encrypted, $pub);
echo "<br><br>Encrypted: " . $encrypted;
$plain = '';
openssl_private_decrypt($encrypted, $plain, $pri);
echo "<br><br>Decrypted: " . $plain;
?>
Open your browser (Apache must be started) and type http://127.0.0.1/rsa/ssltest.php
It will load the keys and en- and decrypt a small message. You should see something similar to this in your browser:
B4X:
string(451) "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2IJuXnJVvITMZjbAwSbu tC1LiT1q0F01PxBtGhjN4MNRbB9AixWF31y6YTjMtz5OHgJ0qAwymW3G04mgH7al 4B+dLOjhNwuBdlsZlELdsBu7+zdh2InyYikmnJU+oIOowWpIYI7GYSp++Sxf3xac 05XlqMFgy/5t373REwdMXbrTI6oTcOauDX+xdG7k7GIEPY/BjveHqXJTwt7px8wQ HWRgB3uMmHTxXHG//UmpY6X0UyRAZR3Yyk4HpRycqXa4wCTrnUAr90OplshHhcOz Uf9aEiG5m+p7nJhRD7MFPpJayIG2mBKQ32z3XycD3P3Ef4TSfHFgzI+Nb+CtvY1B ywIDAQAB -----END PUBLIC KEY----- "
string(1704) "-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDYgm5eclW8hMxm NsDBJu60LUuJPWrQXTU/EG0aGM3gw1FsH0CLFYXfXLphOMy3Pk4eAnSoDDKZbcbT iaAftqXgH50s6OE3C4F2WxmUQt2wG7v7N2HYifJiKSaclT6gg6jBakhgjsZhKn75 LF/fFpzTleWowWDL/m3fvdETB0xdutMjqhNw5q4Nf7F0buTsYgQ9j8GO94epclPC 3unHzBAdZGAHe4yYdPFccb/9SaljpfRTJEBlHdjKTgelHJypdrjAJOudQCv3Q6mW yEeFw7NR/1oSIbmb6nucmFEPswU+klrIgbaYEpDfbPdfJwPc/cR/hNJ8cWDMj41v 4K29jUHLAgMBAAECggEADDkw6fwigwYsVAj7UOxVxa5Y+WKSSTk57FmND1AfL3VX f3c0OaX5bObbTunaBO5rkp4o3+PwZ2EfPIoklCXHr6OZSBPNw0HPCVOTWh98TJkE P+aci5EeMhSIrYZvhrhoKqNJesoUwR+ZE5BByWKJcBiiYqioQlwW7+7TgvOCiDgN Y/oRjbDRgHq2e24OXGLzhumhZ6mJ5MAg8s0ixivTFOFqsfnkJK2zUu3jsQOowrou o1kKeTbBJSPsDS5Bm/sjRPxraJ8CtQcB8ru+odbjTqeP+mG660/ll62dL4w3r6ZS fiP3dNTEXh07TWf8DtnIlY9PhjJc04YjZ6nHNRGmYQKBgQDxjq8UQJtof0HfRlG7 zjDShBOK19h54vLoY6uvmG3+vU2E4oVlVvEVvrTdcnkb9haw02K0WYHMW7vcKrez KqJyp2FARaJGIbRvXcW/LaMhzzEfd42slgtX94H7u+g8dx6L9uC0QmCSjxTwmWli gfecOR4w491lh57XMmFMF7YOLwKBgQDldFxPMCFCssIuvtIJHzVaAIgXoQ3JiOr1 0wRYrRyqplncSx0HhyFVEZ1uGn8QKzYNs877bBzan3uriklR9GYtLhibN+Ytgvei t17f928WhjRyX8mm09xPIAWrCqGZvVmk/x+nOgEQGoraCDYx5zZaIvu6ZlrCri3z AId8S9XbJQKBgAhUd00nfTR5Tvg4IJFtZtmbnGDpWJm7bcz9wunnQ8PJG2c9uIPq H540WWBZljuUnOu0Hm9BtuwpLa1F+9e93KQ/iWcB/7qTZvmALlWNaVa9ImCHaudM tU9vRZg8vqF3KiKBfPY6Y8IqFPrHD49KFBPbFGNzOCtMJfodzqUlHC4ZAoGBALS3 EHzNy2RcpdNrNsE4cyyPfqAdmF5CF8vEhofQz+MXYW6/Of3Tz8zQMs2k0K5LWicw lrQuUgtd0GkqYNTLSC4NQBP/0qnFnIPrKC39EuEKkgQCrS9XbQxkjBJKLTyIhTIO PT/Xzz5/qRxPm19yWrxjER+dvZ3W0RmyMQMUNzqBAoGAJQxs1UIxrEnxcLxoq1rG zd61IYKo4wJ78GPNMghdqh0VcP6sx0WKRCv2iroaYlLiZcS9z35e6nDXbaoff7vY xGKaDxw2gfhb+U4GIRza/OTcV1s6LHsoW6sah3WJgT27IBMa4i83q/aCmVoErNMr B3NHFwqr6BUWA/YNdJUwA94= -----END PRIVATE KEY----- "
Plaintext: Hello RSA
Encrypted: �;*��CTy�z�O �]����S-�9��|� ���wh;���YZ�#�^Ѭ��C_�H����0�h�?���q���oP�$�f�0&��\5=���P*R�g�p�mk��w�ٿ�Ԯ���%�n$�]�z�<� �h{��BY>��mN%�k;��Nbj(/��x"3ۯH�r�mt1�x��պ*���@�f��M̭�H�IEM�4������6� SM4��D�y��a��-�F�emq�s6�aouA� ^X�A
Decrypted: Hello RSA
Well done. RSA is working fine on your system. Check for typo's when you get other results.
2. Use the keys in B4A
We will use httputils to get the keys we've created by the script earlier via php. Create a new *.php file called "GetKeys.php" in "C:\xampp\htdocs\rsa\":
B4X:
<?php
$pub = Base64_Encode(file_get_contents('PublicKey.pem'));
$pri = Base64_Encode(file_get_contents('PrivateKey.pem'));
$keys = array(
array(
"PubKey" => $pub,
"PrivKey" => $pri,
)
);
print json_encode ($keys);
?>
In B4a we will create a job to call that php script (and yes, I was lazy. I put it in Activity_Create with no check if first time):
B4X:
Sub Activity_Create(FirstTime As Boolean)
'Do not forget to load the layout file created with the visual designer. For example:
'Activity.LoadLayout("Layout1")
Dim GetKeys As HttpJob
GetKeys.Initialize("GetKeys", Me)
GetKeys.Download2("http://192.168.178.21/rsa/GetKeys.php", _
Array As String("Action", "GetKeys" ))
End Sub
With this, the php script will be called, both keys (files) will be read, Base64 encoded and then put in a list with maps (in php an array in an array) and send back as a JSON string to our app.
In JobDone:
B4X:
Select Job.JobName
Case "GetKeys"
If res.Length<12 Then
Msgbox(res,"Error")
Else
Dim KeyL As List
Dim KeyMap As Map
KeyL = parser.NextArray
If KeyL.Size > 0 Then
For i =0 To KeyL.Size -1
KeyMap = KeyL.Get(i)
ForeignPubKeyString=KeyMap.Get("PubKey")
ForeignPrivKeyString=KeyMap.Get("PrivKey")
Next
we will parse the JSON from the script, put the answer in a list and then get the maps out of it. Each map has both keys in it.
The next step is to initialize the RSA cryption:
B4X:
c.Initialize("RSA/ECB/PKCS1Padding")
ForeignKPG.Initialize("RSA", 2048)
'Convert the Public Key
ForeignPubKeyBytes=su.DecodeBase64(ForeignPubKeyString)
ForeignPubKeyString=Bconv.StringFromBytes(ForeignPubKeyBytes, "UTF8")
Log (ForeignPubKeyString)
ForeignPubKeyString=ForeignPubKeyString.Replace("-----BEGIN PUBLIC KEY-----","")
ForeignPubKeyString=ForeignPubKeyString.Replace("-----END PUBLIC KEY-----","")
Log ("Truncated: " & ForeignPubKeyString)
Log (ForeignPrivKeyString)
'Convert the Private Key
ForeignPrivKeyBytes=su.DecodeBase64(ForeignPrivKeyString)
ForeignPrivKeyString=Bconv.StringFromBytes(ForeignPrivKeyBytes, "UTF8")
Log (ForeignPrivKeyString)
ForeignPrivKeyString=ForeignPrivKeyString.Replace("-----BEGIN PRIVATE KEY-----","")
ForeignPrivKeyString=ForeignPrivKeyString.Replace("-----END PRIVATE KEY-----","")
Log ("Truncated: " & ForeignPubKeyString)
ForeignPubKeyBytes=su.DecodeBase64(ForeignPubKeyString)
ForeignKPG.publicKeyFromBytes(ForeignPubKeyBytes)
ForeignPrivKeyBytes=su.DecodeBase64(ForeignPrivKeyString)
ForeignKPG.PrivateKeyFromBytes(ForeignPrivKeyBytes)
As you can see, the headers and footers must be removed. After that the Keys can be loaded in the KeyPairGenerator of agrahams library. With it you can create new keys, export AND import keys. Our keys are imported (coming from the server). Important is to decode them from Base64.
Now we're ready to en- and decrypt a message. This is the reason why I use both keys. Usually this is a no go (because the private key has to be kept secret!). So it's just for the prove that the OpenSSL keys work in B4A.
B4X:
'Local test with server's public & private key
mess="RSA is cool"
MessageBytes = Bconv.StringToBytes(mess, "UTF8")
MessageBytesEncrypted = c.encrypt(MessageBytes, ForeignKPG.PublicKey, False)
MessageBytesDecrypted= c.Decrypt(MessageBytesEncrypted,ForeignKPG.PrivateKey, False)
MessageStringDecrypted=Bconv.StringFromBytes(MessageBytesDecrypted,"UTF8")
Log ("Local decrypt: " & MessageStringDecrypted)
The message has to be converted to bytes, then en- and decrypted. You see the decrypted message in the logs now
Nice, but now we want to let the server decrypt the message:
B4X:
'Now let the server try to decrypt it...
MessageStringEncrypted=Bconv.HexFromBytes(MessageBytesEncrypted)
MessageStringEncrypted=su.EncodeBase64(MessageBytesEncrypted)
Log(MessageStringEncrypted)
Dim DeCryptM As HttpJob
DeCryptM.Initialize("DeCryptM", Me)
DeCryptM.Download2("http://192.168.178.21/rsa/DeCryptRSA.php", _
Array As String("Action", "DeCryptM", "Mess", MessageStringEncrypted ))
Important: Convert the message from bytes to hex and Base64 encode it. After that just send it to the script "DeCryptRSA.php" in the same folder as the scripts above:
B4X:
<?php
$pri = file_get_contents('PrivateKey.pem');
$messENC = $_GET["Mess"];
$messENC = base64_decode($messENC, true);
if (openssl_private_decrypt($messENC, $messDE, $pri))
{
print json_encode ($messDE);
}
else
{
print ("Error: Decryption failed: $pri");
}
?>
That's it... You should see the encrypted message after the job returns to JobDone.
All the needed files are included.
Libs used:
ByteConverter
Encryption
Httputils2
JSON
StringUtils
Attachments
Last edited: