|
2 | 2 |
|
3 | 3 | import top.gregtao.concerto.util.HashUtil; |
4 | 4 |
|
| 5 | +import java.nio.charset.StandardCharsets; |
5 | 6 | import java.util.*; |
6 | 7 |
|
7 | 8 | public class QQMusicApiEncrypt { |
8 | 9 |
|
9 | | - // // Original source by: https://blog.csdn.net/qq_23594799/article/details/111477320, https://blog.csdn.net/qq_37438485/article/details/124420854 |
10 | | - // |
11 | | - // private static final String ENCRYPT_STATIC = "CJBPACrRuNy7"; |
12 | | - // private static final String PREFIX = "zzb"; |
13 | | - // |
14 | | - // /** |
15 | | - // * @param body 需要加密的参数,这是一段请求体数据,为json字符串格式,例如下面的格式,可以抓包获取 |
16 | | - // * {"comm":{"ct":24,"cv":0},"vip":{"module":"userInfo…baseinfo_v2","param":{"vec_uin":["3011429848"]}}} |
17 | | - // * @return 加密的方式为固定字串 zza + 10-16位的随机字符串 + (CJBPACrRuNy7 + 请求数据)的MD5值 |
18 | | - // */ |
19 | | - // public static String getSign(String body){ |
20 | | - // return PREFIX + UUID.randomUUID().toString().replaceAll("-", "") + HashUtil.md5(ENCRYPT_STATIC + body); |
21 | | - // } |
| 10 | + // Code by: https://github.com/jixunmoe/qmweb-sign, MIT license |
| 11 | + public static class ZzcSign { |
| 12 | + private static final int[] PART_1_INDEXES = {23, 14, 6, 36, 16, 40, 7, 19}; |
| 13 | + private static final int[] PART_2_INDEXES = {16, 1, 32, 12, 19, 27, 8, 5}; |
| 14 | + private static final int[] SCRAMBLE_VALUES = {89, 39, 179, 150, 218, 82, 58, 252, 177, 52, 186, 123, 120, 64, 242, 133, 143, 161, 121, 179}; |
| 15 | + |
| 16 | + public static String getSign(String payload) { |
| 17 | + String hash = HashUtil.sha1(payload); |
| 18 | + |
| 19 | + StringBuilder part1 = new StringBuilder(); |
| 20 | + for (int index : PART_1_INDEXES) { |
| 21 | + if (index < hash.length()) { |
| 22 | + part1.append(hash.charAt(index)); |
| 23 | + } |
| 24 | + } |
| 25 | + |
| 26 | + StringBuilder part2 = new StringBuilder(); |
| 27 | + for (int index : PART_2_INDEXES) { |
| 28 | + if (index < hash.length()) { |
| 29 | + part2.append(hash.charAt(index)); |
| 30 | + } |
| 31 | + } |
| 32 | + |
| 33 | + StringBuilder part3 = new StringBuilder(); |
| 34 | + |
| 35 | + for (int i = 0; i < SCRAMBLE_VALUES.length; i++) { |
| 36 | + int scramble = SCRAMBLE_VALUES[i]; |
| 37 | + int value = Integer.parseInt(hash.substring(i * 2, i * 2 + 2), 16); |
| 38 | + part3.append((char) (scramble ^ value)); |
| 39 | + } |
| 40 | + |
| 41 | + String b64Part = Base64.getEncoder().encodeToString(part3.toString().getBytes(StandardCharsets.UTF_8)); |
| 42 | + b64Part = b64Part.replaceAll("[/+=]", ""); |
| 43 | + |
| 44 | +// byte[] part3 = new byte[20]; |
| 45 | +// for (int i = 0; i < SCRAMBLE_VALUES.length; i++) { |
| 46 | +// int value = SCRAMBLE_VALUES[i] ^ Integer.parseInt(hash.substring(i * 2, i * 2 + 2), 16); |
| 47 | +// part3[i] = (byte) value; |
| 48 | +// } |
| 49 | +// |
| 50 | +// String b64Part = Base64.getEncoder().encodeToString(part3) |
| 51 | +// .replaceAll("[/+=]", "") |
| 52 | +// .toLowerCase(); |
| 53 | + |
| 54 | + return "zzc" + (part1 + b64Part + part2).toLowerCase(); |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + /** |
| 59 | + * Original source by: https://blog.csdn.net/qq_23594799/article/details/111477320, https://blog.csdn.net/qq_37438485/article/details/124420854 |
| 60 | + * private static final String ENCRYPT_STATIC = "CJBPACrRuNy7"; |
| 61 | + * private static final String PREFIX = "zzb"; |
| 62 | + * <p> |
| 63 | + * * @param body 需要加密的参数,这是一段请求体数据,为json字符串格式,例如下面的格式,可以抓包获取 |
| 64 | + * * {"comm":{"ct":24,"cv":0},"vip":{"module":"userInfo…baseinfo_v2","param":{"vec_uin":["3011429848"]}}} |
| 65 | + * * @return 加密的方式为固定字串 zza + 10-16位的随机字符串 + (CJBPACrRuNy7 + 请求数据)的MD5值 |
| 66 | + * <p> |
| 67 | + * public static String getSign(String body){ |
| 68 | + * return PREFIX + UUID.randomUUID().toString().replaceAll("-", "") + HashUtil.md5(ENCRYPT_STATIC + body); |
| 69 | + * } |
| 70 | + */ |
22 | 71 | public static class Sign { |
23 | 72 |
|
24 | 73 | private static void test(List<Integer> resNum, int a, int b, int c) { |
|
0 commit comments