加密ArcGIS离线地图及其在Android上的实现(2)

离线地图的加密

考虑性能的影响,对离线地图的加密需要使用尽可能简单的加密方法,因此,这里使用对离线地图的索引文件进行加密的方法。对于原始的索引数据文件,我们只需要对若干字节进行交换即可,用户可以根据需要改变自己的加密方法,同样,这个加密方法只有数据的发布者才知道:

static public void encrypt(String inPath, String outPath) {

FileInputStream in = null;

FileOutputStream out = null;

try {

File inFile = new File(inPath);

File outFile = new File(outPath);

in = new FileInputStream(inFile);

out = new FileOutputStream(outFile, false);

int read;

read = in.read();

int count = 0;

while (read != -1) {

byte b = (byte) read;

// 此处可以增加置换对数以增加文件的复杂度

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) {}

}

}

在设备上读取加密的离线地图

设备上读取加密的离线地图分为2步:校验设备的身份和获取加密的数据,这两步都必须封装在动态连接库中确保算法的保密。在Android上,需要通过JNI实现,我们可以把这两步都封装在一个C函数中:

JNIEXPORT jbyteArray JNICALL Java_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 设备编号", deviceId);

__android_log_write(ANDROID_LOG_INFO, "JNI 数据位置", location);

__android_log_write(ANDROID_LOG_INFO, "JNI 数据位于", bundleBase);

// 生成一些路径

const char* sValid = my_strcat(location, deviceId);

const char* sIndex = my_strcat(my_strcat(location, "_alllayers/"),

my_strcat(bundleBase, ".bundly"));

const char* sTile = my_strcat(my_strcat(location, "_alllayers/"),

my_strcat(bundleBase, ".bundle"));

// 设备标识需要连接一个秘密的字符串

const char* security = "-wuyf_qwert";

const char* s = my_strcat(deviceId, security);

// 生成MD5校验值,MD5结果全部使用小写

struct MD5Context md5c;

MD5Init(&md5c);

MD5Update(&md5c, s, strlen(s));

unsigned char ss[16];

MD5Final(ss, &md5c);

// 检查MD5校验是不是满足,如果不满足则立即返回,不进行后续处理

int valid = 0;

FILE* fValid;

if ((fValid = fopen(sValid, "rb")) != NULL) {

char str[32];

fread(str, 32, 1, fValid);

int i;

int hasError = 0;

for (i = 0; i < 16; i++) {

unsigned int s1 = ss[i];

int s2 = str[2 * i];

if (s2 >= 48 && s2 <= 57)

s2 -= 48;

else if (s2 >= 97 && s2 <= 102)

s2 -= 87;

int s3 = str[2 * i + 1];

if (s3 >= 48 && s3 <= 57)

s3 -= 48;

else if (s3 >= 97 && s3 <= 102)

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", "设备身份校验通过");

// 校验无误,开始获取切片

int rGroup = 128 * (row / 128);

int cGroup = 128 * (col / 128);

int index = 128 * (col - cGroup) + (row - rGroup);

__android_log_write(ANDROID_LOG_INFO, "JNI 开始读取加密索引", sIndex);

FILE* fIndex;

long offset = -1;

if ((fIndex = fopen(sIndex, "rb")) != NULL) {

fseek(fIndex, 16 + 5 * index, SEEK_SET);

char buffer[5];

fread(buffer, 5, 1, fIndex);

int i;

for (i = 0; i < 5; 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 开始读取数据", sTile);

FILE* fTile;

if ((fTile = fopen(sTile, "rb")) != NULL) {

fseek(fTile, offset, SEEK_SET);

char lengthBytes[4];

fread(lengthBytes, 4, 1, fTile);

int length = (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", "获取数据成功");

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);

return result;

}

上述代码中高亮的2段分别对应了校验设备和解密数据的关键,可以看到这和前面的算法是可以对应起来的,当然,这个算法只有数据的发布者掌握。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pxxyz.html