NDK開發(五) :JNI實現文件加解密

轉載請以連接形式標明出處: 本文出自:103style的博客html

本文操做以 Android Studio 3.4.2 版本爲例android


NDK開發文章彙總git

咱們app作網絡請求的時候通常都會添加校驗位,校驗位的加密方法能夠經過jni實現,提供安全係數。github


目錄

  • 編寫測試代碼
  • 實現建立文件邏輯
  • 實現JNI加密邏輯
  • 實現JNI解密邏輯
  • 執行測試代碼

編寫測試代碼

  • 建立Encryptor類,編寫對應的測試代碼:
    public class Encryptor {
        private static final String TAG = "Encryptor";
        static {
            System.loadLibrary("encryptor");
        }
        private final String BASE_URL = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
        /**
         * 加密
         *
         * @param normalPath  文件路徑
         * @param encryptPath 加密以後的文件路徑
         */
        public native static void encryption(String normalPath, String encryptPath);
        /**
         * 解密
         *
         * @param encryptPath 加密以後的文件路徑
         * @param decryptPath 解密以後的文件路徑
         */
        public native static void decryption(String encryptPath, String decryptPath);
        /**
         * 建立文件
         *
         * @param normalPath 文件路徑
         */
        private native void createFile(String normalPath);
        /**
         * 測試加解密
         */
        public void test() {
            String fileName = "testJni.txt";
            String encryptPath = encryption(fileName);
            decryption(encryptPath);
        }
        /**
         * 加密
         */
        public String encryption(String fileName) {
            String normalPath = BASE_URL + fileName;
            File file = new File(normalPath);
            if (!file.exists()) {
                createFile(normalPath);
            }
            String encryptPath = BASE_URL + "encryption_" + fileName;
            Encryptor.encryption(normalPath, encryptPath);
            Log.d(TAG, "加密完成了...");
            return encryptPath;
        }
        /**
         * 解密
         */
        public void decryption(String encryptPath) {
            if (!new File(encryptPath).exists()) {
                Log.d(TAG, "解密文件不存在");
                return;
            }
            String decryptPath = encryptPath.replace("encryption_", "decryption_");
            Encryptor.decryption(encryptPath, decryptPath);
            Log.d(TAG, "解密完成了...");
        }
    }
    複製代碼
  • 建立encryptor.cpp
  • 添加如下代碼到CMakeLists.txt
    add_library(encryptor
            SHARED
            src/main/cpp/encryptor.cpp)
    target_link_libraries(
            encryptor
            ${log-lib})
    複製代碼

實現建立文件邏輯

fopen()函數介紹安全

#include <cstdio>

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Encryptor_createFile(JNIEnv *env, jobject instance,
                                                    jstring normalPath_) {
    //獲取字符串保存在JVM中內存中
    const char *normalPath = env->GetStringUTFChars(normalPath_, nullptr);
    //打開 normalPath  wb:只寫打開或新建一個二進制文件;只容許寫數據
    FILE *fp = fopen(normalPath, "wb");

    //把字符串寫入到指定的流 stream 中,但不包括空字符。
    fputs("Hi, this file is created by JNI, and my name is 103style.", fp);

    //關閉流 fp。刷新全部的緩衝區
    fclose(fp);
    //釋放JVM保存的字符串的內存
    env->ReleaseStringUTFChars(normalPath_, normalPath);
}
複製代碼

實現JNI加密邏輯

#include <android/log.h>
#include <cstdio>
#include <cstring>

#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"Encryptor",FORMAT,##__VA_ARGS__);

char password[] = "103style";

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Encryptor_encryption(JNIEnv *env, jclass type, jstring normalPath_,
                                                    jstring encryptPath_) {
    //獲取字符串保存在JVM中內存中
    const char *normalPath = env->GetStringUTFChars(normalPath_, nullptr);
    const char *encryptPath = env->GetStringUTFChars(encryptPath_, nullptr);

    LOGE("normalPath = %s, encryptPath = %s", normalPath, encryptPath);

    //rb:只讀打開一個二進制文件,容許讀數據。
    //wb:只寫打開或新建一個二進制文件;只容許寫數據
    FILE *normal_fp = fopen(normalPath, "rb");
    FILE *encrypt_fp = fopen(encryptPath, "wb");

    if (normal_fp == nullptr) {
        LOGE("%s", "文件打開失敗");
        return;
    }

    //一次讀取一個字符
    int ch = 0;
    int i = 0;
    size_t pwd_length = strlen(password);
    while ((ch = fgetc(normal_fp)) != EOF) { //End of File
        //寫入(異或運算)
        fputc(ch ^ password[i % pwd_length], encrypt_fp);
        i++;
    }

    //關閉流 normal_fp和encrypt_fp。刷新全部的緩衝區
    fclose(normal_fp);
    fclose(encrypt_fp);

    //釋放JVM保存的字符串的內存
    env->ReleaseStringUTFChars(normalPath_, normalPath);
    env->ReleaseStringUTFChars(encryptPath_, encryptPath);
}
複製代碼

實現JNI解密邏輯

#include <android/log.h>
#include <cstdio>
#include <cstring>

#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"Encryptor",FORMAT,##__VA_ARGS__);

char password[] = "103style";

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_Encryptor_decryption(JNIEnv *env, jclass type, jstring encryptPath_,
                                                    jstring decryptPath_) {
    ////獲取字符串保存在JVM中內存中
    const char *encryptPath = env->GetStringUTFChars(encryptPath_, nullptr);
    const char *decryptPath = env->GetStringUTFChars(decryptPath_, nullptr);

    LOGE("encryptPath = %s, decryptPath = %s", encryptPath, decryptPath);

    //rb:只讀打開一個二進制文件,容許讀數據。
    //wb:只寫打開或新建一個二進制文件;只容許寫數據
    FILE *encrypt_fp = fopen(encryptPath, "rb");
    FILE *decrypt_fp = fopen(decryptPath, "wb");

    if (encrypt_fp == nullptr) {
        LOGE("%s", "加密文件打開失敗");
        return;
    }

    int ch;
    int i = 0;
    size_t pwd_length = strlen(password);
    while ((ch = fgetc(encrypt_fp)) != EOF) {
        fputc(ch ^ password[i % pwd_length], decrypt_fp);
        i++;
    }

    //關閉流 encrypt_fp 和 decrypt_fp。刷新全部的緩衝區
    fclose(encrypt_fp);
    fclose(decrypt_fp);

    //釋放JVM保存的字符串的內存
    env->ReleaseStringUTFChars(encryptPath_, encryptPath);
    env->ReleaseStringUTFChars(decryptPath_, decryptPath);
}
複製代碼

執行測試代碼

private void testEncryptor() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x1024);
            return;
        }
    }
    new Encryptor().test();
}
複製代碼

執行程序會在 手機根目錄 生成如下三個文件:bash

  • testJni.txt:原文件
  • encryption_testJni.txt:加密以後的文件
  • decryption_testJni.txt:解密以後的文件

demo地址: https://github.com/103style/NDKDoc/tree/master/HelloNDK網絡

若是以爲不錯的話,請幫忙點個讚唄。app

以上函數


掃描下面的二維碼,關注個人公衆號 Android1024, 點關注,不迷路。 測試

Android1024
相關文章
相關標籤/搜索