最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】Python实现小花生中addSignature的md5加密生成签名的逻辑

Python crifan 1323浏览 0评论
折腾:
【已解决】小花生app中调用接口parentChildReadingBookQuery2时timestamp和signature生成的逻辑
期间,需要把找到的java的md5参数加密的代码:
com/huili/readingclub/model/ModelSecurity.java
  public static void addSignature(RequestParams paramRequestParams, String paramString)
  {
    Object localObject = paramString;
    if (paramString.startsWith("http://www.xiaohuasheng.cn:83")) {
      localObject = paramString.substring("http://www.xiaohuasheng.cn:83".length());
    }
    if (((String)localObject).startsWith("/UserService.svc/getToken/")) {
      return;
    }
    int i;
    if (StringUtil.isNullOrEmpty(MainActivity.userId)) {
      i = 0;
    } else {
      i = Integer.parseInt(MainActivity.userId);
    }
    int j = i;
    if (i < 1) {
      j = 0;
    }
    paramString = "";
    if (j != 0) {
      paramString = getToken(MainActivity.userId);
    }
    long l = DateUtils.get1970ToNowSeconds();
    if (j == 0)
    {
      paramString = new StringBuilder();
      paramString.append(l);
      paramString.append((String)localObject);
      paramString.append(“AyGt7ohMR!xx#N");
      paramString = StringUtil.md5(paramString.toString());
    }
    else
    {
      StringBuilder localStringBuilder = new StringBuilder();
      localStringBuilder.append(MainActivity.userId);
      localStringBuilder.append(l);
      localStringBuilder.append((String)localObject);
      localStringBuilder.append(paramString);
      localStringBuilder.append(“AyGt7ohMR!xx#N");
      paramString = StringUtil.md5(localStringBuilder.toString());
    }
    if (j != 0) {
      paramRequestParams.addHeader("userId", MainActivity.userId);
    }
    localObject = new StringBuilder();
    ((StringBuilder)localObject).append(l);
    ((StringBuilder)localObject).append("");
    paramRequestParams.addHeader("timestamp", ((StringBuilder)localObject).toString());
    paramRequestParams.addHeader("signature", paramString);
  }

其中调用的代码是:
com/huili/readingclub/network/XutilsHttpClient.java
      if (paramHttpMethod == HttpRequest.HttpMethod.GET) {
        ModelSecurity.addSignature(localRequestParams, paramString1);
      } else if (paramHttpMethod == HttpRequest.HttpMethod.POST) {
        ModelSecurity.addSignature(localRequestParams, (String)JsonUtil.jsonToMap(paramString2).get("J"));
      }
想办法改造成python的。
并且,找到一组数据,供测试和验证
POST /Reading.svc/parentChildReadingBookQuery2 HTTP/1.1
Content-Type: application/json
Authorization: NSTp9~)NwSfrXp@\
userId: 1134723
timestamp: 1553845899
signature: c687d5dfa015246e6bdc6b3c27c2afea
Content-Length: 212
Host: www.xiaohuasheng.cn:83
User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; A0001 Build/KOT49H) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
Cookie: ASP.NET_SessionId=sjwpqfwt013elkehr2ytl0sq
Cookie2: $Version=1
Accept-Encoding: gzip
Connection: keep-alive


{"J":"{\"userId\":\"1134723\",\"fieldName\":\"\",\"fieldValue\":\"全部类别\",\"theStageOfTheChild\":\"\",\"parentalEnglishLevel\":\"\",\"supportingResources\":\"有音频\",\"offset\":20,\"limit\":10}","C":0}
其中有
J字段值
timestamp值
-》算出的signature是c687d5dfa015246e6bdc6b3c27c2afea
需要用Python复原此过程
然后就是想办法去写Python代码了。
除了写代码还,还要分析对应逻辑。
此处简单看了下,看来只需要关注:
      StringBuilder localStringBuilder = new StringBuilder();
      localStringBuilder.append(MainActivity.userId);
      localStringBuilder.append(l);
      localStringBuilder.append((String)localObject);
      localStringBuilder.append(paramString);
      localStringBuilder.append(“AyGt7ohMR!xx#N");
      paramString = StringUtil.md5(localStringBuilder.toString());
java substring
Java substring() 方法 | 菜鸟教程
而其中:
  • MainActivity.userId:应该就是字符串”1134723″
  • l:此处的时间戳
    • long l = DateUtils.get1970ToNowSeconds();
    • 此处直接赋值用于测试
  • localObject:
  • paramString:此处传入的J的值
  • 固定字符串:”AyGt7ohMR!xxx#N”
然后去计算出md5值
再去看看:
StringUtil.md5
com/huili/readingclub/utils/StringUtil.java
  public static String md5(String paramString)
  {
    return Const.getMD5Str(paramString);
  }
com/huili/readingclub/utils/Const.java
  public static final String getMD5Str(String paramString)
  {
    char[] arrayOfChar = new char[16];
    char[] tmp6_5 = arrayOfChar;
    tmp6_5[0] = 48;
    char[] tmp12_6 = tmp6_5;
    tmp12_6[1] = 49;
    char[] tmp18_12 = tmp12_6;
    tmp18_12[2] = 50;
    char[] tmp24_18 = tmp18_12;
    tmp24_18[3] = 51;
    char[] tmp30_24 = tmp24_18;
    tmp30_24[4] = 52;
    char[] tmp36_30 = tmp30_24;
    tmp36_30[5] = 53;
    char[] tmp42_36 = tmp36_30;
    tmp42_36[6] = 54;
    char[] tmp49_42 = tmp42_36;
    tmp49_42[7] = 55;
    char[] tmp56_49 = tmp49_42;
    tmp56_49[8] = 56;
    char[] tmp63_56 = tmp56_49;
    tmp63_56[9] = 57;
    char[] tmp70_63 = tmp63_56;
    tmp70_63[10] = 97;
    char[] tmp77_70 = tmp70_63;
    tmp77_70[11] = 98;
    char[] tmp84_77 = tmp77_70;
    tmp84_77[12] = 99;
    char[] tmp91_84 = tmp84_77;
    tmp91_84[13] = 100;
    char[] tmp98_91 = tmp91_84;
    tmp98_91[14] = 101;
    char[] tmp105_98 = tmp98_91;
    tmp105_98[15] = 102;
    tmp105_98;
    try
    {
      paramString = paramString.getBytes();
      Object localObject = MessageDigest.getInstance("MD5");
      ((MessageDigest)localObject).update(paramString);
      paramString = ((MessageDigest)localObject).digest();
      int i = paramString.length;
      localObject = new char[i * 2];
      int j = 0;
      int k = 0;
      while (j < i)
      {
        int m = paramString[j];
        int n = k + 1;
        localObject[k] = ((char)arrayOfChar[(m >> 4 & 0xF)]);
        k = n + 1;
        localObject[n] = ((char)arrayOfChar[(m & 0xF)]);
        j++;
      }
      paramString = new String((char[])localObject);
      return paramString;
    }
    catch (Exception paramString) {}
    return null;
  }
-》看起来,以及,希望是,普通的,md5加密算法
-》去找找python中的md5:
【已解决】Python中计算字符串的md5值
结果不对:
【已解决】为何Python中32字节的md值和小花生中getMD5Str计算出的md5值不同
期间去:
【已解决】小花生中如何得到getToken的计算逻辑以便得到正确的md5值可以正常请求接口
此处得到了user的token:
  • userId是:1554276832
  • 返回的token是:40d2267f-359e-4526-951a-66519e5868c3
接着再去试试模拟addSignature中的md5值生成的逻辑,看看值是否正确:
from hashlib import md5

def generateSignature(timestampInt, paramString):
    userId = "1134723"
    timestamp = "%s" % timestampInt
    # localObject = "/Reading.svc/parentChildReadingBookQuery2"
    # localObject = paramString
    userToken = "40d2267f-359e-4526-951a-66519e5868c3"
    # fixedSault = “AyGt7ohMR!xx#N"
    secretKey = “AyGt7ohMR!xx#N"

    # strToCalc = userId + timestamp + localObject + paramString + fixedSault
    # strToCalc = timestamp + localObject + fixedSault
    strToCalc = userId + timestamp + paramString + userToken + secretKey
    print("strToCalc=%s" % strToCalc)

    encodedStr = strToCalc.encode()
    # encodedStr = strToCalc.encode("UTF-8")
    # print("encodedStr=%s" % encodedStr)
    md5Result = md5(encodedStr)
    # print("md5Result=%s" % md5Result) # md5Result=<md5 HASH object @ 0x1044f1df0>

    # md5Result = md5()
    # md5Result.update(strToCalc)

    # md5Digest = md5Result.digest()
    # print("md5Digest=%s" % md5Digest) # 
    # print("len(md5Digest)=%s" % len(md5Digest))

    md5Hexdigest = md5Result.hexdigest()
    print("md5Hexdigest=%s" % md5Hexdigest)
    print("len(md5Hexdigest)=%s" % len(md5Hexdigest))
    # md5Hexdigest=585ad2765d147c7e918478a4ce843ed2
    # md5Hexdigest=321ed614f7211147be90a45bbca94127
    # md5Hexdigest=defc3b231167e16932ea923d616e2d40
    # md5Hexdigest=c687d5dfa015246e6bdc6b3c27c2afea
    return md5Hexdigest
    # return md5Digest

if __name__ == "__main__":
    timestampInt = 1553845899
    # paramString = "{\"userId\":\"1134723\",\"fieldName\":\"\",\"fieldValue\":\"全部类别\",\"theStageOfTheChild\":\"\",\"parentalEnglishLevel\":\"\",\"supportingResources\":\"有音频\",\"offset\":20,\"limit\":10}"
    paramString = """{"userId":"1134723","fieldName":"","fieldValue":"全部类别","theStageOfTheChild":"","parentalEnglishLevel":"","supportingResources":"有音频","offset":20,"limit":10}"""

    generatedSignature = generateSignature(timestampInt, paramString)
    # print("timestampInt=%d, paramString=%s-> %s" % (timestampInt, paramString, generatedSignature))
即:
11347231553845899{"userId":"1134723","fieldName":"","fieldValue":"全部类别","theStageOfTheChild":"","parentalEnglishLevel":"","supportingResources":"有音频","offset":20,"limit":10}40d2267f-359e-4526-951a-66519e5868c3AyGt7ohMR!xxx#N
算出的md5是:
c687d5dfa015246e6bdc6b3c27c2afea
和最开始抓包抓到的:
signature: c687d5dfa015246e6bdc6b3c27c2afea
是一致的了-》终于计算出正确的几个参数合并后的md5的signature值了。
【总结】
此处对于之前
src/main/java/com/huili/readingclub/model/ModelSecurity.java
的addSignature:
    public static void addSignature(RequestParams requestParams, String str) {
        if (str.startsWith(MyConfig.SERVER_PORT)) {
            str = str.substring(MyConfig.SERVER_PORT.length());
        }
        if (!str.startsWith("/UserService.svc/getToken/")) {
            StringBuilder stringBuilder;
            int parseInt = StringUtil.isNullOrEmpty(MainActivity.userId) ? 0 : Integer.parseInt(MainActivity.userId);
            if (parseInt < 1) {
                parseInt = 0;
            }
            String str2 = "";
            if (parseInt != 0) {
                str2 = getToken(MainActivity.userId);
            }
            long j = DateUtils.get1970ToNowSeconds();
            if (parseInt == 0) {
                stringBuilder = new StringBuilder();
                stringBuilder.append(j);
                stringBuilder.append(str);
                stringBuilder.append(MyConfig.SECRET_KEY);
                str = StringUtil.md5(stringBuilder.toString());
            } else {
                StringBuilder stringBuilder2 = new StringBuilder();
                stringBuilder2.append(MainActivity.userId);
                stringBuilder2.append(j);
                stringBuilder2.append(str);
                stringBuilder2.append(str2);
                stringBuilder2.append(MyConfig.SECRET_KEY);
                str = StringUtil.md5(stringBuilder2.toString());
            }
            if (parseInt != 0) {
                requestParams.addHeader(USER.USERID, MainActivity.userId);
            }
            stringBuilder = new StringBuilder();
            stringBuilder.append(j);
            stringBuilder.append("");
            requestParams.addHeader("timestamp", stringBuilder.toString());
            requestParams.addHeader("signature", str);
        }
    }
中的md5核心计算逻辑:
                StringBuilder stringBuilder2 = new StringBuilder();
                stringBuilder2.append(MainActivity.userId);
                stringBuilder2.append(j);
                stringBuilder2.append(str);
                stringBuilder2.append(str2);
                stringBuilder2.append(MyConfig.SECRET_KEY);
                str = StringUtil.md5(stringBuilder2.toString());
对应的Python实现是:
from hashlib import md5

def generateSignature(timestampInt, paramString):
    userId = "1134723"
    timestamp = "%s" % timestampInt
    # localObject = "/Reading.svc/parentChildReadingBookQuery2"
    # localObject = paramString
    userToken = "40d2267f-359e-4526-951a-66519e5868c3"
    # fixedSault = “AyGt7ohMR!xx#N"
    secretKey = “AyGt7ohMR!xx#N"

    # strToCalc = userId + timestamp + localObject + paramString + fixedSault
    # strToCalc = timestamp + localObject + fixedSault
    strToCalc = userId + timestamp + paramString + userToken + secretKey
    print("strToCalc=%s" % strToCalc)

    encodedStr = strToCalc.encode()
    # encodedStr = strToCalc.encode("UTF-8")
    # print("encodedStr=%s" % encodedStr)
    md5Result = md5(encodedStr)
    # print("md5Result=%s" % md5Result) # md5Result=<md5 HASH object @ 0x1044f1df0>

    # md5Result = md5()
    # md5Result.update(strToCalc)

    md5Digest = md5Result.digest()
    print("md5Digest=%s" % md5Digest) # 
    print("len(md5Digest)=%s" % len(md5Digest))

    md5Hexdigest = md5Result.hexdigest()
    print("md5Hexdigest=%s" % md5Hexdigest)
    print("len(md5Hexdigest)=%s" % len(md5Hexdigest))
    # md5Hexdigest=c687d5dfa015246e6bdc6b3c27c2afea
    return md5Hexdigest
    # return md5Digest

if __name__ == "__main__":
    timestampInt = 1553845899
    paramString = "{\"userId\":\"1134723\",\"fieldName\":\"\",\"fieldValue\":\"全部类别\",\"theStageOfTheChild\":\"\",\"parentalEnglishLevel\":\"\",\"supportingResources\":\"有音频\",\"offset\":20,\"limit\":10}"
    # paramString = """{"userId":"1134723","fieldName":"","fieldValue":"全部类别","theStageOfTheChild":"","parentalEnglishLevel":"","supportingResources":"有音频","offset":20,"limit":10}"""

    generatedSignature = generateSignature(timestampInt, paramString)
    # print("timestampInt=%d, paramString=%s-> %s" % (timestampInt, paramString, generatedSignature))
运行效果:
要计算的逻辑
userId + timestamp + paramString + userToken + secretKey
对应的字符串
11347231553845899{"userId":"1134723","fieldName":"","fieldValue":"全部类别","theStageOfTheChild":"","parentalEnglishLevel":"","supportingResources":"有音频","offset":20,"limit":10}40d2267f-359e-4526-951a-66519e5868c3AyGt7ohMR!xxx#N
的md5值是:
c687d5dfa015246e6bdc6b3c27c2afea
另外去网上验证:
md5加密,sha1加密–cmd5
也是对的:
【后记20190410】
后来发现,源码中:
对于GET来说,参数还略有不同,原先的paramString其实就从POST的jValue变成了urlEndpoint了。
所以最后代码改为:

    def generateSignature(self, timestampInt, jValueOrUrlEndpoint):
        # print("generateSignature: timestampInt=%d, jValueOrUrlEndpoint=%s" % (timestampInt, jValueOrUrlEndpoint))
        # userId = "1134723"
        userId = gUserId
        timestamp = "%s" % timestampInt
        # localObject = "/Reading.svc/parentChildReadingBookQuery2"
        # localObject = jValueOrUrlEndpoint
        # userToken = "40d2267f-359e-4526-951a-66519e5868c3"
        userToken = gUserToken
        # fixedSault = “AyGt7ohMR!xx#N"
        # secretKey = “AyGt7ohMR!xx#N"
        secretKey = gSecretKey


        # strToCalc = userId + timestamp + localObject + jValueOrUrlEndpoint + fixedSault
        # strToCalc = timestamp + localObject + fixedSault
        strToCalc = userId + timestamp + jValueOrUrlEndpoint + userToken + secretKey
        # print("strToCalc=%s" % strToCalc)


        encodedStr = strToCalc.encode()
        # encodedStr = strToCalc.encode("UTF-8")
        # print("encodedStr=%s" % encodedStr)
        md5Result = md5(encodedStr)
        # print("md5Result=%s" % md5Result) # md5Result=<md5 HASH object @ 0x1044f1df0>


        # md5Result = md5()
        # md5Result.update(strToCalc)


        # md5Digest = md5Result.digest()
        # print("md5Digest=%s" % md5Digest) #
        # print("len(md5Digest)=%s" % len(md5Digest))


        md5Hexdigest = md5Result.hexdigest()
        # print("md5Hexdigest=%s" % md5Hexdigest)
        # print("len(md5Hexdigest)=%s" % len(md5Hexdigest))
        # md5Hexdigest=c687d5dfa015246e6bdc6b3c27c2afea
        # print("md5=%s from %s" % (md5Hexdigest, strToCalc))
        return md5Hexdigest
        # return md5Digest


    def generateCurrentHeaders(self, jValueOrUrlEndpoint):
        curHeaders = copy.deepcopy(gHeaders)
        curTimestampInt = getCurTimestamp()


        curTimestampStr = str(curTimestampInt)
        curHeaders["timestamp"] = curTimestampStr


        curSignature = self.generateSignature(curTimestampInt, jValueOrUrlEndpoint)
        curHeaders["signature"] = curSignature


        return curHeaders


urlEndpoint = "/Reading.svc/viewEnglishSeries2/%s/%s" % (gUserId, seriePrimayKey)
fullUrl = "%s%s" % (gServerPort, urlEndpoint)
# /Reading.svc/viewEnglishSeries2/1134723/31
curHeaders = self.generateCurrentHeaders(urlEndpoint)
从而也支持GET类的api请求的signature参数的生成。

转载请注明:在路上 » 【已解决】Python实现小花生中addSignature的md5加密生成签名的逻辑

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.182 seconds, using 22.16MB memory