Skip to Content

Encrypted Storage

The Encrypted Storage plugin provides an asynchronous API to store key value pairs securely. The API is based on the web storage interface but is asynchronous in nature. The Logon plugin also provides get and set methods that can be used to store user names, password, keys and certificates while the Encrypted Storage plugin is better suited to storing application data.

For additional details see C:\SAP\MobileSDK3\KapselSDK\docs\api\sap.EncryptedStorage.html or Using the Encrypted Storage Plugin.

The following steps will demonstrate this plugin.

  • In the folder C:\Kapsel_Projects\KapselGSDemo add the encrypted storage plugin.
    cordova plugin add kapsel-plugin-encryptedstorage --searchpath %KAPSEL_HOME%/plugins
    or
    cordova plugin add kapsel-plugin-encryptedstorage --searchpath $KAPSEL_HOME/plugins
    
  • Replace www\index.html with with the following content.
    <html>
        <head>
            <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
            <script type="text/javascript" src="cordova.js"></script>
            <script type="text/javascript" charset="utf-8" src="serverContext.js"></script>
    
            <script>
                window.onerror = onError;
                keyTextField = "";
                valueTextField = "";
                resultsTextArea = "";
                storeName = "testStore";
                store = null;
                
                function onError(msg, url, line) {
                    var idx = url.lastIndexOf("/");
                    var file = "unknown";
                    if (idx > -1) {
                        file = url.substring(idx + 1);
                    }
                    alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
                    return false; //suppressErrorAlert;
                }
                
                function init() {
                    if (sap.Logger) {
                        sap.Logger.setLogLevel(sap.Logger.DEBUG);  //enables the display of debug log messages from the Kapsel plugins.
                        sap.Logger.debug("Log level set to DEBUG");
                    }
                    if (navigator.notification) { // Override default HTML alert with native dialog. alert is not supported on Windows
                        window.alert = navigator.notification.alert;
                    }
                    keyTextField = document.getElementById("keyTextField");
                    valueTextField = document.getElementById("valueTextField");
                    resultsTextArea = document.getElementById("resultsTextArea");
                    
                    var passcodePolicy = {
                            "expirationDays":"0",
                            "hasDigits":"false",
                            "hasLowerCaseLetters":"false",
                            "hasSpecialLetters":"false",
                            "hasUpperCaseLetters":"false",
                            "defaultAllowed":"true",
                            "lockTimeout":"5",
                            "minLength":"6",
                            "minUniqueChars":"0",
                            "retryLimit":"5"
                    };
                    
                    //Used if the application is not registering with the SMP 3.0 server.  New to SP03.
                    sap.Logon.initPasscodeManager(successCallback, errorCallback, appId, null, passcodePolicy, context);
                    
                    //Used if the application registers with the SMP 3.0 server
                    //sap.Logon.init(successCallback, errorCallback, appId, context);
                    
                    createStore();
                }
                
                function createStore() {
                    store = new sap.EncryptedStorage(storeName); //SP03 the Encrypted Storage plugin requires logon.  API changed no password required.
                    //store = new sap.EncryptedStorage(storeName, "securePassword123");  //SP02
                }
                
                function deleteStore() {
                     store.deleteStore(successCallback, errorCallback);
                }
                
                function successCallback(info) {
                    console.log("Success: " + JSON.stringify(info));
                }
                
                function errorCallback(errorInfo) {
                    alert("Error: " + JSON.stringify(errorInfo));
                }
                
                function setItem(key, value) {
                    store.setItem(key, value, successCallback, errorCallback);
                }
                
                function getItem(key) {
                    store.getItem(key, function(value) {
                        console.log(value);
                        resultsTextArea.value = resultsTextArea.value + key + ":" + value + "\n";
                    }, errorCallback);
                }
    
                function setItemLogon(key, value) {
                   sap.Logon.set(successCallback, errorCallback, key, value);
                }
                
                function getItemLogon(key) {
                    sap.Logon.get(function(value) {
                        console.log(value);
                        resultsTextArea.value = resultsTextArea.value + key + ":" + value + "\n";
                    }, errorCallback, key);
                }
                
                function removeItem(key) {
                    store.removeItem(key, successCallback, errorCallback);
                }
                
                function clearAll() {
                    store.clear(successCallback, errorCallback);
                }
                
                function showAll() {
                    resultsTextArea.value = "";
                    store.length(function(length) {
                        for (var i = 0; i < length; i++) {
                            store.key(i, function(key) {
                                getItem(key);
                            }, errorCallback);
                        }
                    }, errorCallback);
                }
                
                document.addEventListener("deviceready", init, false);    
            </script>
        </head>
        <body>
            <h1>EncryptedStorage Sample</h1>
            <button id="setItem" onclick="setItem(keyTextField.value, valueTextField.value)">Set Item</button>
            <button id="getItem" onclick="resultsTextArea.value='';getItem(keyTextField.value)">Get Item</button>
            <button id="removeItem" onclick="removeItem(keyTextField.value)">Remove Item</button>
            <button id="clearAll" onclick="clearAll()">Clear All Items</button>
            <button id="showAll" onclick="showAll()">Show All Items</button>
            <button id="deleteStore" onclick="deleteStore()">Delete Store</button>
            <button id="createStore" onclick="createStore()">Create Store</button><br><br>
            <button id="setItemLogon" onclick="setItemLogon(keyTextField.value, valueTextField.value)">Set Item from Logon</button>
            <button id="getItemLogon" onclick="resultsTextArea.value='';getItemLogon(keyTextField.value)">Get Item from Logon</button>
            <button id="lockDV" onclick="sap.Logon.lock(successCallback, errorCallback)">Lock Data Vault</button>
            <button id="unlockDV" onclick="sap.Logon.unlock(successCallback, errorCallback)">Unlock Data Vault</button>
            <button id="deletePCM" onclick="sap.Logon.deletePasscodeManager(successCallback, errorCallback)">Delete PasscodeManager</button>
            <button id="initPCM" onclick="init()">Init PasscodeManager</button>
            <button id="dataVaultState" onclick="sap.Logon.core.getState(function(value) {alert(JSON.stringify(value))}, errorCallback)">Show Data Vault state</button><br>
            Key:<input type="text" id="keyTextField"><br>
            Value:<input type="text" id="valueTextField"><br>
            <textarea rows="10" cols="30" id="resultsTextArea"></textarea><br>
        </body>
    </html>​
  • Notice that the API is asynchronous. This can make it a bit more challenging to work with. The article Asynchronous JS: Callbacks, Listeners, Control Flow Libs and Promises provides some suggestions on how to work with asynchronous methods.
  • Prepare, build and deploy the app with the following command.
    cordova run android
    or 
    cordova run windows -- --archs=x64 
    or
    cordova run windows --device -- --archs=arm --phone
    or
    cordova run ios

  • If the Logging plugin is added and the log level set to debug, the messages logged by the Encrypted Storage plugin can be viewed. The log tag it uses is SMP_ENCRYPTED_STORAGE.
  • The data vault of the Logon plugin is required by the Encrypted Storage plugin. The Logon plugin can be initialized using the method sap.Logon.initPasscodeManager. This is to be used instead of sap.Logon.init if the application is not registering against an SAP Mobile Platform. Note that in the case where a registration is not being performed, the passcode policy must be supplied as it is not provided by an SMP or HCPms server.If the Logon plugin’s data vault is deleted, the EncyptedStorage plugin will also delete all storage as well. This can occur when the user clicks the Forgot Application Passcode button on the unlock screen of the Logon plugin, if the user enters too many incorrect passcodes or if the method sap.Logon.core.deleteRegistration is called.
  • The following are some technical details of where the data is stored on Android.
    Key value pairs are stored in a SQLLite Database.
    The database is created using local storage which can only be accessed by the application that created it. The file is stored under /data/data/packageName and can be seen and accessed when using an emulator but not a device.The values and the keys stored in this SQLLite database are encrypted. See Encrypted Storage Plugin for additional technical details on the encryption used to store the data.

Back to Getting Started with Kapsel

To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. Umer Farooq

    Thank you for a very informative blog on Encrypted Storage. A quick question though …

    We have a complex structure of oData with multiple navigation and 1..n relationships that are being persisted via CREATE_DEEP_ENTITY operation in ONLINE mode.

    In OFFLINE application, we are saving the same complex structure (multiple entries) in EncryptedStorage and show it to user in ‘Outbox’. Than we synchronise the Outbox and persist the data with CREATE_DEEP_ENTITY once user comes online. Is this the right usage of EncryptedStorage for storing such data or are we missing something here? As far as I know multiple navigation with 1…n is not yet supported with oData offline.

    Thanks.

    (0) 

Leave a Reply