Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development Knowledge Base

BlackBerry 10 - Using one-way encryption for password storage

by Retired ‎12-04-2012 11:29 AM - edited ‎07-15-2013 04:13 AM (8,129 Views)

 

Introduction

 

BlackBerry® 10 has a set of security related APIs collectively known as the Security Builder® Crypto-C™ APIs. In this knowledge base article we examine how Security Builder can be used to allow passwords to be securely stored using a technique known as “one way encryption”. A sample Cascades™/C++ application called PasswordSample is used to illustrate the various points of this article and is available from our Cascades Community Samples repository in full.

  

Readers should be familiar with C/C++ but do not need any particular prior knowledge of information security or cryptography.

 

The authors

 

This article was co-authored by Martin Woolley and John Murray both of whom work in the RIM Developer Relations team. Both Martin and John specialize in NFC applications development but are interested in pretty much everything technical... including security. Rob Williams lent a hand too... he’s quite the security expert, having worked for Certicom for 6 years.

 

About the BlackBerry 10 Security Builder APIs

 

The Security Builder API provides a full range of cryptography related functions which you can exploit for various purposes from within your own applications. The various types of algorithms supported include ECC (Elliptic Curve Cryptography), symmetric and asymmetric encryption, hash functions, MAC functions and more. You can check the documentation, for which a link is provided at the end of this article, for full details.

 

For typical use cases the API is pretty straightforward and often you won’t need to know much about how it’s implemented or the details of the cryptographic functions that you are reliant upon.

 

That said, the Security Builder has an interesting architecture and whilst you may not *need* to fully appreciate it, you will probably find it interesting, so let’s start there. 

 

Security Builder acts as an abstraction layer which sits in front of components from some other “provider” or “providers”. So in a way, Security Builder does not actually provide any security functionality (directly) at all. All the action happens in the provider components.

  

What is a “provider”, I hear you say, and what is the point of having another API in front of the provider? Well, a provider may be a software library or, perhaps, a piece of hardware such as a crypto acceleration card. A provider software library will typically include implementations of particular cryptography functions and algorithms, and you could, in theory, use that library directly from your code. But different libraries from different vendors are likely to have different APIs which will make maintenance and portability more difficult over time. Security Builder hides details by allowing a provider’s library to be “plugged in” using an adaptor framework and then accessed via the uniform, abstract API of the Security Builder. The eagle-eyed amongst you will have noticed one other point too; you can hide multiple providers behind the Security Builder so in addition to abstracting and hiding API differences, it can also aggregate functions from a series of different providers so they’re all accessible from the one, unifying API, that of the Security Builder.

  

If you’re following this (and we hope you are!) then you may well have one rather important question in your mind. If the BlackBerry 10 Security Builder API is “just” a fancy abstraction and adapter layer, then what concrete cryptography implementations are available on BlackBerry 10? Or to put it another way, is there a ready-made “provider” that you can use right out of the box?

 

Happily, the answer is YES! 

 

BlackBerry 10 includes the Security Builder GSE-C 5.6 Provider (SB-GSE-C). Note that “GSE” stands for Government Security Edition and that another name for “SB-GSE-C” is the “BlackBerry OS Cryptographic Kernel”. At the time of writing, BlackBerry OS Cryptographic Kernel (version 5.6) has been validated to FIPS 140-2, Level 1, under Certificate # 1578.

 

So, armed with the Security Builder APIs and the concrete, SB-GSE-C provider, you should have everything you need.

 

User ID and password authentication

 

A common requirement of many systems is to authenticate users by user ID and password before allowing them access to the system’s main functionality. There are other ways of authenticating users of course, but user ID and password is good enough for many scenarios and is therefore a popular response to the requirement.

 

User ID + password solutions will generally need both user ID and password to be stored somewhere such that when the user attempts to “log in”, the user ID and password that they enter can be compared with the details previously set up and stored against their profile. The question then arises as to how best to store the user’s password such that it can be considered private and safe from unauthorized use by anyone with access to the machine upon which the password is stored, and such that it’s still easy to compare the stored password with a password entered by a user through a user interface?

 

One approach involves a technique sometimes referred to as “one way encryption”.

 

Before we dive into "one-way encryption", you should note the following points:

 

  • There are various ways of authenticating a user. User ID and Password is just one. You will need to assess which method is appropriate to your needs and particular security requirements. Remember that security is not "on or off". In other words it's not always useful to think in terms of something being either "secure" or "insecure". Security is a continuum with very weak security at one end and very strong security at the other and you'll need to decide where on that spectrum your solution needs to be.
  • If you do use User ID and Password then consider the use of a "salt" to make your credentials store resistant to dictionary attacks. Wikipedia describes "Salt" in the field of cryptography here: http://en.wikipedia.org/wiki/Salt_(cryptography)
  • Good user ID and password implementations will include rules that ensure "good" passwords are selected by users. For example it's common and good practice to see minimum lengths enforced and a particular mix of character types (e.g. numeric, alphabetic, punctuation) mandated.

This article and the sample application "PasswordSample" that accompanies it deliberately keeps things simple so we can focus on learning how to use the Security Builder APIs and so we neither use a salt nor enforce any particular rules about passwords.

 

 

One way encryption

 

“One-way encryption” utilizes what are known as one way hash functions. These are mathematical functions that convert variable length strings into fixed length binary bit sequences. The binary sequence produced by a hash function is known as a “hash” or “message digest”. It’s extremely hard to reverse the process (hence “one way”) and a good algorithm will also make it very hard to find two different input strings that will generate the same hash as output. Examples of commonly used hash algorithms are MD2, MD4, MD5, SHA-1 and SHA-256. Some are better than others and some are in fact considered quite weak these days and therefore we recommend certain of these are not used (e.g. MD2 and MD4).

 

You can find our recommendations as well as details of all hash algorithms supported by the Security Builder API in the reference documentation here: 

http://developer.blackberry.com/native/beta/reference/com.qnx.doc.crypto/topic/c_dg_recommend_hash_a...

 

User credentials may need to be transmitted across a network too, in which case it would be common to use a protocol such as HTTPS to ensure details cannot be intercepted by eavesdroppers. We’re going to focus on one-way encryption for secure storage of credentials in this article rather than protection of data “in flight” across a network.

 

 

The PasswordSample application

 

The PasswordSample application has a UI through which users must correctly enter a user ID and password before being given access to other functions, which in this case is simply a user profile page where the user’s details, including user ID and password, can be changed. The user profile details are persisted locally on the BlackBerry 10 device and user ID and password are protected using one-way encryption.

 

combined_screenshots.jpg

Figure 1 - The PasswordSample application

 

Using the Security Builder APIs

 

Making use of the Security Builder API generally follows the same, standard pattern regardless of the particular cryptography operations you wish to perform. The pattern generally looks like this:

 

steps.png

Figure 2 - Using the Security Builder APIs

 

Note that Security Builder methods generally return an int return code which indicates the success or failure of operations. This should be checked after each call. A value of SB_SUCCESS indicates the operation was successful.


 

Making a hash of it

 

Let’s look at exactly how PasswordSample creates hash values from user ID and password data.

 

To make life easy, all crypto operations were implemented in a singleton class called SecurityManager. The set up step was implemented in a method called initSecurity. Here’s what it looks like:

 

int SecurityManager::initSecurity() {

	qDebug() << "XXXX initSecurity";

	int returnCode = SB_SUCCESS; /* Return Code */

	/* Create SB Contexts */

	returnCode = hu_GlobalCtxCreateDefault(&sbCtx);

	if (returnCode != SB_SUCCESS) {
		qDebug() << "XXXX makeHash ERROR creating SB contexts:" << Utilities::intToHex(returnCode);
		return returnCode;
	}

	// Register global context with GSE-C 5.6 Provider
	// GSE = Government Security Edition (SB GSE-C)
	// SB GSE-C is also known as BlackBerry OS Cryptographic Kernel

	returnCode = hu_RegisterSbg56(sbCtx);
	if (returnCode != SB_SUCCESS) {
		qDebug() << "XXXX makeHash ERROR calling hu_RegisterSbg56:" << Utilities::intToHex(returnCode);
		return returnCode;
	}

	returnCode = hu_InitSbg56(sbCtx);
	if (returnCode != SB_SUCCESS) {
		qDebug() << "XXXX makeHash ERROR calling hu_InitSbg56:" << Utilities::intToHex(returnCode);
		return returnCode;
	}

	return returnCode;
}

 Figure 3 - Preparing to use the Security Builder API

 

Step 3, clean up, was implemented in its own method as well:

 

void SecurityManager::endSecurity() {
	/* Clean up contexts */
	qDebug() << "XXXX endSecurity";
	(void) hu_SHA256End(&sha256Context, NULL, sbCtx);
	hu_GlobalCtxDestroy(&sbCtx);
}

 Figure 4 - Cleaning up at the end

 

To make sure endSecurity() is always called before the application exits, we used Qt’s signals/slots to ensure that when our application is about to exit, a method of our own is invoked. This is where we call the endSecurity() method. All this code resides in PasswordSample.cpp.

 

PasswordSample::PasswordSample(bb::cascades::Application *app) :
		QObject(app) {
....
    connect(app, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
......

}

void PasswordSample::onAboutToQuit() {
	SecurityManager* sec_mgr = SecurityManager::getInstance();
	sec_mgr->endSecurity();
}

 Figure 5 - Using signals and slots to ensure we clean up on exit

 

We also implemented a method called makeHash in SecurityManager. It takes two parameters; the first a QString which contains the input data we wish to make the hash for, and the second, a pointer to a char array. This is where the message digest is stored once calculated. Here’s the code:

  

int SecurityManager::makeHash(const QString input_data, unsigned char* messageDigest) {

	/* Initialize variables */

	int returnCode = SB_SUCCESS; /* Return Code */

	QByteArray input_bytes = input_data.toUtf8();
	unsigned char* hash_input = reinterpret_cast<unsigned char*>(input_bytes.data());

	returnCode = hu_SHA256Begin((size_t) SB_SHA256_DIGEST_LEN, NULL, &sha256Context, sbCtx);
	if (returnCode != SB_SUCCESS) {
		qDebug() << "XXXX makeHash ERROR initialising SHA-256 context:" << Utilities::intToHex(returnCode);
		return returnCode;
	}

	/* Hash Message */

	returnCode = hu_SHA256Hash(sha256Context, (size_t) input_bytes.length(), hash_input, sbCtx);
	if (returnCode != SB_SUCCESS) {
		qDebug() << "XXXX makeHash ERROR creating hash:" << Utilities::intToHex(returnCode);
		return returnCode;
	}

	/* Complete SHA-256 Hashing */

	returnCode = hu_SHA256End(&sha256Context, messageDigest, sbCtx);
	if (returnCode != SB_SUCCESS) {
		qDebug() << "XXXX makeHash ERROR completing hashing" << Utilities::intToHex(returnCode);
		return returnCode;
	}

	return SB_SUCCESS;
}

 Figure 6 - Making the message digest AKA hash

 

You can see that creating a message digest requires three API calls in total; hu_SHA256Begin, hu_SHA256Hash, and hu_SHA256End. The documentation describes each of these methods as follows:

 

 

hu_SHA256Begin Creates a SHA-256 context object
hu_SHA256Hash Updates a SHA-256 context with the given data
hu_SHA256End Completes the message digest operation by generating the digest and destroying the SHA-256 context object

 

Putting it all together

 

PasswordSample stores a hex encoded representation of hash values derived from both the user ID and password. We chose to store it in a hex encoded representation for no other reason than to make it easy to display the values. A QSettings object is used for the persistent storage. This is a really simple to use class from Qt which is good for storing name/value pairs. On the device, your QSettings object ends up as a “.conf” file in your application’s sandbox in a sub-directory of the data/ directory. You can see this in the figure below. That’s a view of a BlackBerry Dev Alpha’s file system obtained using the Momentics IDE’s TargetFileSystemNavigator by the way.

 

QSettings_file_in_dir.png

Figure 7 - QSettings data in PasswordSample.conf in the application sandbox

 

Here’s what the file contained after a non-default user ID and password had been set along with a first name and last name for the user, using PasswordSample’s user profile page:

 

QSettings_file_content.png

Figure 8 - QSettings file contents

 

It’s clear that the first_name and last_name values have not been hashed whereas the password and user_id values have been. Knowing the hash values for these fields is of no value whatsoever though; you need to know the strings that gave rise to those particular hash values and only the user that chose the user ID and password can know this.

 

Now, when the user attempts to login, they must enter a user ID and password value. To establish whether these are correct or not, PasswordSample has to create message digests of each of these values, hex encode them and then compare them with the hex encoded hash values that were previously stored. If the values match then the user must have entered the right values. This is all achieved in the method isCredentialsOk.

 

bool SecurityManager::isCredentialsOK(QString entered_user_id, QString entered_password) {
	qDebug() << "XXXX isCredentialsOK(" << entered_user_id << "," << entered_password << ")";
	int result = SB_SUCCESS;
	DataManager* data_mgr = DataManager::getInstance();
	QString current_user_id_hash_as_hex = data_mgr->getUserid();
	QString current_password_hash_as_hex = data_mgr->getPassword();
	bool password_ready = false;
	// if DataManager was not able to provide the stored password or a default then it will have returned an empty string
	if (current_password_hash_as_hex.length() > 0) {
		password_ready = true;
	}

	// if we were unable to either
	// a) restore password from QSettings or
	// b) create a default password using the SB API then
	// we have a system error and it's game over

	if (!password_ready) {
		qDebug() << "XXXX SYSTEM ERROR: password not ready";
		return false;
	}

	// hash the user ID entered by the user and compare it with the user_id hash restored from QSettings
	unsigned char message_digest_user_id[SB_SHA256_DIGEST_LEN];
	QString entered_user_id_hash = "";
	result = makeHash(entered_user_id, message_digest_user_id);
	if (result == SB_SUCCESS) {
		QByteArray entered_user_id_data = QByteArray::fromRawData(reinterpret_cast<const char *>(message_digest_user_id), SB_SHA256_DIGEST_LEN);
		QString entered_user_id_hash_as_hex = QString::fromAscii(entered_user_id_data.toHex());
		qDebug() << "XXXX entered user_id hash:" << entered_user_id_hash_as_hex;
		qDebug() << "XXXX current user_id hash:" << current_user_id_hash_as_hex;
		if (current_user_id_hash_as_hex.compare(entered_user_id_hash_as_hex) != 0) {
			qDebug() << "XXXX incorrect credentials entered #1";
			return false;
		}
	} else {
		qDebug() << "XXXX SYSTEM ERROR: failed to calculate hash of entered user_id:" << result;
		return false;
	}

	// hash the password entered by the user and compare it with the password hash restored from QSettings
	unsigned char message_digest_password[SB_SHA256_DIGEST_LEN];
	QString entered_password_hash = "";
	result = makeHash(entered_password, message_digest_password);
	if (result == SB_SUCCESS) {
		QByteArray entered_password_data = QByteArray::fromRawData(reinterpret_cast<const char *>(message_digest_password), SB_SHA256_DIGEST_LEN);
		QString entered_password_hash_as_hex = QString::fromAscii(entered_password_data.toHex());
		qDebug() << "XXXX entered password hash:" << entered_password_hash_as_hex;
		qDebug() << "XXXX current password hash:" << current_password_hash_as_hex;
		if (current_password_hash_as_hex.compare(entered_password_hash_as_hex) != 0) {
			qDebug() << "XXXX incorrect credentials entered #2";
			return false;
		} else {
			return true;
		}
	} else {
		qDebug() << "XXXX SYSTEM ERROR: failed to calculate hash of entered password:" << result;
		return false;
	}
}

 Figure 9 - Checking credentials entered by the user against the hash values stored in QSettings

 

Summary

 

The Security Builder API is a powerful and extensible framework for cryptography oriented operations. We’ve scraped the surface here by looking at one specific use case: that of user ID and password based authentication and storage. You can find out more about the Security Builder API by following these links:

 

Security Builder User's Guide:

http://developer.blackberry.com/native/documentation/bb10/com.qnx.doc.crypto/topic/c_sb_ug_overview....

 

GSE-C 5.6 Provider - http://developer.blackberry.com/native/documentation/bb10/com.qnx.doc.crypto/topic/c_sbgse_adp_intro...

 

PasswordSample has been released as an open source application. You can download the code from here:

https://github.com/blackberry/Cascades-Community-Samples/tree/master/PasswordSample

 

Note that in addition to demonstrating a simple application of the Security Builder APIs, PasswordSample also includes:

  • A custom QML control. The Timer class is exposed to QML and used to remove UI messages after a 5 second delay.
  • Dynamic management of Tabs in a TabbedPane
  • Simple animations. Go on.... touch one of the padlock graphics. You know you want to....
  • Covers. Minimize the application when either "logged in" or not logged in and note the image on the minimized application's Active Frame
  • Use of QSettings for simple persistent storage of name/value pairs

  

You can contact Martin, John or Rob through the BlackBerry support forums or through Twitter®:

 

 

  Support Forum ID Twitter
Martin mwoolley @mdwrim
John jomurray @jcmrim
Rob   @robbieDubya
Contributors
Users Online
Currently online: 40 members 6,094 guests
Please welcome our newest community members: