Menu Home

Android:Get Certificate SHA1 with JNI

#include <assert.h>
#include <string.h>
#include <stdio.h> 
#include <android/log.h>

const char HexCode[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

static void byte_array_to_hex_string(JNIEnv *env, const jbyteArray array, const jsize array_size, char *hex_string) {
    jbyte *sha1 = (*env)->GetByteArrayElements(env, array, NULL);

    for (int i = 0; i < array_size; i++) {
       hex_string[i * 2] = HexCode[((unsigned char)sha1[i]) / 16];
       hex_string[i * 2 + 1] = HexCode[((unsigned char)sha1[i]) % 16];
    }
    hex_string[array_size * 2] = '\0';
}

static jstring get_safe_code(JNIEnv *env, jobject thiz, jobject app_context) {
    jmethodID method_ID = NULL;

    jclass native_clazz = (*env)->GetObjectClass(env, app_context);
    method_ID = (*env)->GetMethodID(env, native_clazz, "getPackageName", "()Ljava/lang/String;");
    // Get Application package name
    jstring package_name = (*env)->CallObjectMethod(env, app_context, method_ID);

    method_ID = (*env)->GetMethodID(env, native_clazz, "getPackageManager", 
                                                "()Landroid/content/pm/PackageManager;");

    jobject package_manager = (*env)->CallObjectMethod(env, app_context, method_ID);
    jclass package_manager_class = (*env)->GetObjectClass(env, package_manager);
    
    method_ID = (*env)->GetMethodID(env, package_manager_class, "getPackageInfo", 
                                                     "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    jobject package_info_obj = (*env)->CallObjectMethod(env, package_manager, method_ID,
                                                    package_name, 64); // GET_RESOLVED_FILTER = 64
    
    jclass package_info_class = (*env)->GetObjectClass(env, package_info_obj);
    jfieldID signatures_fieldID = (*env)->GetFieldID(env, package_info_class, 
                                              "signatures", "[Landroid/content/pm/Signature;");

    jobjectArray signatures_obj_array = (*env)->GetObjectField(env, package_info_obj, signatures_fieldID);
    if (NULL == signatures_obj_array) {
        ALOGE("Signature[] is NULL, SET SAFE CODE NULL!");
        return NULL;        
    }

    // Get signature
    jobject signature_obj = (*env)->GetObjectArrayElement(env, signatures_obj_array, 0);
    jclass signature_class = (*env)->GetObjectClass(env, signature_obj);
    method_ID = (*env)->GetMethodID(env, signature_class, "toByteArray", "()[B");
    jbyteArray signature_byte_array = (jbyteArray)((*env)->CallObjectMethod(env, signature_obj, method_ID));
    
    // new ByteArrayInputStream()
    jclass byte_array_input_stream_class = (*env)->FindClass(env, "java/io/ByteArrayInputStream");
    method_ID = (*env)->GetMethodID(env, byte_array_input_stream_class, "<init>", "([B)V");
    jobject byte_array_input_stream_obj = (*env)->NewObject(env, byte_array_input_stream_class,  method_ID, signature_byte_array);

    // CertificateFactory.getInstance("X.509"); 
    jclass certificate_factory_class = (*env)->FindClass(env, "java/security/cert/CertificateFactory");
    method_ID = (*env)->GetStaticMethodID(env, certificate_factory_class,
                                                              "getInstance","(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;");
    jstring x_509_jstring = (*env)->NewStringUTF(env, "X.509");
    jobject certificate_factory_obj = (*env)->CallStaticObjectMethod(env, certificate_factory_class, method_ID, x_509_jstring);

    // certificate_factory_obj.generateCertificate();
    method_ID = (*env)->GetMethodID(env, certificate_factory_class,  "generateCertificate",
                                                                 "(Ljava/io/InputStream;)Ljava/security/cert/Certificate;");
    jobject x509_cert_obj = (*env)->CallObjectMethod(env, certificate_factory_obj, method_ID, byte_array_input_stream_obj);

    // x509_cert_obj.getEncoded()
    jclass x509_cert_calss = (*env)->GetObjectClass(env, x509_cert_obj);
    method_ID = (*env)->GetMethodID(env, x509_cert_calss, "getEncoded", "()[B");
    jbyteArray cert_byte_array = (jbyteArray)((*env)->CallObjectMethod(env, x509_cert_obj, method_ID));

    // MessageDigest.getInstance("SHA1")   
    jclass message_digest_class = (*env)->FindClass(env, "java/security/MessageDigest");
    method_ID = (*env)->GetStaticMethodID(env, message_digest_class,"getInstance","(Ljava/lang/String;)Ljava/security/MessageDigest;");
    jstring sha1_jstring = (*env)->NewStringUTF(env, "SHA1");
    jobject sha1_digest_obj = (*env)->CallStaticObjectMethod(env, message_digest_class, method_ID, sha1_jstring);

    // sha1.digest() 
    method_ID = (*env)->GetMethodID(env, message_digest_class, "digest", "([B)[B");
    jbyteArray sha1_byte_array = (jbyteArray)((*env)->CallObjectMethod(env, sha1_digest_obj, method_ID, cert_byte_array));
    
    // convert to HEX string
    jsize sha1_array_size = (*env)->GetArrayLength(env, sha1_byte_array);
    // ****** CAUTION: memory malloc ******
    char *sha1_hex_string = (char*)malloc(sha1_array_size * 2 + 1);       
    if (NULL == sha1_hex_string) {                                   
         ALOGE("MALLOC MEMORY ERROR, SET SAFE CODE NULL !!!");                   
         return NULL;                                             
     }                                                           
    memset(sha1_hex_string, 0x0, sha1_array_size * 2 + 1);      

    byte_array_to_hex_string(env, sha1_byte_array, sha1_array_size, sha1_hex_string);
   
    ALOGI("SHA1 HEX STRING: %s\n", sha1_hex_string);

    // Now we get application package name and certificate SHA1 
    char safe_code[SAFE_CODE_LEN];
    sprintf(safe_code, "%s",  sha1_hex_string);    
    free(sha1_hex_string);
    sha1_hex_string = NULL;

    ALOGI("SAFE CODE: %s ", safe_code);

    return (*env)->NewStringUTF(env, safe_code);
}

Categories: android应用 android构建工具

Tagged as:

lnmcc

Leave a Reply

Your email address will not be published.