Posted on by

Today’s guest tutorial comes to you courtesy of Mark Eberhardt, the founder of Minion Multimedia, an independent app development studio based in the Pacific Northwest. Mark has been a Corona developer for the last several years, releasing a variety of cross-platform apps for iOS and Android.

open-ssl-feat

When Corona Labs introduced Corona Plugins, I was excited to learn that OpenSSL was one of the first in the initial batch. Using this, my apps can be further enhanced to protect my customers’ privacy. Most of this I learned from George Zhao’s documentation and files on his GitHub page. Now, in this tutorial, I’ll show you how to initialize the appropriate plugin module, then to do some basic encryption and decryption.


Additions to “build.settings”

The first step is to add a couple of lines to the build.settings file to support the OpenSSL plugin:

settings =
{
   plugins =
   {
      ["plugin.openssl"] = { publisherId = "com.coronalabs", },
   },
}

Setting Up

Next, you need to require the plugin in the main project file:

local openssl = require "plugin.openssl"

Next, we’ll create a cipher object. The method can be a variety of encryption methods. For the sake of this tutorial, we’ll use “aes-256-cbc”.

local cipher = openssl.get_cipher ( "aes-256-cbc" )

Encryption

To encrypt a string of text, we’ll use the following line of code:

local encryptedData = cipher:encrypt ( "text", "key" )

The text is a string that you want encrypted, and key is a string containing a passphrase, which can be anything.

If you want the user to be able to select their own passphrase, a simple native text field could be used to get their input. Additionally, you could have that input hashed using the crypto functions.

local crypto = require "crypto"
local key = crypto.digest( crypto.sha256, "plainTextPassPhrase" )

Encoding the Text for Transport

I also like to apply a base64 encode on the encrypted text. This allows for easier storage or data sharing. To encode the text as base64 is really simple. We enable the mime functions then call b64 to encode the text.

local mime = require ( "mime" )
local encryptedData = mime.b64 ( cipher:encrypt ( "text", "key" ) )

Now the encrypted data is stored as a base64 string.


Decryption

If we want to decrypt something, it’s just as easy!

local decryptedData = cipher:decrypt ( "text", "key" )

Just replace text with the encrypted text, and key with the the string that was used to encrypt the text with. If the encrypted text is base64 encoded, it’s easy to undo the encoding — just use mime.unb64.

local mime = require ( "mime" )
local decryptedData = cipher:decrypt ( mime.unb64 ( "text" ), "key" )

Overall Code

Here’s the overall code up to this point:

local openssl = require "plugin.openssl"

local cipher = openssl.get_cipher ( "aes-256-cbc" )
local mime = require ( "mime" )

local encryptedData = mime.b64 ( cipher:encrypt ( "Your Text Here", "Your Key Here" ) )
local decryptedData = cipher:decrypt ( mime.unb64 ( encryptedData ), "Your Key Here" )

print ( "Encrypted Text: " .. encryptedData )
print ( "Decrypted Text: " .. decryptedData )

PHP

If you want to take things further and if your web host has the OpenSSL module installed, you can create a PHP script that can encode/decode text sent to/from your app:

<?php

$source = 'Your Encrypted Text Here';
$pass = 'Your Key here';
$method = 'aes-256-cbc';

$encrypted = base64_encode ( openssl_encrypt ( $source, $method, $pass ) );

?>

This will return a base64-encoded string that can be decoded with OpenSSL — and decryption is just as simple:

$decrypted = openssl_decrypt ( base64_decode ( $encrypted ), $method, $pass );

So the full scope of the php script would be:

<?php

$source = 'Your Encrypted Text Here';
$pass = 'Your Key here';
$method = 'aes-256-cbc';

$encrypted = base64_encode ( openssl_encrypt ( $source, $method, $pass ) );

$decrypted = openssl_decrypt ( base64_decode ( $encrypted ), $method, $pass );

?>

In practical use, if you’re sending encrypted data to the script, you could replace the $source variable with:

$source = $_POST["yourPostVariable"]

Using “luasec” With OpenSSL

The OpenSSL plugin allows you to do secure socket communication in Lua using luasec. This wraps your insecure protocol in SSL. Please refer to the samples in the Corona Labs GitHub repository. The luasec sample explains how to create the server-side of the secure connection. It requires you to use the test server built into the “openssl” command-line utility that comes with OpenSSL.

To accomplish this, you’ll need to create a private and public key pair server-side. Here’s how:

  1. Generate a private key:
    openssl genrsa -out key.pem 1024
  2. Generate a signing request. Skip any questions you feel like skipping, or fill them out any way you want; it doesn’t matter for testing purposes.
    openssl req -new -key key.pem -out req.pem
  3. Self-sign the request for, let’s say, 10 years:
    openssl x509 -req -days 3650 -in req.pem -signkey key.pem -out cert.pem
  4. Now you have a private key (key.pem) and a signed public key (cert.pem). With these, you’re ready to spawn a server for testing your keys — this example requests the server to listen for incoming connections on port “64001”:
    openssl s_server -key key.pem -cert cert.pem -accept 64001
  5. Connect to your server using the built-in client — this example assumes the server is at IP “10.3.3.129″, listening on port “64001”:
    openssl s_client -connect 10.3.3.129:64001
  6. Type in some random text and you should see it transmitted to the other side. With that working, kill your server (Control-C) and spawn a new secure web server:
    openssl s_server -key key.pem -cert cert.pem -accept 64001 -www

    Now connect to this server using the luasec sample and you should get a response outputted to the console. We’re done: secure socket communication in Corona! Just note that HTTPS requests are done much more easily using network.request() — web documents shouldn’t be requested using luasec.


Export Compliance

To be perfectly clear, I am not a lawyer. Most likely, you will need to fill out some forms to receive the proper paperwork when submitting apps to the Android stores or submitting to Apple for export compliance review.

More information on this subject can be found in the World Wide Trade Compliance section of iTunes Connect, under Policy and Best Practices in the Google Play Developer Console, or at the Bureau of Industry and Security.

In the meantime, these links may help narrow down your particular situation:

U.S. Export Compliance:

French Export Compliance:


In Summary…

As you can see, setting up Corona’s OpenSSL plugin is fast and easy. In just a few lines of code, you can be encrypting and decrypting data! For further reference, please review the documentation, and please post your questions and feedback below.


Posted by . Thanks for reading...

17 Responses to “Tutorial: Using the OpenSSL Plugin”

  1. Jens

    Very interesting! Has anyone tried this out in regard to performance? Kan you expect to encrypt/decrypt kbytes of data in under a second on a device? I have tried another (plain) lua-implemententation of aes and it was not very fast. I think it was the bit manipulation that was the main hindrance.

    Reply
  2. Mark

    @Jens encrypt/decrypt does work pretty fast… I have myself tried a lua-implemententation of aes that wasn’t fast… I haven’t done massive text lengths of text->aes encryption. But again before even small text lengths seem to take forever.

    Reply
  3. Simon Fearby

    Error: Warning: openssl_encrypt() [function.openssl-encrypt]: Using an empty Initialization Vector (iv) is potentially insecure and not recommended

    Workaround here: http://php.net/manual/en/function.openssl-encrypt.php

    dont forget the 2 further parameters. $iv needs to be sent during decryption too.

    php:
    $source = ‘Your Encrypted Text Here’;
    $pass = ‘yourpasswordhere’;
    $method = ‘aes-256-cbc’;
    $raw_output = false;
    $iv = “1721597321565789″;

    $encrypted = base64_encode ( openssl_encrypt ( $source, $method, $pass, $raw_output, $iv) );

    Reply
  4. tgl87

    Thank you for this tutorial

    Writing this line
    local cipher = openssl.get_cipher ( “aes-256-cbc” ), I was wondering which other methods are available? I tried to find a list somewhere, but no such luck.

    It seems from what you say, that other arguments are available:
    “Next, we’ll create a cipher object. The method can be a variety of encryption methods. For the sake of this tutorial, we’ll use “aes-256-cbc”.”

    I need the encryption to use the sha1 algorithm.

    Reply
  5. Leonardo Borsten

    I’m having difficulty using the examples of the PHP decryption script. I am trying this:
    $decrypted = openssl_decrypt ( base64_decode ( $_REQUEST ), $method, $pass );
    I am assuming that the encrypted data is carried in the $_REQUEST. The $_REQUEST appears to be an array. The key part of the array looks like the encrypted data and the value part of the array is empty.

    What is the proper way to receive and parse the posted encryption in PHP?

    Reply
  6. yosu

    Pls note that in PHP, openSSL automatically performs base64 on it. So, the example above needs to be updated as such :

    $encrypted = base64_encode ( openssl_encrypt ( $source, $method, $pass ) );
    TO
    $encrypted = ( openssl_encrypt ( $source, $method, $pass ) );

    Reply
  7. Romowski

    Thank you for great tutorial!!! Unfortunately I have an error in line

    Can somebody help me to solve this issue?

    Error: “module ‘plugin_openssl’ not found:resource (plugin_openssl.lu) does not exist in archive
    no field package.preload['plugin_openssl']
    no file ‘/Users/Apple/Library/Application Support/Corona/Simulator/Plugins/plugin_openssl.lua’
    no file ‘/Users/Apple/Library/Application Support/luaglider2/dev/ProjectBuilds/MyGreatSteppe(Builds)/MyGreatSteppe(default)/MyGreatSteppe/plugin_openssl.lua’
    no file ‘/Applications/CoronaSDK/Corona Simulator.app/Contents/Resources/plugin_openssl.lua’
    no file ‘/Users/Apple/Library/Application Support/Corona/Simulator/Plugins/plugin_openssl.dylib’
    no file ‘./plugin_openssl.dylib’
    no file ‘/Applications/CoronaSDK/Corona Simulator.app/Contents/Resources/plugin_openssl.dylib’”

    Reply
    • Brent Sorrentino

      Hi Edwin,
      Yes, OpenSSL is restricted to Pro/Enterprise users.

      Best regards,
      Brent

      Reply
  8. Samuel

    Hi, I followed step by step this tutorial to use SSL in both local and remote, but the results of encryption are completely different:

    ———–
    At local:

    local openssl = require “plugin.openssl”

    local cipher = openssl.get_cipher ( “aes-256-cbc” )
    local mime = require ( “mime” )

    local encryptedData = mime.b64 ( cipher:encrypt ( “test”, “test” ) )
    local decryptedData = cipher:decrypt ( mime.unb64 ( encryptedData ), “test” )

    print ( “Encrypted Text: ” .. encryptedData ) — 33zefe1wMVR3XvkzkVBo9Q==
    print ( “Decrypted Text: ” .. decryptedData ) — test

    local testParams = {body = “encryptedData=” .. encryptedData}

    network.request( url .. “test.php”, “POST”, networkListener, testParams)

    —————–
    At remote:

    Any idea of what I’m doing wrong? :(

    Reply
      • Samuel

        *Oops, triple post. Sorry about this.

        $source = ‘test’;
        $pass = ‘test’;
        $method = ‘aes-256-cbc’;

        $encrypted = base64_encode ( openssl_encrypt ( $source, $method, $pass ) );
        echo “encrypted : ” .$encrypted; // MzN6ZWZlMXdNVlIzWHZremtWQm85UT09

        $decrypted = openssl_decrypt ( base64_decode ( $encrypted ), $method, $pass );
        echo “decrypted : ” .$decrypted; // ‘test’

        $encryptedData = $_POST['encryptedData'];
        echo ‘source : ‘ .$encryptedData; // 33zefe1wMVR3XvkzkVBo9Q==

        $decryptedData = openssl_decrypt ( base64_decode ( $encryptedData ), $method, $pass );
        echo “decryptedData : ” .$decryptedData; // ” (empty)

        Reply

Leave a Reply

  • (Will Not Be Published)