Android Tutorial Using RSA in B4A to communicate with PHP/OpenSSL

KMatle

Expert
Licensed User
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: http://www.b4x.com/android/forum/th...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:

KMatle

Expert
Licensed User
Small Problem:

In my example I can load the keys generated by OpenSSL into the KeyPairGenerator after conversation. Yesterday I tried to load the KPG generated public key (X.509 format) into OpenSSL which did not work.

Because I CAN load OpenSSL keys to KPG the format must be correct (except there is a difference between loading the PubKey from Bytes or export it to Bytes which I don't believe)

My assumption was to convert the KPG by adding "-----BEGIN PUBLIC KEY-----", etc. like I did remove it the other way but there is still something missing. Any ideas?

Will try some things this evening.
 

KMatle

Expert
Licensed User
Problem solved :D thanks this: http://stackoverflow.com/questions/...two-styles-of-public-key-format-one-begin-rsa

The KeyPairGenerator generates the Public Key in X.509 format which looks like this (as a Base64 encoded string):

B4X:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA27D+c2HxCnemIgGwBbmNBffM8GZhEd62rQWEFK2y/H0tITH5KOSUpBC0exOtVRQhFk470hSSKZj/SoUMgg63R3HKzIoxzyFP1/8BmojmKtWeKj3E8p1AgIvkOUHj8GPLEKxsK9SMZoHQsV7U5SBA35V6cJrrzdZjhExZavYS8pFJmi4kEvZJdUcH+kE2DN8s4PBR9umoeyQVnMPXi5LF0lMXq0rVthL0ORKQkjgJGKZ/qq7IcWJV/d+s0ZnRM3RNHr2fxvhk/CdU4KXp7Zwst1oE2Wdbe+rXTTlK/eMJ59BPE3ORA6oEYQLLxqaMn5r0dZwQ3S0rzDDGMMMIb3x4NQIDAQAB
What we need is this for OpenSSL (and others):

B4X:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA27D+c2HxCnemIgGwBbmNBffM8GZhEd62rQWEFK2y/H0tITH5KOSU
pBC0exOtVRQhFk470hSSKZj/SoUMgg63R3HKzIoxzyFP1/8BmojmKtWeKj3E8p1A
gIvkOUHj8GPLEKxsK9SMZoHQsV7U5SBA35V6cJrrzdZjhExZavYS8pFJmi4kEvZJ
dUcH+kE2DN8s4PBR9umoeyQVnMPXi5LF0lMXq0rVthL0ORKQkjgJGKZ/qq7IcWJV
/d+s0ZnRM3RNHr2fxvhk/CdU4KXp7Zwst1oE2Wdbe+rXTTlK/eMJ59BPE3ORA6oE
YQLLxqaMn5r0dZwQ3S0rzDDGMMMIb3x4NQIDAQAB
-----END PUBLIC KEY-----
What made me crazy about this was the fact that the Key needs to be formated "eye friedly" like you see it here (with CRLF at the end of each line) even it's the same data as in one long string. Anyway.

To convert the KPG's Public key for OpenSSL just

- add "-----BEGIN PUBLIC KEY-----" as a header and -----END PUBLIC KEY----- at the end of it.
- first line 32 Chars
- all the other 64, expcet the last one (rest)

This can be done with this code:

B4X:
c.Initialize("RSA/ECB/PKCS1Padding")
        OwnKPG.Initialize("RSA", 2048) 
        OwnKPG.GenerateKey
        OwnPrivKeyBytes=OwnKPG.PrivateKeyToBytes
       OwnPubKeyBytes=OwnKPG.PublicKeyToBytes
       
        Dim su As StringUtils
     
        Dim RawPubKey As String
        Dim l,co As Int
        RawPubKey=su.EncodeBase64(OwnPubKeyBytes)
        OwnPubKeyString = "-----BEGIN PUBLIC KEY-----" & CRLF
         
        l=32
        co=0
         
        For i=0 To RawPubKey.Length-1
            OwnPubKeyString=OwnPubKeyString & RawPubKey.CharAt(i)
            co=co+1
            If co=l Then 
              co=0
              l=64
              Log (OwnPubKeyString.Length)
              OwnPubKeyString=OwnPubKeyString & CRLF     
            End If
        Next
        OwnPubKeyString = OwnPubKeyString &  CRLF & "-----END PUBLIC KEY-----" 
       
        OwnPubKeyString = OwnPubKeyString.Replace(CRLF&CRLF,CRLF) ' Replace double CRLF's
       
        Log("OwnPubKey: " & OwnPubKeyString)
         
        OwnPubKeyBytes=Bconv.StringToBytes(OwnPubKeyString,"UTF8")
        OwnPubKey64StringExport=su.EncodeBase64(OwnPubKeyBytes)
         
        Log("OwnPubKeyExport: " & OwnPubKey64StringExport)
The Public Key can now transmitted via httputils to a php script:

B4X:
Dim EnCryptRSA As HttpJob
     EnCryptRSA.Initialize("EnCryptRSA", Me)
     EnCryptRSA.Download2("http://192.168.178.21/rsa/EnCryptRSA.php",  _
                 Array As String("Action", "EnCryptRSA", "PubKey", OwnPubKeyString, "Mess", MessageStringDecrypted  ))
PHP:

B4X:
<?php

    $messDE = $_GET["Mess"];
    $pub = $_GET["PubKey"];
    $pub = base64_decode($pub, true);
    openssl_public_encrypt($messDE, $messEN, $pub);
    $messEN=base64_encode($messEN);
    print json_encode ($messEN);
?>
Getting back to JobDone & DeCrypt:

B4X:
Log ("Encrypted Message from Server: " & res)
Dim su As StringUtils
MessageStringEncrypted=parser.NextValue
MessageBytesEncrypted=su.DecodeBase64(MessageStringEncrypted)
MessageBytesDecrypted=c.Decrypt(MessageBytesEncrypted,OwnKPG.PrivateKey,False)
MessageStringDecrypted=Bconv.StringFromBytes(MessageBytesDecrypted,"UTF8")
MessageBytesDecrypted=su.DecodeBase64(MessageStringDecrypted)
MessageStringDecrypted=Bconv.StringFromBytes(MessageBytesDecrypted,"UTF8")
Voilà :D

I've encoded the message to base64 before encryption and after. After receiving the encrypted message it has to be decoded 2 times back.

So now we can exchange keys, en-/decrypt messages between B4A and php/OpenSSL (or other Clients)
 
Last edited:

Abílio Magalhães

Member
Licensed User
Hello.
After following your tutorial I've encountered an issue.
I've created a method which takes as a parameter a string to be encrypted with RSA with a given public key and encode it on Base64 and return that string.

The method is the following:

B4X:
Sub encripta_md5_em_rsa_base64(md5_hash As String) As String
   
    Dim ForeignKPG As KeyPairGenerator
    Dim c As Cipher
    Dim su As StringUtils
    Dim Bconv As ByteConverter
   
    Dim ForeignPubKeyString As String
    Dim ForeignPubKeyBytes(0) As Byte
   
    Dim MessageBytes(0),MessageBytesEncrypted(0) As Byte
    Dim MessageStringEncrypted As String
       
    Dim retorna As String
   
   
    ' inicializa
    retorna = ""
    c.Initialize("RSA/ECB/PKCS1Padding")
    ForeignKPG.Initialize("RSA", 2048)
    ForeignPubKeyString = File.ReadString(File.DirAssets, "pkey.txt").Trim
   
    ' converte a chave pública, faz o seu decode
    ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
    ForeignPubKeyString = Bconv.StringFromBytes(ForeignPubKeyBytes, "UTF8")

    ' retira os begin e end da chave
    ForeignPubKeyString = ForeignPubKeyString.Replace("-----BEGIN PUBLIC KEY-----","")
    ForeignPubKeyString = ForeignPubKeyString.Replace("-----END PUBLIC KEY-----","")
   
    ' faz novamente o decodeBase64
    ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
   
    ' instancia a chave
    ForeignKPG.publicKeyFromBytes(ForeignPubKeyBytes)
   
    ' converte o md5_hash em bytes
    MessageBytes = Bconv.StringToBytes(md5_hash, "UTF8")
   
    ' encripta
    MessageBytesEncrypted = c.encrypt(MessageBytes, ForeignKPG.PublicKey, False)
   
    ' encode em Base64
    MessageStringEncrypted = Bconv.HexFromBytes(MessageBytesEncrypted)
    MessageStringEncrypted = su.EncodeBase64(MessageBytesEncrypted)
   
    ' retorna
    retorna = MessageStringEncrypted
    Return retorna
   
End Sub
When I run the program, it stops on the following line:

B4X:
ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
Prompting the following error:

B4X:
java.io.IOException: Bad Base64 input character decimal 45 in array position 0
I can't figure it out why this is happening!

The given public key is on it's 'regular' format.
 

Abílio Magalhães

Member
Licensed User
Hello.
After following your tutorial I've encountered an issue.
I've created a method which takes as a parameter a string to be encrypted with RSA with a given public key and encode it on Base64 and return that string.

The method is the following:

B4X:
Sub encripta_md5_em_rsa_base64(md5_hash As String) As String
  
    Dim ForeignKPG As KeyPairGenerator
    Dim c As Cipher
    Dim su As StringUtils
    Dim Bconv As ByteConverter
  
    Dim ForeignPubKeyString As String
    Dim ForeignPubKeyBytes(0) As Byte
  
    Dim MessageBytes(0),MessageBytesEncrypted(0) As Byte
    Dim MessageStringEncrypted As String
      
    Dim retorna As String
  
  
    ' inicializa
    retorna = ""
    c.Initialize("RSA/ECB/PKCS1Padding")
    ForeignKPG.Initialize("RSA", 2048)
    ForeignPubKeyString = File.ReadString(File.DirAssets, "pkey.txt").Trim
  
    ' converte a chave pública, faz o seu decode
    ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
    ForeignPubKeyString = Bconv.StringFromBytes(ForeignPubKeyBytes, "UTF8")

    ' retira os begin e end da chave
    ForeignPubKeyString = ForeignPubKeyString.Replace("-----BEGIN PUBLIC KEY-----","")
    ForeignPubKeyString = ForeignPubKeyString.Replace("-----END PUBLIC KEY-----","")
  
    ' faz novamente o decodeBase64
    ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
  
    ' instancia a chave
    ForeignKPG.publicKeyFromBytes(ForeignPubKeyBytes)
  
    ' converte o md5_hash em bytes
    MessageBytes = Bconv.StringToBytes(md5_hash, "UTF8")
  
    ' encripta
    MessageBytesEncrypted = c.encrypt(MessageBytes, ForeignKPG.PublicKey, False)
  
    ' encode em Base64
    MessageStringEncrypted = Bconv.HexFromBytes(MessageBytesEncrypted)
    MessageStringEncrypted = su.EncodeBase64(MessageBytesEncrypted)
  
    ' retorna
    retorna = MessageStringEncrypted
    Return retorna
  
End Sub
When I run the program, it stops on the following line:

B4X:
ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
Prompting the following error:

B4X:
java.io.IOException: Bad Base64 input character decimal 45 in array position 0
I can't figure it out why this is happening!

The given public key is on it's 'regular' format.
SOLVED
 

ArminKH

Well-Known Member
@KMatle
i was looking for RSA Encryption for B4A since 4 month ago and now it is seems a big success for b4a community
i can't test it right now but i'm sure it's great
thank u for sharing;)
 

ziomorgan

Member
Licensed User
Hello.
After following your tutorial I've encountered an issue.
I've created a method which takes as a parameter a string to be encrypted with RSA with a given public key and encode it on Base64 and return that string.

The method is the following:

B4X:
Sub encripta_md5_em_rsa_base64(md5_hash As String) As String
  
    Dim ForeignKPG As KeyPairGenerator
    Dim c As Cipher
    Dim su As StringUtils
    Dim Bconv As ByteConverter
  
    Dim ForeignPubKeyString As String
    Dim ForeignPubKeyBytes(0) As Byte
  
    Dim MessageBytes(0),MessageBytesEncrypted(0) As Byte
    Dim MessageStringEncrypted As String
      
    Dim retorna As String
  
  
    ' inicializa
    retorna = ""
    c.Initialize("RSA/ECB/PKCS1Padding")
    ForeignKPG.Initialize("RSA", 2048)
    ForeignPubKeyString = File.ReadString(File.DirAssets, "pkey.txt").Trim
  
    ' converte a chave pública, faz o seu decode
    ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
    ForeignPubKeyString = Bconv.StringFromBytes(ForeignPubKeyBytes, "UTF8")

    ' retira os begin e end da chave
    ForeignPubKeyString = ForeignPubKeyString.Replace("-----BEGIN PUBLIC KEY-----","")
    ForeignPubKeyString = ForeignPubKeyString.Replace("-----END PUBLIC KEY-----","")
  
    ' faz novamente o decodeBase64
    ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
  
    ' instancia a chave
    ForeignKPG.publicKeyFromBytes(ForeignPubKeyBytes)
  
    ' converte o md5_hash em bytes
    MessageBytes = Bconv.StringToBytes(md5_hash, "UTF8")
  
    ' encripta
    MessageBytesEncrypted = c.encrypt(MessageBytes, ForeignKPG.PublicKey, False)
  
    ' encode em Base64
    MessageStringEncrypted = Bconv.HexFromBytes(MessageBytesEncrypted)
    MessageStringEncrypted = su.EncodeBase64(MessageBytesEncrypted)
  
    ' retorna
    retorna = MessageStringEncrypted
    Return retorna
  
End Sub
When I run the program, it stops on the following line:

B4X:
ForeignPubKeyBytes = su.DecodeBase64(ForeignPubKeyString)
Prompting the following error:

B4X:
java.io.IOException: Bad Base64 input character decimal 45 in array position 0
I can't figure it out why this is happening!

The given public key is on it's 'regular' format.

Hi,
i have the same problem.
can you show me the solution please ?
Thanks
 

KMatle

Expert
Licensed User

deantangNYP

Active Member
Licensed User
encrypted.JPG

Please Please advise.. Many Thanks.

May i know if i wish to Decrypt the Text (assuming "string1", the encrypted string need to be converted to what format?) in yellow in B4a, what is the procedure? Is the following procedure correct?

1) MessageBytes = Bconv.StringToBytes(string1, "UTF8")
2) MessageBytesDecrypted= c.Decrypt(MessageBytes,ForeignKPG.PrivateKey, False)
3) MessageStringDecrypted=Bconv.StringFromBytes(MessageBytesDecrypted,"UTF8")
 
Last edited:

Javier Alonso

Member
Licensed User
Just a working example on RSA encrypting/decrypting between php and B4A.
I got it working using in B4A a cipher like "RSA/ECB/PKCS1Padding" and PKCS1 padding in PHP.

Generating keys and encrypting in B4A with the public key:
B4X:
Dim su As StringUtils
Dim c As Cipher
Dim k As KeyPairGenerator
c.Initialize("RSA/ECB/PKCS1Padding")
k.Initialize("RSA", 256)
k.GenerateKey
Log(su.EncodeBase64(k.PublicKeyToBytes))
Log(su.EncodeBase64(k.PrivateKeyToBytes))
Dim original(), final() AsByte
original = su.DecodeBase64("fzyKUNceSnDPaQcsruf8cg==")
Log("Original: " & su.EncodeBase64(original))
final = c.Encrypt(original, k.PublicKey, False)
Log("Output: " & su.EncodeBase64(final))
it relies on StringUtils and Encryption. The data to encode is a random 16 bytes long byte array. The key length is maybe too short (256), you may use 1024 or 2048.
The ouput shows the Base64 encoding of the original data and the public and private keys

To decrypt in php use:
B4X:
$encrypted = base64_decode('IuFMrbbZv6yA4eK7ErzmjlCZzKcTz9eXJhmZ8g6OyJ0='); // Or whatever the encoded string is

   if (!$privateKey = openssl_pkey_get_private('-----BEGIN PRIVATE KEY-----
MIHCAgEAMA0GCSqGSIb3DQEBAQUABIGtMIGqAgEAAiEAurV1KKl17MmWL+pVR2Gh
fAqPudllIxj85g034zFTwOUCAwEAAQIhAJS9E/11qpUdLsEzLAa2lz5uhO+BNVx+
E/Bf2S3uclHBAhEA3laF2PsQaHPXn87YV/XoMQIRANb6AOSh7IFBRhJla3yMqvUC
EF83KobrrfEtevADQv8YXmECEA9Cd8XC6LLUG1E6+cJBifECEBJAPbKNda4/o4kz
g1K6E2Q=
-----END PRIVATE KEY-----'))
   {
       die('Private Key failed');
   }
   $a_key = openssl_pkey_get_details($privateKey);

   $decrypted = '';
   if (!openssl_private_decrypt($aes, $output, $privateKey, OPENSSL_PKCS1_PADDING))
   {
       echo('Failed to decrypt data<br>');
   } else {
      echo(base64_encode($output) . '<br>');
   }
   openssl_free_key($privateKey);
Copy the base64-encoded private key obtained in B4A and paste it in php. It has to be formatted exactly this way, in 64-chars lines.

Encryption in php using the public key:
B4X:
   $original = base64_decode('fzyKUNceSnDPaQcsruf8cg==');

   if (!$publicKey = openssl_pkey_get_public('-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALq1dSipdezJli/qVUdhoXwKj7nZZSMY
/OYNN+MxU8DlAgMBAAE=
-----END PUBLIC KEY-----')) {
       die('.NOPublic Key failed');
   }
   $a_key = openssl_pkey_get_details($publicKey);

   if (!openssl_public_encrypt($original, $encrypted, $publicKey, OPENSSL_PKCS1_PADDING))
   {
      die('Failed to encrypt data');
   } else {
      echo(base64_encode($encrypted) . '<br>');
   }
   openssl_free_key($publicKey);
Again, the base64-encoded public key has to be pasted in 64-chars lines.

Decription in B4A (preloading the public and private keys, instead of generating them):
B4X:
Dim su AsStringUtils
Dim c AsCipher
Dim k AsKeyPairGenerator
c.Initialize("RSA/ECB/PKCS1Padding")
k.Initialize("RSA", 256)
k.PrivateKeyFromBytes(su.DecodeBase64("MIHCAgEAMA0GCSqGSIb3DQEBAQUABIGtMIGqAgEAAiEAurV1KKl17MmWL+pVR2GhfAqPudllIxj85g034zFTwOUCAwEAAQIhAJS9E/11qpUdLsEzLAa2lz5uhO+BNVx+E/Bf2S3uclHBAhEA3laF2PsQaHPXn87YV/XoMQIRANb6AOSh7IFBRhJla3yMqvUCEF83KobrrfEtevADQv8YXmECEA9Cd8XC6LLUG1E6+cJBifECEBJAPbKNda4/o4kzg1K6E2Q="))
k.PublicKeyFromBytes(su.DecodeBase64("MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALq1dSipdezJli/qVUdhoXwKj7nZZSMY/OYNN+MxU8DlAgMBAAE="))
Dim original(), final() AsByte
original = su.DecodeBase64("NliuUtAcFefpEC90mLjsyDXxoIy063iuzar724GBe3s=")
Log("Original: " & su.EncodeBase64(original))
final = c.Decrypt(original, k.PrivateKey, False)
Log("Output: " & su.EncodeBase64(final))
Hope it helps
 
Top