You need to encrypt a database based on a user’s password. In addition, you need to allow the user to change his password and update the encryption accordingly.
Use the user’s password as the basis for the encryption key, and use the reencrypt() method of the SQLConnection class to change the encryption key for a database.
Although creating a random key may work for many situations, in some cases it is preferable to base the key on user input. This is ideal in situations where you are downloading password-protected data from an online service, for example, as it allows the same password that secures the data online to secure the data in the AIR application.
Because the
open() and
openAsync() methods of the
SQLConnection class expect a 16-byte binary key, you will need to create a MD5 hash of the user's password by utilizing the AS3Crypto library. This creates the needed 16-byte
ByteArray that can then be passed into the
open() or
openAsync() method.
When the user changes his password, the
reencrypt() method of the
SQLConnection class allows the application to change the encryption key for a specific database, as long as the database connection has already been opened with the old encryption key. Once this method has been called, a transaction-like process is executed. If the process is
interrupted before completion, the database retains the old encryption key. If the process is completed successfully, a
SQLEvent.REENCRYPT event is dispatched. If it fails, a
SQLError.ERROR event is dispatched.
Warning
Remember that a database that is not encrypted cannot be encrypted; its data must be imported into a new encrypted database.
In this example, the user must specify a password to connect to the database. If the database does not exist, a new database is created using the password hash as the encryption key. While the database is connected, the user can enter a new password and click the Change Password button. This
triggers the
reencrypt() method, which changes the encryption key for the database.
You will need to include the AS3Crypto library for this project, because it will be used to generate the random encryption key. Download the
as3crypto.swc file from
http://code.google.com/p/as3crypto/ and add it to your project's build path.
To create the encryption key, the
MD5 class from the AS3Crypto library is used along with the password entered by the user. The password, which is passed into the function as a string, is converted into a
ByteArray by using the
writeUTFBytes() method. Next, the
MD5 class is instantiated, and the
hash() method is called on the
ByteArray. The returned value is used as the encryption key for the database:
private function createEncryptionKey(password:String):ByteArray {
var ba:ByteArray = new ByteArray();
ba.writeUTFBytes(password);
var md5:MD5 = new MD5();
var output:ByteArray = md5.hash(ba);
return output;
}
To allow the changing of the password, the
reencrypt() method of the
SQLConnection class is used. This method must be called while the
SQLConnection is open:
connection.addEventListener(SQLEvent.REENCRYPT, handleDatabaseReencrypt); connection.reencrypt( createEncryptionKey(newPassword.text) );
The completed example, shown here, integrates all this functionality into a single AIR application:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:s= "library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
horizontalAlign="left">
<s:layout><s:HorizontalLayout/></s:layout>
<fx:Script>
<![CDATA[
import flash.utils.ByteArray;
import mx.collections.ArrayCollection;
import com.hurlant.crypto.hash.MD5;
public static const ENCRYPTED_DB_FILE:String = "encrypted.db";
[Bindable]
private var results:ArrayCollection = new ArrayCollection();
private var connection:SQLConnection;
private var dbFile:File;
private function createEncryptionKey(password:String):ByteArray {
var ba:ByteArray = new ByteArray();
ba.writeUTFBytes(password);
var md5:MD5 = new MD5();
var output:ByteArray = md5.hash(ba);
results.addItem("[ACTION]: Hash Key Created " +
output.toString());
return output;
}
private function handleConnectClick(event:MouseEvent):void {
results.addItem("[ACTION]: Attempting Database Connection");
dbFile = File.applicationStorageDirectory.resolvePath(
ENCRYPTED_DB_FILE );
connection = new SQLConnection();
connection.addEventListener(SQLEvent.OPEN,
handleDatabaseOpen);
connection.addEventListener(SQLErrorEvent.ERROR,
handleDatabaseError);
connection.openAsync(dbFile,SQLMode.CREATE,null,false,1024,
createEncryptionKey(password.text));
}
private function handleDisconnectClick(event:MouseEvent):void {
connection.close();
disconnectButton.enabled = false;
password.enabled = true;
connectButton.enabled = true;
newPassword.enabled = false;
reencryptButton.enabled = false;
}
private function handleReencryptClick(event:MouseEvent):void {
connection.addEventListener(SQLEvent.REENCRYPT,
handleDatabaseReencrypt);
connection.reencrypt(createEncryptionKey(newPassword.text));
}
private function handleDatabaseOpen(event:SQLEvent):void {
results.addItem("[ACTION]: Database Connection Successful");
disconnectButton.enabled = true;
newPassword.enabled = true;
reencryptButton.enabled = true;
password.enabled = false;
connectButton.enabled = false;
}
private function handleDatabaseReencrypt(event:SQLEvent):void {
connection.removeEventListener(SQLEvent.REENCRYPT,
handleDatabaseReencrypt);
results.addItem("[ACTION]: Database Reencrypted");
}
private function handleDatabaseError(event:SQLErrorEvent):void {
results.addItem("[ERROR]: Database Error " +
event.error.detailArguments.toString() );
}
]]>
</fx:Script>
<mx:Label text="Encryption By Password" fontWeight="bold" fontSize="18" />
<mx:Label text="Connect To Database" fontWeight="bold"/>
<s:HGroup>
<s:Label text="Password" />
<s:TextInput id="password" />
<s:Button id="connectButton" label="Connect"
click="handleConnectClick(event)" />
<s:Button id="disconnectButton" label="Disconnect"
click="handleDisconnectClick(event)" enabled="false" />
</s:HGroup>
<s:Label text="Change Password / ReEncrypt" fontWeight="bold"/>
<s:HGroup>
<s:Label text="New Password" />
<s:TextInput id="newPassword" enabled="false" />
<s:Button id="reencryptButton" label="Change Password"
click="handleReencryptClick(event)" enabled="false" />
</s:HGroup>
</s:WindowedApplication>
This recipe was originally contributed by Marco Casario as part of O'Reilly's Flex 4 Cookbook.
+