Encrypt ArcGIS offline map and its implementation on Android

Source: Internet
Author: User

 

How to encrypt ArcGIS offline Map

Currently, slice files in the compact format are a good solution for offline maps. However, if we want to restrict offline maps from being used by third-party programs, or, you want to restrict offline maps to only authorized devices. In this case, we must protect the offline map data deployed on smart devices. Therefore, we need to encrypt the offline map data.

Here, I use this idea, which includes the following main steps:

1. The authorized device serial number + confidential identifier is then generated by MD5.

2. MD5 checksum is distributed together with encrypted offline data. A third-party program cannot obtain a confidential identifier and thus cannot generate a correct checksum.

3. encryption of offline data is achieved through encrypted index files, and encryption is achieved through byte exchange, which basically does not affect performance.

4. the algorithms used to read encrypted files are encapsulated in the dynamic connection library to ensure that the algorithms cannot be obtained by third parties through decompilation.

The following describes the implementation of each link in detail.

Device unique identity confirmation

The unique serial number of a device may have different acquisition methods on different systems. By combining the CPU serial number, IMEI serial number, MAC address, and other methods, you can generate different identifiers for each device, for example, in Android, an serial number can be generated by combining IMEI and imsi:

Telephonymanager TM = (telephonymanager)This

. Getsystemservice (context.Telephony_service);

String IMEI = TM. getdeviceid ();

String imsi = TM. getsubscriberid ();

DeviceID = string.Format("% S-% s", IMEI, imsi );

For example, here I get a device ID "000000000000000-3102600000000000000". Next I will attach a confidential identifier to the above device ID based on different situations, and then calculate its MD5 verification value:

String id = string.Format("% S-% s", DeviceID, "wuyf_qwert ");

Messagedigest MD = messagedigest.Getinstance("MD5 ");

Byte[] Bytes = md. Digest (Id. getbytes ());

Result = stringutil.Bytestohexstring(Bytes );

Here, "wuyf_qwert" is a defined secret identifier. This secret identifier is only known to the data publisher. Therefore, a third party cannot generate a verification value by itself through the device identifier. Finally, you can save the verification value in a file named after the device serial number and publish it together with the data (multiple devices use multiple verification files for easy deletion ).

Figure 1 verification file deployed with data

Offline map Encryption

Considering the impact of performance, encryption of offline maps must be as simple as possible. Therefore, here we use the encryption method for offline Map Index files. For the original index data file, we only need to exchange several bytes. You can change your encryption method as needed. Similarly, this encryption method is only known to the data Publisher:

Static Public VoidEncrypt (string inpath, string outpath ){

Fileinputstream in =Null;

Fileoutputstream out =Null;

Try{

File infile =NewFile (inpath );

File OUTFILE =NewFile (outpath );

In =NewFileinputstream (infile );

Out =NewFileoutputstream (OUTFILE,False);

IntRead;

Read = in. Read ();

IntCount = 0;

While(Read! =-1 ){

ByteB = (Byte) Read;

// Here, the number of replicas can be increased to increase the complexity of files.

If(Read = 3 ){

B = (Byte) 37;

Count ++;

}Else If(Read = 37 ){

B = (Byte) 3;

Count ++;

}

Out. Write (B );

Read = in. Read ();

}

Out. Flush ();

System.Out. Println (count );

}Catch(Exception ex ){

Ex. printstacktrace ();

}Finally{

Try{

In. Close ();

Out. Close ();

}Catch(Exception ex ){}

}

}

Read encrypted offline maps from devices

The device can read encrypted offline maps in two steps: Verify the device's identity and obtain encrypted data. Both steps must be encapsulated in the dynamic connection library to ensure algorithm confidentiality. On Android, JNI is required. We can encapsulate these two steps in a C function:

Jniexport jbytearray jnicallJava_com_esri_wuyf_jni_getencrypttile(Jnienv * ENV,

Jobject OBJ, jstring strdeviceid, jstring strlocation,

Jstring strbundlebase, jint level, jint row, jint col ){

Jbytearray result = 0;

Const Char* DeviceID = (* env)-> getstringutfchars (ENV, strdeviceid, 0 );

Const Char* Location = (* env)-> getstringutfchars (ENV, strlocation, 0 );

Const Char* Bundlebase = (* env)->Getstringutfchars(ENV, strbundlebase, 0 );

_ Android_log_write (android_log_info, "JNI device number", DeviceID );

_ Android_log_write (android_log_info, "JNI data location", location );

_ Android_log_write (android_log_info, "JNI data is located in", bundlebase );

// Generate some paths

Const Char* Svalid = my_strcat (location, DeviceID );

Const Char* Sindex = my_strcat (location, "_ alllayers /"),

My_strcat (bundlebase ,".Bundly"));

Const Char* Stile = my_strcat (location, "_ alllayers /"),

My_strcat (bundlebase, ". Bundle "));

// The device ID needs to connect a secret string

Const Char* Security = "-wuyf_qwert ";

Const Char* S = my_strcat (DeviceID, security );

// Generate the MD5 check value. All MD5 results are in lower case.

StructMd5context md5c;

Md5init (& md5c );

Md5update (& md5c, S, strlen (s ));

Unsigned CharSs [16];

Md5final (SS, & md5c );

// Check whether MD5 verification is met. If not, return immediately without further processing.

IntValid = 0;

File * fvalid;

If(Fvalid = fopen (svalid ,"RB"))! = NULL ){

CharSTR [32];

Fread (STR, 32, 1, fvalid );

IntI;

IntHaserror = 0;

For(I = 0; I

Unsigned IntS1 = ss [I];

IntS2 = STR [2 * I];

If(S2> = 48 & S2

S2-= 48;

Else If(S2> = 97 & S2

S2-= 87;

IntS3 = STR [2 * I + 1];

If(S3> = 48 & S3

S3-= 48;

Else If(S3> = 97 & S3

S3-= 87;

If(S1! = 16 * S2 + S3 ){

Haserror = 1;

Break;

}

}

If(Haserror = 0 ){

Valid = 1;

}

}

Fclose (fvalid );

If(Valid = 1 ){

_ Android_log_write (android_log_info, "JNI", "device identity verification passed ");

// Check that the slice is correct and start obtaining the slice

IntRgroup = 128*(Row/128 );

IntCgroup = 128*(COL/128 );

IntIndex = 128 * (Col-cgroup) + (Row-rgroup );

_ Android_log_write (android_log_info, "JNI reads encrypted indexes", sindex );

File * findex;

LongOffset =-1;

If(Findex = fopen (sindex ,"RB"))! = NULL ){

Fseek (findex, 16 + 5 * index, seek_set );

CharBuffer [5];

Fread (buffer, 5, 1, findex );

IntI;

For(I = 0; I

If(Buffer [I] = 3 ){

Buffer [I] = 37;

}Else If(Buffer [I] = 37 ){

Buffer [I] = 3;

}

}

Offset = (Long) (Buffer [0] & 0xff) + (Long) (Buffer [1] & 0xff)

* 256 + (Long) (Buffer [2] & 0xff) * 65536

+ (Long) (Buffer [3] & 0xff) * 16777216 + (Long) (Buffer [4]

& 0xff) * 4294967296;

}

Fclose (findex );

_ Android_log_write (android_log_info, "JNI starts to read data", stile );

File * ftile;

If(Ftile = fopen (STILE ,"RB"))! = NULL ){

Fseek (ftile, offset, seek_set );

CharLengthbytes [4];

Fread (lengthbytes, 4, 1, ftile );

IntLength = (Int) (Lengthbytes [0] & 0xff) + (Int) (Lengthbytes [1]

& 0xff) * 256 + (Int) (Lengthbytes [2] & 0xff) * 65536

+ (Int) (Lengthbytes [3] & 0xff) * 16777216;

Char* Tile = malloc (Sizeof(Char) * Length );

Fread (tile, length, 1, ftile );

_ Android_log_write (android_log_info, "JNI", "data retrieved ");

Result = (* env)-> newbytearray (ENV, length );

(* Env)-> setbytearrayregion (ENV, result, 0, length, tile );

Free (tile );

}

Fclose (ftile );

}

Free ((Void*) S );

Free ((Void*) Svalid );

Free ((Void*) Sindex );

Free ((Void*) Stile );

ReturnResult;

}

The highlighted two sections in the above Code correspond to the key of device verification and data decryption respectively. We can see that this corresponds to the previous algorithm. Of course, this algorithm is only available to data publishers.

In the android program, you only need to call a Java method to obtain map data:

Result = JNI. getencrypttile (DeviceID, location, bundlebase, level, row, col );

Now, even if the DEX file in the android program is decompiled, you cannot know the actual algorithm called in the dynamic link library behind the code.

The following describes how to encrypt the ArcGIS offline map on Android:

Figure 2 Effect of encrypted offline map displayed on Android

Appendix: Steps for JNI development on Android to prepare the development environment

1. Download and install cygwin: http://cygwin.com/setup.exe. when installing cygwin, select the development tool package and VIM (used to edit environment variables ).

2. Download Android ndk. I am using R5: http://dl.google.com/android/ndk/android-ndk-r5-windows.zip, and unzip it to zookeeper.

Create a Java class

Create a new Java class in the android project. Pay attention to the "native" mark:

PackageCom. ESRI. wuyf;

Public ClassJNI {

Public Native Byte[] Getencrypttile (string DeviceID, string location, string bundlebase,IntLevel,IntRow,IntCOL );

}

Use Java tools to generate JNI header files

Run the command line in the bin directory of the android project:

Microsoft Windows [version 6.1.7600]

Copyright (c) 2009 Microsoft Corporation. All rights reserved.

D:/wuyf/workspace/Android/agsencrypttiles/bin> javah-JNI com. ESRI. wuyf. JNI

After successful execution, a com_esri_wuyf_jni.h file is generated. Now, create a "JNI" folder under the root directory of the android project and copy the generated C header file to this directory:

/* Do not edit this file-it is machine generated */

# Include

/* Header for class com_esri_wuyf_jni */

# Ifndef_ Included_com_esri_wuyf_jni

# Define_ Included_com_esri_wuyf_jni

# Ifdef_ Cplusplus

Extern"C "{

# Endif

/*

* Class: com_esri_wuyf_jni

* Method: getencrypttile

* Signature :(Ljava/Lang/String; iii) [B

*/

Jniexport jbytearrayJnicallJava_com_esri_wuyf_jni_getencrypttile

(Jnienv *, jobject, jstring, jint );

# Ifdef_ Cplusplus

}

# Endif

# Endif

How to Implement JNI

Create a com_esri_wuyf_jni.c file under the "JNI" directory of the android project and implement the functions in the header file:

# Include"Com_esri_wuyf_jni.h"

# Include"Md5.h"

Jniexport jbytearrayJnicallJava_com_esri_wuyf_jni_getencrypttile(Jnienv * ENV,

Jobject OBJ, jstring strdeviceid, jstring strlocation,

Jstring strbundlebase, jint level, jint row, jint col ){

......

ReturnResult;

}

Create a makefile for Android

Create an android. mk file in the "JNI" Directory, which is the makefile of Android:

Local_path: = $ (call my-DIR)

Include $ (clear_vars)

Local_src_files: = com_esri_wuyf_jni.c md5.c

Local_c_includes: = $ (jni_h_include)

Local_ldlibs: =-llog

Local_prelink_module: = false

Local_module: = JNI

Include $ (build_shared_library)

Compile the JNI Link Library

From the Start Menu, enter cygwin bash shell, first in the current user's. add a $ ndk environment variable to bash_profile (pointing to the decompressed directory of Android ndk), so that we can compile Android JNI code more conveniently:

$ VI ~ /. Bash_profile

Export ndk =/cygdrive/D/software/develop/Android-ndk-Windows

In cygwin bash shell, enter the android project directory (/cygdrive/D indicates the D disk in Windows) and run the ndk compilation command:

This libjni. so will be generated in the libs/armeabi directory of the android project. Note that this link library will not be automatically updated to the Android device during debugging. Therefore, once this link library is re-compiled, you need to manually push to the corresponding directory of the device (here is/data/COM. ESRI. wuyf/LIB:

Call the JNI function in Java code

Load the JNI library statically in the Java class using the JNI function, create a JNI object, and call the corresponding method:

Static{

System.Loadlibrary("JNI ");

}

JNI =NewJNI ();

Result = JNI. getencrypttile (DeviceID, location, bundlebase, level, row, col );

Push offline data to devices

In development, you also need to batch push offline data to devices. This requires the android ADB tool:

D:/software/develop/Android-SDK-Windows/platform-tools> ADB push D:/temp/sdcard

This means to push all content under D:/temp to the device's SD card. Note that this temp directory does not appear on the SD card.

In addition, if you want to delete files in batches from the SD card, you must enter shell to execute the Linux RM command:

> ADB remount

> ADB Shell

# Rm-r/sdcard/xxx

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.