Secure Public Key Encryption: Android Key Generation and Server Encryption

July 19, 2016 | Views: 9465

Begin Learning Cyber Security for FREE Now!

FREE REGISTRATIONAlready a Member Login Here

Hello everyone!

This article depicts a specific problem I encountered on one of my recent projects. The main problem was: ONE of my project modules had a specific functionality, which involved key generation on an Android device. The public key is transmitted to the web server, which then uses public key sent to encrypt the requisite secret and display the encrypted secret as a QR code on the desktop. Finally, the Android app we developed decodes the QR code and the private key (which was generated before), then decrypts the cipher to get the secret back.

The reverse process had many solutions. But, for my problem, there were bits and pieces everywhere. We found it would be better to generate keys on client app, as it would avoid sending private keys back to client if generated on the server and thus triggering channel breaking attacks.

I’ll mainly explain the three sub-functions, which were carried out by the main module.

  1. Key pair generation on Android app
  2. Public key encryption on server ( uses RSA algorithm) and encoding cipher to QR code using PHP
  3. QR code decode and decryption of cipher to get the secret generated by the server

 

1. Key pair generation on Android app

We mainly use “spongy castle” as our default security provider. It’s an alternative to default bouncy castle.

If you’re developing an app using Android studio like me, and in order to get the required repo module, add these lines to your app gradle:

compile 'com.madgag.spongycastle:core:1.54.0.0'
compile 'com.madgag.spongycastle:prov:1.54.0.0'
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
compile 'com.madgag.spongycastle:pg:1.54.0.0'

The next main thing is to add the following to the main class of the intent you’re going to generate keys. This is done to make sure we use spongy castle as our security provider.

static {
        Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
    }

Let's come to the key pair generation, required code for the key pair generation.


try {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "SC"); //specify the algorithm for generation
    generator.initialize(1024); //initialize
    KeyPair kPair = generator.generateKeyPair(); //generate a keypair
        byte[] privateKeyEnc = kPair.getPrivate().getEncoded(); //store private key as byte stream
        byte[] publicKeyEnc = kPair.getPublic().getEncoded(); //store public key as byte stream
         publicKey = new String(Base64.encode(publicKeyEnc)); //encode to base64 format and store it as string .this is sent to server
         privateKey = new String(Base64.encode(privateKeyEnc)); //encode to base64 format and store it as string 
    }
    catch(Exception e) {

        Log.d("failure","fail"); //for debugging


    }


2. Public key encryption on server (uses RSA) and encoding cipher to QR code using PHP

The public key is received by the back-end server. We used pure implementation of the RSA algorithm provided by phplibsec library for PHP. We also used the phpqrcode library to encode cipher text into qrcode format.

The main code required for the operation:

$publicKey = $_POST[‘pub’]; //received from the android app.

include(‘Crypt/RSA.php’);   //include phplibsec library
$rsa = new Crypt_RSA();

$rsa->setHash(‘sha1’);  //set the required parameters for encryption such as hash algorithm
$rsa->setMGFHash(‘sha1’);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP); //follows Optimal asymmetric encryption padding
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1); //set the private key format
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1); //set the public key format
$key = “—–BEGIN PUBLIC KEY—–n” .($publicKey)
. ‘—–END PUBLIC KEY—–‘;//this is done to adjust key to actual format provided by lib.
$rsa->loadKey($key);

$messageEncrypt = base64_encode($rsa->encrypt(“secret_to_be_shared”)); //encrypt the secret to be shared and encode it to base64.

include “phpqrcode/qrlib.php”; //include the qrcode library
$tempDir = EXAMPLE_TMP_SERVERPATH; //store path for temporary server storage
$codeContents = $messageEncrypt;
$fileName = ‘filename.png’; //custom qrcode file name.this is for test purpose.can be modified to generate for parallel access

$pngAbsoluteFilePath = $fileName; //pathnames

$urlRelativeFilePath = $fileName;
if (!file_exists($pngAbsoluteFilePath)) {
QRcode::png($codeContents, $pngAbsoluteFilePath); //qrcode generation and this is displayed on the screen.

}

 

3. QR code decode and decryption of cipher to get the secret generated by the server

In this sub module, we decode the QR code to get the cipher text and finally decrypt using the private key, which was generated by the Android.

-> Don’t forget to add spongy castle as a default security provider at the intent, which is used to decipher the cipher text.

-> I mainly used a method of calling the QR code app installed already on the mobile device to decode the QR code. I passed the request as an intent. (DM me for the code.)

->I received the result and finally decrypt using a private key. Make sure to specify default service provider as spongy castle here, too (in this intent).

CODE:

byte[] privateKeyBytes = Base64.decode(privatekey); //rivert back to byte stream
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); //get the keyspec back
KeyFactory fact = KeyFactory.getInstance(“RSA”, “SC”); //specify the required algo and security provider
PrivateKey priv = fact.generatePrivate(keySpec);
Cipher rsaCipher = Cipher.getInstance(“RSA/None/OAEPWithSHA1AndMGF1Padding”, “SC”); //specify parameters
rsaCipher.init(Cipher.DECRYPT_MODE, priv);
byte[] messageDecoded = Base64.decode(contents); //cipher text resulted from decoding qr code is base64 decoded to byte stream
byte[] messageDecryptBytes = rsaCipher.doFinal(messageDecoded); decode the cipher byte stream
String messagedecrypt = new String(messageDecryptBytes);  store it as a string
Log.d(“decrypteddddd”, messagedecrypt); //for logging purpose

 

Finally…we get the secret on the Android device shared only between device and the server.

So, why did I use QR encoding as a way of communication between app and server?

QR codes are small for temporary storage and they offer additional security measures (they implement security by default). Our project was mainly focused on a new high secure authentication technique, which required faster transmission and additional security (this module is just a part of it). And, we already know two-way authentication can also be vulnerable to high specialized attacks such as social engineering (Mobile is secure!! But, not the carriers delivering such messages? Sigh!!.)

 

Why did I write this article, anyway?

There were very few bits and pieces required for the process which we carried out. It would be great to have everything in a single place. It would help fellow security developers.

Well, that’s it…let me know your suggestions in the comment section below.

Share with Friends
FacebookTwitterLinkedInEmail
Use Cybytes and
Tip the Author!
Join
Share with Friends
FacebookTwitterLinkedInEmail
Ready to share your knowledge and expertise?
10 Comments
  1. Great work! I think QR code implementation for security uses is great.

  2. Thank u

  3. Awesome work!?

  4. Can you please explain where are you storing private key on android device ?

    • Hello ankur,as you can see I am storing it in a variable called privateKey …this variable is passed to the next intent which involves decoding of QR code ,by which we recieve a cipher text which is finally decrypted by the privateKey…and not to forget key pair generation is unique per session and also it creates a unique finger print of device per session..only the device which has valid private key can decrypt the cipher text received.

  5. Nice
    😉

Comment on This

You must be logged in to post a comment.

Our Revolution

We believe Cyber Security training should be free, for everyone, FOREVER. Everyone, everywhere, deserves the OPPORTUNITY to learn, begin and grow a career in this fascinating field. Therefore, Cybrary is a free community where people, companies and training come together to give everyone the ability to collaborate in an open source way that is revolutionizing the cyber security educational experience.

Cybrary On The Go

Get the Cybrary app for Android for online and offline viewing of our lessons.

Get it on Google Play
 

Support Cybrary

Donate Here to Get This Month's Donor Badge

 
Skip to toolbar

We recommend always using caution when following any link

Are you sure you want to continue?

Continue
Cancel