Last active
January 21, 2021 17:08
-
-
Save i-sync/2dc65b8acacfc3a99080b22ef5c877ba to your computer and use it in GitHub Desktop.
iHuman Android application API signature parameter algorithm - ihuman.apk.2.0.1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.ihuman.hpfutility.net.d; | |
| import android.text.TextUtils; | |
| import android.util.Pair; | |
| import cn.jiguang.net.HttpUtils; | |
| import com.google.devtools.build.android.desugar.runtime.ThrowableExtension; | |
| import com.google.gson.Gson; | |
| import com.google.gson.GsonBuilder; | |
| import com.google.gson.annotations.Expose; | |
| import com.google.gson.annotations.SerializedName; | |
| import com.huawei.hms.support.api.entity.pay.HwPayConstant; | |
| import com.ihuman.hpfutility.net.e.b; | |
| import com.ihuman.hpfutility.net.entry.ExcludeParamIfEmpty; | |
| import com.ihuman.hpfutility.net.entry.SignId; | |
| import com.ihuman.hpfutility.net.entry.SignParam; | |
| import java.lang.reflect.Field; | |
| import java.lang.reflect.Type; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import java.util.Comparator; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import org.json.JSONObject; | |
| public abstract class c<T> extends a<T> { | |
| private static final Gson BZ = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization().create(); | |
| @SerializedName("platform") | |
| @Expose | |
| private String Ca = "Android"; | |
| @SignId(2) | |
| @SerializedName("deviceid") | |
| @Expose | |
| @ExcludeParamIfEmpty | |
| private String Cb; | |
| @SignId(8) | |
| @SerializedName("timestamp") | |
| @Expose | |
| @ExcludeParamIfEmpty | |
| private long time; | |
| @SignId(16) | |
| @SerializedName("token") | |
| @Expose | |
| @ExcludeParamIfEmpty | |
| private String token; | |
| @SignId(1) | |
| @SerializedName("uid") | |
| @Expose | |
| @ExcludeParamIfEmpty | |
| private String userId; | |
| private static class a implements Comparator<Pair<String, ? extends Object>> { | |
| private a() { | |
| } | |
| /* renamed from: a */ | |
| public int compare(Pair<String, ? extends Object> pair, Pair<String, ? extends Object> pair2) { | |
| return ((String) pair.first).compareToIgnoreCase((String) pair2.first); | |
| } | |
| } | |
| private String b(List<Pair<String, ? extends Object>> list, boolean z) { | |
| Collections.sort(list, new a()); | |
| StringBuilder sb = new StringBuilder(); | |
| int size = list.size(); | |
| for (int i = 0; i < size; i++) { | |
| Pair pair = (Pair) list.get(i); | |
| if (i != 0) { | |
| sb.append(HttpUtils.PARAMETERS_SEPARATOR); | |
| } | |
| sb.append((String) pair.first).append(HttpUtils.EQUAL_SIGN).append(z ? com.ihuman.hpfutility.common.b.a.URLEncode(pair.second.toString()) : pair.second); | |
| } | |
| return sb.toString(); | |
| } | |
| public com.ihuman.hpfutility.net.e.a<T> a(b bVar) { | |
| byte[] ig = bVar.ig(); | |
| if (bVar.ig() == null) { | |
| return null; | |
| } | |
| try { | |
| JSONObject jSONObject = new JSONObject(new String(ig)); | |
| int optInt = jSONObject.optInt("code", -1); | |
| return (optInt == 0 || optInt == 2000) ? new com.ihuman.hpfutility.net.e.a<>(an(jSONObject.optString("result", "")), optInt) : new com.ihuman.hpfutility.net.e.a<>(optInt, jSONObject.optString("message", "")); | |
| } catch (Exception e) { | |
| return new com.ihuman.hpfutility.net.e.a<>(-1, e.getMessage()); | |
| } | |
| } | |
| public void am(String str) { | |
| this.Cb = str; | |
| } | |
| /* access modifiers changed from: protected */ | |
| public T an(String str) { | |
| Class cls = m1if(); | |
| Type ie = ie(); | |
| if (cls != null) { | |
| return BZ.fromJson(str, cls); | |
| } | |
| if (ie != null) { | |
| return BZ.fromJson(str, ie); | |
| } | |
| return null; | |
| } | |
| public HashMap<String, String> hZ() { | |
| return null; | |
| } | |
| public HashMap<String, String> ia() { | |
| Field[] declaredFields; | |
| Pair pair; | |
| HashMap<String, String> hashMap = new HashMap<>(); | |
| int id = id(); | |
| ArrayList arrayList = new ArrayList(); | |
| ArrayList<Pair> arrayList2 = new ArrayList<>(); | |
| Class cls = getClass(); | |
| while (true) { | |
| Class cls2 = cls; | |
| for (Field field : cls2.getDeclaredFields()) { | |
| if (((Expose) field.getAnnotation(Expose.class)) != null) { | |
| SignId signId = (SignId) field.getAnnotation(SignId.class); | |
| SignParam signParam = (SignParam) field.getAnnotation(SignParam.class); | |
| boolean z = !(signId == null || (signId.value() & id) == 0) || (signParam != null && signParam.hV()); | |
| field.getType().getName(); | |
| SerializedName serializedName = (SerializedName) field.getAnnotation(SerializedName.class); | |
| String str = serializedName != null ? serializedName.value() : field.getName(); | |
| field.setAccessible(true); | |
| try { | |
| if (((ExcludeParamIfEmpty) field.getAnnotation(ExcludeParamIfEmpty.class)) == null) { | |
| pair = new Pair(str, field.get(this)); | |
| } else { | |
| Object obj = field.get(this); | |
| boolean z2 = true; | |
| if (obj == null) { | |
| z2 = false; | |
| } else if (obj instanceof Number) { | |
| z2 = ((Number) obj).longValue() != 0; | |
| } else if (obj instanceof String) { | |
| z2 = !TextUtils.isEmpty((String) obj); | |
| } | |
| if (z2) { | |
| pair = new Pair(str, obj); | |
| } | |
| pair = null; | |
| } | |
| } catch (IllegalAccessException e) { | |
| ThrowableExtension.printStackTrace(e); | |
| } | |
| if (pair != null) { | |
| arrayList2.add(pair); | |
| if (z) { | |
| arrayList.add(pair); | |
| } | |
| } | |
| } | |
| } | |
| cls = cls2.getSuperclass(); | |
| if (cls == null) { | |
| break; | |
| } | |
| } | |
| for (Pair pair2 : arrayList2) { | |
| hashMap.put(pair2.first, pair2.second == null ? "" : pair2.second.toString()); | |
| } | |
| String ao = com.ihuman.hpfutility.net.f.a.ao(b(arrayList, false)); | |
| if (ao == null) { | |
| throw new IllegalArgumentException("Sign data error !"); | |
| } | |
| hashMap.put(HwPayConstant.KEY_SIGN, ao); | |
| return hashMap; | |
| } | |
| public int ib() { | |
| return 1; | |
| } | |
| public int id() { | |
| return 27; | |
| } | |
| /* access modifiers changed from: protected */ | |
| public Type ie() { | |
| return null; | |
| } | |
| /* access modifiers changed from: protected */ | |
| /* renamed from: if reason: not valid java name */ | |
| public abstract Class<T> m1if(); | |
| public void setTime(long j) { | |
| this.time = j; | |
| } | |
| public void setToken(String str) { | |
| this.token = str; | |
| } | |
| public void setUserId(String str) { | |
| this.userId = str; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.ihuman.hpfutility.net.f; | |
| import com.google.devtools.build.android.desugar.runtime.ThrowableExtension; | |
| import com.umeng.analytics.pro.dm; | |
| import java.security.MessageDigest; | |
| import java.security.NoSuchAlgorithmException; | |
| public class a { | |
| private static final char[] Cd = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; | |
| public static String ao(String str) { | |
| String ap = ap(str); | |
| if (ap != null) { | |
| return aq(ap); | |
| } | |
| return null; | |
| } | |
| public static String ap(String str) { | |
| byte[] digest; | |
| try { | |
| byte[] bytes = str.getBytes(); | |
| MessageDigest instance = MessageDigest.getInstance("MD5"); | |
| instance.update(bytes); | |
| char[] cArr = new char[(r4 * 2)]; | |
| int i = 0; | |
| for (byte b : instance.digest()) { | |
| int i2 = i + 1; | |
| cArr[i] = (char) Cd[(b >>> 4) & 15]; | |
| i = i2 + 1; | |
| cArr[i2] = (char) Cd[b & dm.m]; | |
| } | |
| return new String(cArr); | |
| } catch (Exception e) { | |
| ThrowableExtension.printStackTrace(e); | |
| return null; | |
| } | |
| } | |
| public static String aq(String str) { | |
| return k(str, "SHA-256"); | |
| } | |
| private static String k(String str, String str2) { | |
| if (str == null || str.length() <= 0) { | |
| return null; | |
| } | |
| try { | |
| MessageDigest instance = MessageDigest.getInstance(str2); | |
| instance.update(str.getBytes()); | |
| byte[] digest = instance.digest(); | |
| StringBuffer stringBuffer = new StringBuffer(); | |
| for (byte b : digest) { | |
| String hexString = Integer.toHexString(b & 255); | |
| if (hexString.length() == 1) { | |
| stringBuffer.append('0'); | |
| } | |
| stringBuffer.append(hexString); | |
| } | |
| return stringBuffer.toString(); | |
| } catch (NoSuchAlgorithmException e) { | |
| ThrowableExtension.printStackTrace(e); | |
| return null; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # _*_ coding: utf-8 _*_ | |
| import json | |
| import os | |
| import time | |
| import re | |
| import sys, getopt | |
| import hashlib | |
| import requests | |
| import random | |
| from collections import OrderedDict | |
| #无符号右移 | |
| import ctypes | |
| def int_overflow(val): | |
| maxint = 2147483647 | |
| if not -maxint-1 <= val <= maxint: | |
| val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1 | |
| return val | |
| def unsigned_right_shitf(n,i): | |
| # 数字小于0,则转为32位无符号uint | |
| if n<0: | |
| n = ctypes.c_uint32(n).value | |
| # 正常位移位数是为正数,但是为了兼容js之类的,负数就右移变成左移好了 | |
| if i<0: | |
| return -int_overflow(n << abs(i)) | |
| #print(n) | |
| return int_overflow(n >> i) | |
| def get_sign(data): | |
| src = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'] | |
| ordered_data = OrderedDict(sorted(data.items())) | |
| ordered_data_str = '&'.join([f"{k}={ordered_data[k]}" for k in ordered_data.keys()]) | |
| print(ordered_data_str) | |
| digest = hashlib.md5(f'{ordered_data_str}'.encode('utf-8')).digest() | |
| r = [] | |
| for d in digest: | |
| i = unsigned_right_shitf(d, 4) & 15 | |
| r.append(src[i]) | |
| r.append(src[d & 15]) | |
| m5 = ''.join(r) | |
| print(m5) | |
| s256 = str(hashlib.sha256(m5.encode('utf-8')).hexdigest()) | |
| return s256 | |
| if __name__ == "__main__": | |
| ''' | |
| key: id value, | |
| 2.0.1 : id=27, sign params [uid, deviceid, token, timestamp] for checkin request | |
| 4.1.0 : id=10, sign params [deviceid, timestamp] for most post request. album,... | |
| & opeator | |
| signid |param |27 |10 | |
| 1 |uid |1 |0 | |
| 2 |deviceid |2 |2 | |
| 8 |timestamp |8 |8 | |
| 16 |token |16 |0 | |
| ''' | |
| param = { | |
| 'uid': 'userid', | |
| #'app_version': '4.1.0', | |
| #'device': 'phone', | |
| 'deviceid': 'deviceid', | |
| #'platform': 'Android', | |
| 'token': 'token', | |
| 'timestamp': 'timestamp' | |
| } | |
| new_sign = get_sign(param) | |
| print(new_sign) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment