Overview
This section provides the Content Provider Interface APIs for Secure Storage Manager (SSM).
Content Provider Interface APIs
Action | Method |
---|---|
Add new data. See Android reference. |
Uri insert (Uri uri, ContentValues values) |
Modify/Update existing data. See Android reference. |
int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) |
Return data based on selection criteria. See Android reference. |
Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) |
Delete data. |
int delete (Uri uri, String selection, String[] selectionArgs) |
Content Provider parameters:
Key | Value | Mandatory/Optional |
---|---|---|
target_app_package | Package name and signature of the target app in a json array. Multiple target apps and signatures can also be given in a json array. The signature must be provided in Base64 format. To generate the signature of any APK, See Get the signature of an Android APK. | Mandatory |
data_name | Unique name to identify data. | Mandatory |
data_value | Any data (string or json). | Mandatory |
data_persist_required | ASet whether persistence is required after Enterprise Reset (true/false). | Mandatory |
data_input_form | Set whether data received should be encrypted: plaintext =1, encrypted=2 |
Optional |
data_output_form | Set whether data passed to the intended recipient should be encrypted.: plaintext =1, encrypted=2 |
Optional |
Notes:
- Querying persistent data after reboot could be delayed until the system is completely initialized.
- Querying persistent data could be slower than non-persistent data, since SSM stores persistent data in a device-persistent location.
- Data names (data_name) cannot be duplicated in the same application when inserting data. If an app tries to insert a duplicate data name, it throws a Duplicate Data Name exception.
- Apps can store data only up to 10 KB in a single record. If any single data record is larger than 10 KB, it must be split and stored as multiple records with unique data names.
Get the Android APK signature
To generate the signature (signing certificate) of any APK:
Go to the Zebra App Signature Tool page.
Follow instructions for downloading and using the tool.
Use the command below (adapt as needed)
Java -jar SigTools.jar GetCert -INFORM APK -OUTFORM BASE64 -IN Client.apk -OUTFILE Client.txt
NOTES:
- “Client.apk” represents the app for which a signature is obtained.
- Signature (as a Base64 format string) is saved as “Client.txt” in the example.
- Contents of “Client.txt” can be copied as the target-package app signature.
- If a signature must be read from a file, rename “Client.txt” to “packageName.txt” (substitute “packageName” with that of the target app) and place the file in the /assets directory on the device.
Sample Code
Insert / Update Data in a Single App
Sample code to securely insert data in plain text:
private String TARGET_APP_PACKAGE = "target_app_package";
private String DATA_NAME = "data_name";
private String DATA_VALUE = "data_value";
private String DATA_INPUT_FORM = "data_input_form";
private String DATA_OUTPUT_FORM = "data_output_form";
private String DATA_PERSIST_REQUIRED = "data_persist_required";
private String MULTI_INSTANCE_REQUIRED = "multi_instance_required";
AUTHORITY = "content://com.zebra.securestoragemanager.securecontentprovider/data";
Uri cpUri = Uri.parse(AUTHORITY);
ContentValues values = new ContentValues();
// TARGET_APP_PACKAGE gives both package name info and signature info in single entry. This can be either single target app or even multiple target apps.
values.put(TARGET_APP_PACKAGE,
"{\"pkgs_sigs\": [{\"pkg\":\"com.ztestapp.clientapplication\",\"sig\":\"ABSFFSDF… WREWED\"}]}");
// Dummy sig is placed here. use SigTool to get this base64 String.
values.put(DATA_NAME, “unique name to identify data in UTF-8 encoded format");
values.put(DATA_VALUE, “any string data/json data");
values.put(DATA_INPUT_FORM, "1"); //plaintext =1, encrypted=2
values.put(DATA_OUTPUT_FORM, "1"); //plaintext=1, encrypted=2, keystrokes=3
values.put(DATA_PERSIST_REQUIRED, "false");
values.put(MULTI_INSTANCE_REQUIRED, "false");
values.put(AUTO_DELETE_REQUIRED, "false");
Uri createdRow = getContentResolver().insert(cpUri, values);
Log.d(TAG, "Created row: " + createdRow.toString());
The return URI provides the URI of the newly inserted row.
Insert / Update Data in Multiple Apps
Sample code to insert the package name and signature of all target apps as a json array in the content values object, which must then be passed to the Insert/Update method:
//Code snippet - single app support:
values.put(COLUMN_TARGET_APP_PACKAGE,
"{\"pkgs_sigs\":[{\"pkg\":\"com.ztestapp.clientapplication\",\"sig\":\"24727AB4E6C4A…ACE1FE342F0D6872B27B3C\"}
]}");
//Code snippet - multiple app support:
values.put(COLUMN_TARGET_APP_PACKAGE, "{\"pkgs_sigs\":[
{\"pkg\":\"com.ztestapp.clientapplication\",\"sig\":\"24727AB4E6C4A0BE……27B3C\"},
{\"pkg\":\"com.ztestapp.clientapplication2\",\"sig\":\"24727AB4E……872B27B3C\"},
{\"pkg\":\"com.ztestapp.abc\",\"sig\":\"25677AB4E6C……72B27B3C\"}
]}");
The return URI provides the number of rows updated.
Query
Sample code to return the package name and other parameter data:
Uri cpUriQuery = Uri.parse(AUTHORITY + "/[com.ztestapp.clientapplication]");
String selection = "target_app_package = '" + packageName + "'" +"AND "+ "data_persist_required = '" + "false" + "'" +
"AND "+"multi_instance_required = '"+ "true" + "'";
Cursor cursor = null;
try {
cursor = getContentResolver().query(cpUriQuery, null, selection, null, null);
} catch (Exception e) {
Log.d(TAG, "Error: "+ e.getMessage());
}
// Then traverse the cursor object to get the required field values using the standard Android method. Not shown here.
Limitation: When querying data from persistent storage (i.e data_persist_required = true
), large data sets are not supported due to Android parcel size limitations. “TransactionTooLargeException” is encountered if the query result data size is too large.
Delete
Sample code to delete the package name and other parameter data:
Uri cpUriDelete = Uri.parse(AUTHORITY + "/[com.ztestapp.clientapplication]");
String whereClause = "target_app_package = '" + packageName + "'" +"AND "+ "data_persist_required = '" + "false" + "'" +
"AND "+"multi_instance_required = '"+ "true" + "'";
int rowsDeleted = getContentResolver().delete(cpUriDelete, whereClause , null);