1

I am trying to generate token at run time using sign certificate and verify that token on server to access any resources. I don't want to store token in XML file because it is available after reverse engineering of APK

Code for generating token is

public String getToken() {
    Signature[] sigs;
    try {
        sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;

        String token = sigs[0].toCharsString();
        return token;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

Issue is some device return different token even apk is generated from the same certificate, don't know the reason why it is returning different token for some devices.

All i want is generate a token which could be used to access web resources, and i don't want to store token in apk no one can get the token by decompiling apk.

nhoxbypass
  • 9,695
  • 11
  • 48
  • 71

3 Answers3

1

The signing certificate's fingerprint will be unique across all the devices. Would you please try this solution to get that fingerprint as String and use it as token.

https://stackoverflow.com/a/22506133/4586742

Bob
  • 13,447
  • 7
  • 35
  • 45
  • what was the issue in my code?i have added log file some device calling web service different token. – Om Infowave Developers Aug 04 '17 at 03:10
  • so it's crack able,any one can generate **fingerprint** using above logic and use that key for access resources.is they any solution for that. – Om Infowave Developers Aug 19 '17 at 07:19
  • t's also possible to generate fingerprint using some technique 'List apps = context.getPackageManager().getInstalledPackages(PackageMana‌​ger.GET_SIGNATURES);' gives all list of installed package for (Signature s : pi.signatures) { Log.d("PackageTrackerfix", "old: " + s.toCharsString() + " " + s.hashCode()); }' it return all certificate details that we are using in 'generateCertificate()' – Om Infowave Developers Aug 19 '17 at 07:24
  • Doing encryption of the fingerprint and pass encrypted value will increase the security. – Bob Aug 19 '17 at 07:24
  • i have already did,but if anyone get the fingerprint so they can also try reverse engineering on it – Om Infowave Developers Aug 19 '17 at 07:26
  • Yes. 100% security is a lie. Why do you need to generate the token at client side. Why don't you consider some standard like [OAuth 2.0](https://oauth.net/2/) for authentication which involves short-lived (1 hour) tokens. – Bob Aug 19 '17 at 07:28
  • there is again new attach on my app,they have generated fingerprint using above logic and replaced static fingerprint with fingerprint that i am generating at run time so now they are again able to access all the resources – Om Infowave Developers Aug 19 '17 at 07:28
  • for Oauth there is no login system,non user get register with app.so how to use Oauth? – Om Infowave Developers Aug 19 '17 at 07:32
  • Why do you need token if there is no user model? Btw, if you want to store a token securely, you can consider [Android keystore](https://developer.android.com/training/articles/keystore.html) – Bob Aug 19 '17 at 08:09
  • attacker have removed the ads my application,there is IAP in my app if it's subscribed user they don't see any ads for normal user there are ads,but attacker remove the condition and always pass true for subscribed user condition and upload APK with new sign certificate,that's way i have generated token using sign certificate ,if it's signed by me then only user able to get the resources. – Om Infowave Developers Aug 21 '17 at 03:27
1

you can store token with C or C++ and add signature verification

public static String getSignature(Context context) {
try {
    PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
    Signature[] signatures = packageInfo.signatures;
    return signatures[0].toCharsString();
} catch(PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}
return null;

}

const char * app_signature = "singsing";
static int is_valid = 0;
void
Java_com_xxx_xxx_nativeInit(JNIEnv *env, jobject thiz, jobject context_object){
    jclass context_class = (*env)->GetObjectClass(env, context_object);

    //context.getPackageManager()
    jmethodID methodId = (*env)->GetMethodID(env, context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
    jobject package_manager_object = (*env)->CallObjectMethod(env, context_object, methodId);
    if (package_manager_object == NULL) {
        return;
    }

    //context.getPackageName()
    methodId = (*env)->GetMethodID(env, context_class, "getPackageName", "()Ljava/lang/String;");
    jstring package_name_string = (jstring)(*env)->CallObjectMethod(env, context_object, methodId);
    if (package_name_string == NULL) {
        return ;
    }
    (*env)->DeleteLocalRef(env,context_class);

    //PackageManager.getPackageInfo(Sting, int)
    //public static final int GET_SIGNATURES= 0x00000040;
    jclass pack_manager_class = (*env)->GetObjectClass(env, package_manager_object);
    methodId = (*env)->GetMethodID(env, pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    (*env)->DeleteLocalRef(env,pack_manager_class);
    jobject package_info_object = (*env)->CallObjectMethod(env, package_manager_object, methodId, package_name_string, 0x40);
    if (package_info_object == NULL) {
        return ;
    }
    (*env)->DeleteLocalRef(env,package_manager_object);

    //PackageInfo.signatures[0]
    jclass package_info_class = (*env)->GetObjectClass(env, package_info_object);
    jfieldID fieldId = (*env)->GetFieldID(env, package_info_class, "signatures", "[Landroid/content/pm/Signature;");
    (*env)->DeleteLocalRef(env,package_info_class);
    jobjectArray signature_object_array = (jobjectArray)(*env)->GetObjectField(env,package_info_object, fieldId);
    if (signature_object_array == NULL) {
        return ;
    }
    jobject signature_object = (*env)->GetObjectArrayElement(env,signature_object_array, 0);
    (*env)->DeleteLocalRef(env,package_info_object);
    jclass signature_class = (*env)->GetObjectClass(env, signature_object); 
    methodId = (*env)->GetMethodID(env, signature_class,  "toCharsString", "()Ljava/lang/String;");
    (*env)->DeleteLocalRef(env,signature_class);
    jstring signature_jstirng = (jstring) (*env)->CallObjectMethod(env, signature_object, methodId);
    const  char *sign=(*env)->GetStringUTFChars(env, signature_jstirng,NULL); 
    if (strcmp(sign,app_signature)==0 || strcmp(sign,app_j_s)==0) {
        is_valid= 1;
    } 
    return;
}
sanemars
  • 767
  • 5
  • 18
0

@Om Infowave Developers,

I Suggest you to use a Android Keystore System to generate a KeyPair then use KeyPair to encrypt a Token, Store a token in shared preference. whenever you need a token decrypt token using KeyPair.

  1. This way you get unique token every time.
  2. Token is encrypted and secured.
  3. KeyPair is different for every device hence more secure.

Also I just notice that you are returning zero-index based key. Their might be chances that key you are looking for present in subsequent indices. Suggest you to log all key stored in Signature[] sigs;

Hope this help.

Sandy
  • 251
  • 1
  • 4
  • 10
  • @Sanday how to verify this token on server? – Om Infowave Developers Aug 08 '17 at 08:48
  • How are you currently verifying token on server? Use same way you are verifying token on server currently. only difference is you stored a token in shared preference on android device in encrypted format after its generates first time. After which pull token from shared preference decrypt token and send it to server. Let me know if you any other help. More than happy to help. – Sandy Aug 09 '17 at 06:11
  • Another way is to send device ID and token to server, store both device id and token on server. – Sandy Aug 09 '17 at 06:13