The Titanium SDK provides a Ti.App.Properties
object, which provides a convenient way to persist user and application information. The Securely
framework provides a familiar API designed to mirror Ti.App.Properties
, which allows you to persist this information in a secure fashion. This recipe describes how to use the Securely.Properties
object to store, read, and remove data in/from an encrypted and secure manner.
This recipe uses the Securely
native module. This module and other code assets can be downloaded from the source provided by the book, or individually through the links provided in the See also section at the end of this recipe. Installing these in your project is straightforward. Simply, copy the modules
folder into your project as shown in the following screenshot:
This recipe is designed to run within the context of a Ti.UI.Window
or other component within a single Titanium context. The code samples in this section demonstrate how to use the Secure properties of Securely
using the same tests that Appcelerator uses for the Titanium SDK's Ti.App.Properties
class. For more information, please refere to the app.js
included with the recipe's source.
Once you have added the Securely
module to your project, you need to create your application namespace in the app.js
file and use require
to import the module into your code as the following code snippet demonstrates:
//Create our application namespace var my = { secure : require('bencoding.securely'), isAndroid : Ti.Platform.osname === 'android', testObjects:{ testList : [ {name:'Name 1', address:'1 Main St'}, {name:'Name 2', address:'2 Main St'} ] } };
After the app namespace has been created, the next step is to create a new properties object. This object contains the following property values that must be set at creation time:
secret
: This is a required parameter. secret
is the password used to encrypt and decrypt all property values. The same secret
used to encrypt must be used during the decryption process or a null
value will be returned.identifier
: This parameter is optional. If no value is provided, the bundle name on iOS or the PackageName
on Android is used. identifier
allows you to segment each property with an identifier, if needed.accessGroup
: This parameter is an optional value used on the iOS platform. Access groups can be used to share keychain items among two or more applications. If no access group is provided, the keychain values will only be accessible within the app saving the values.encryptFieldNames
: This parameter is an optional value only used on the Android platform. When set to true
, Securely
will create an MD5 hash using the provided secret
for all property names.var properties = my.secure.createProperties({ secret:"sshh_dont_tell", identifier:"myPropertyIdentifier", accessGroup:"myAccessGroup", encryptFieldNames:false });
The displayResults
function shown in the following code snippet is used to compare the test result with the expected value. Based on the comparison, the proper message is generated for presenting to the user.
function displayResults(result, expected) { if (result instanceof Array) { return displayResults(JSON.stringify(result), JSON.stringify(expected)); }else{ if (result === expected) { return "Success ("+result+"=="+expected+")"; } else { return "Fail: " + result + "!=" + expected; } } };
Each supported property type has a get
method. For example, to read a Boolean property, the getBool
method is called and a name is provided. This API works similar to the Ti.App.Properties
object within the Titanium SDK, with added support for reading and decrypting secure properties. If no stored value is available, a null or default value type is provided. The following snippet demonstrates how to read saved secure property values:
Ti.API.info('Bool: ' + displayResults(properties.getBool('whatever'), (my.isAndroid ? false : null))); Ti.API.info('Double: ' + displayResults(properties.getDouble('whatever'), (my.isAndroid ? 0: null))); Ti.API.info('int: ' + displayResults(properties.getInt('whatever'), (my.isAndroid ? 0 : null))); Ti.API.info('String: ' + displayResults(properties.getString('whatever'),null)); Ti.API.debug('StringList: ' + displayResults(properties.getList('whatever'),null));
Also similar to Ti.App.Properties
, Securely
provides the ability to read and decrypt a secure property and provide a default value if there is no stored value for the requested secure property.
Ti.API.info('Bool: ' + displayResults(properties.getBool('whatever',true),true)); Ti.API.info('Double: ' + displayResults(properties.getDouble('whatever',2.5),2.5)); Ti.API.info('int: ' + displayResults(properties.getInt('whatever',1),1)); Ti.API.info('String: ' + displayResults(properties.getString('whatever',"Fred"),"Fred")); Ti.API.debug('StringList: ' + displayResults(properties.getList('whatever'),testList));
Each supported property type has a set
method used to encrypt and persist values. For example, to save and encrypt a Boolean property and the setBool
method, and provide a property name and Boolean value. This API works similar to the Ti.App.Properties
object within the Titanium SDK. Securely
supports both encrypting and writing the value to the secure properties directly. The following code snippet demonstrates how to save the following values to secure and encrypted storage:
properties.setString('MyString','I am a String Value '), properties.setInt('MyInt',10); properties.setBool('MyBool',true); properties.setDouble('MyDouble',10.6); properties.setList('MyList',my.testObjects.testList);
To demonstrate the properties were saved correctly, the get
method is called for each file and the results are printed to the console within Titanium Studio.
Ti.API.info('MyString: '+ properties.getString('MyString')); Ti.API.info('MyInt: '+ properties.getString('MyInt')); Ti.API.info('MyBool: '+ properties.getString('MyBool')); Ti.API.info('MyDouble: '+ properties.getString('MyDouble')); var list = properties.getList('MyList'), Ti.API.info('List: ' + JSON.stringify(list));
The property names can be returned as an array by calling the listProperties
method on the Securely
property object. The following code snippet demonstrates how to use this method to print a JSON representation of the names
array to the console within Titanium Studio.
if(!properties.hasFieldsEncrypted()){ var allProperties = properties.listProperties(); Ti.API.info(JSON.stringify(allProperties)); }
You can remove properties using two methods on the Securely
properties object. The removeProperty
and removeAllProperties
are designed to be familiar and mirror the methods with the same name on the Titanium SDK's Ti.App.Properties
object.
The removeProperty
method will remove the provided secure property name, if it exists.
properties.removeProperty('MyInt'),
The removeAllProperties
method will remove all properties within the identifier provided when creating the properties object.
properties.removeAllProperties();
The Securely property object provides the hasProperty
method to provide the ability to check if a secure property exists. If the property exists, a Boolean true
value is returned, otherwise a result of false
is provided. This API is designed to be familiar as it mirrors the Ti.App.Properties.hasProperty
function within the core Titanium SDK.
Ti.API.info("Does MyInt property exist? " + properties.hasProperty('MyInt'));
The underlying infrastructure for secure properties is implemented differently depending on the platform running your application. Although Securely
provides a cross-platform API, it is important to understand how each platform has been implemented and its associated security considerations.
The Securely
framework saves all property values as serialized strings within the iOS Keychain. This provides secure storage and since it is part of iOS does not require any dependencies. Since Securely
uses the iOS keychain service, it is recommended that your organization review Apple's Keychain documents before storing sensitive data within the securely-managed container.
The Securely
framework saves all property values as serialized and AES-encrypted strings into Android's SharedPreferences
. Although Android introduced native keychain support in API level 14, the Securely
module was designed to accommodate a larger number of devices and targets API level 8 and higher. It is recommended that your Enterprise reviews the secure properties' implementation within Securely
to ensure it is in compliance with your corporate or industry standards and requirements.
By default on Android, the property names are not encrypted. This can be enabled by setting the encryptFieldNames
on creation of the properties
object. Due to the need to encrypt all property names, this property can only be set on creation of a new properties
object. When field name encryption is enabled, Securely
will create a SHA-1 hash for each field name using the secret
property value provided. Enabling this feature creates performance considerations. Regression and performance testing is recommended before implementing your existing Titanium app.
18.219.182.76