1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 网易云音乐params和encSecKey生成原理

网易云音乐params和encSecKey生成原理

时间:2019-03-19 17:37:28

相关推荐

网易云音乐params和encSecKey生成原理

1.首先来个整体的解析

params:经过两次AES加密后的数据(128位,CBC,pkcs5padding)

第一加密:要加密的是真正要发送的明文数据(数据的具体格式,下面会讲),密钥固定为0CoJUm6Qyw8W8jud,iv为固定为0102030405060708

第二加密:先把第一次加密结果转base64格式后,再进行加密。密钥是在前端随机生成的(长度为16个字节),iv为也是固定为0102030405060708

encSecKey:经过RSA加密后的数据(1024位,ECB,nopadding)

上面提到的第二次AES加密的密钥是在前端随机生成的,服务器想要解密数据,必须知道这个密钥,但服务器是怎么知道这个随机密钥的呢?

这时encSecKey就派上用场了。用RSA加密AES密钥后,再发给服务器。没错,encSecKey就是RSA加密后的AES密钥

注意,在加密前,需要对明文反转处理,例如:如果加密的明文是aaaabbbbccccdddd,那你要把它转成ddddccccbbbbaaaa后再进行RSA加密

用到了RSA加密,那这个RSA的公钥是多少?很幸运,这个公钥是固定的。modulus和publicExponent如下(都是十进制):

modulus=15779475026713150221247681780034549812187278333338974742401153102536627753526253991370180629076647918947753359785498960680319425397866032994198078607243280642783368547261879259295694346872951301770580765135349259590167490536138082469680638514416594216629258349130257685001248172188325316586707301643237607

publicExponent=65537

2.简化爬虫

上面提到过,params的第二次AES加密的密钥是在前端随机生成的,假如进行干预,让每次生成的密钥都一样,这样的话encSecKey每次也就一样了。

为了方便爬虫,让每次encSecKey都固定,我就让第二次AES加密密钥每次都是aaaabbbbccccdddd

然后进行按上面提到的规则进行RSA加密,生成encSecKey代码如下

import javax.crypto.Cipher;import java.math.BigInteger;import java.nio.charset.StandardCharsets;import java.security.KeyFactory;import java.security.interfaces.RSAPublicKey;import java.security.spec.RSAPublicKeySpec;public class Test {public static void main(String[] args) throws Exception{String modulus ="15779475026713150221247681780034549812187278333338974742401153102536627753526253991370180629076647918947753359785498960680319425397866032994198078607243280642783368547261879259295694346872951301770580765135349259590167490536138082469680638514416594216629258349130257685001248172188325316586707301643237607";String publicExponent = "65537";RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));RSAPublicKey key = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicSpec);Cipher cipher = Cipher.getInstance("RSA/ECB/nopadding");cipher.init(Cipher.ENCRYPT_MODE,key);//注意,我这里已经进行字符串反转byte[] res = cipher.doFinal("ddddccccbbbbaaaa".getBytes(StandardCharsets.UTF_8));//把密文转成16进制字符串后输出System.out.print(longToHexString(res));}//这个函数是用来将二进制数据转成16进制字符串的static private String longToHexString(byte[] num) {StringBuffer hexString = new StringBuffer();for (int i=0;i<num.length;i++){if((num[i]&0xf0)==0){hexString.append("0"+Integer.toHexString(num[i]&0xff));}else{hexString.append(Integer.toHexString(num[i]&0xff));}}return hexString.toString();}}

输出encSecKey为:

814e4abf9c1c6a2af74a7ecca8843f3052626c5c054584352e3fd38a519bd659e687cf1c079e1aac5dd9d491af6b8abf92109862ada93dc7b0ef94a8ee79d557ff2a20512b87ce507e357861366b8542139c67896748852d4086104a8dfc99a2e2e0640b46a4357407b72407b2849b323425c6ed45a0222e69d551a2e59e15b7

到这里,已经简化了爬虫,即以后每次请求,encSecKey的值都是固定的,都是上面这个字符串。

params用到的加密密钥也固定了,

第一次是0CoJUm6Qyw8W8jud

第二次是aaaabbbbccccdddd

iv都是0102030405060708

3.网易云主要接口

既然我们知道了param和encSecKey的生成原理,下面我们就介绍一下基本接口:音乐搜索接口获取音乐文件接口

音乐搜索

接口:/weapi/cloudsearch/get/web

请求方式:post

求情数据:

返回格式:json格式,里面包含有歌曲的id数据,id用于获取歌曲文件链接

2.获取音乐文件链接

接口:/weapi/song/enhance/player/url

请求方式:post

请求数据:

返回数据示例:

{“data”:[{“id”:193824,“url”:“http://m10./0826233706/5e405016288a01153be3bc74b384/ymusic/369d/350a/1ee0/465d7f1ada6b28c4d8c83dcc37858e84.mp3”,“br”:128000,“size”:4091445,“md5”:“465d7f1ada6b28c4d8c83dcc37858e84”,“code”:200,“expi”:1200,“type”:“mp3”,“gain”:0.0,“fee”:0,“uf”:null,“payed”:0,“flag”:0,“canExtend”:false,“freeTrialInfo”:null,“level”:“standard”,“encodeType”:“mp3”,“freeTrialPrivilege”:{“resConsumable”:false,“userConsumable”:false},“freeTimeTrialPrivilege”:{“resConsumable”:false,“userConsumable”:false,“type”:0,“remainTime”:0},“urlSource”:0}],“code”:200}

黑体那个就是纯音乐文件,打开可以直接下载或者播放

4.代码示例

如果你看不懂上面的讲解也无大碍,看懂下面的代码就可以了

生成param的java代码:

try {//明文数据,两次AES加密后再发送,请根据需求进行修改;172447为歌曲idString data ="{\"ids\":\"[570839692]\",\"br\":128000,\"csrf_token\":\"\"}";Cipher cipher = Cipher.getInstance("AES/CBC/pkcs5padding");IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes(StandardCharsets.UTF_8));//第一次加密SecretKeySpec key1 = new SecretKeySpec("0CoJUm6Qyw8W8jud".getBytes(StandardCharsets.UTF_8),"AES");cipher.init(Cipher.ENCRYPT_MODE,key1,iv);byte[] res = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));//第二次加密(注意:要先把第一次加密结果转成base64后再进行第一次加密)SecretKeySpec key2 = new SecretKeySpec("aaaabbbbccccdddd".getBytes(StandardCharsets.UTF_8),"AES");cipher.init(Cipher.ENCRYPT_MODE,key2,iv);byte[] base64 =Base64.getEncoder().encode(res);//转base64res=cipher.doFinal(base64);String params= URLEncoder.encode(Base64.getEncoder().encodeToString(res),StandardCharsets.UTF_8);System.out.println(params);}catch (Exception e){e.printStackTrace();}

输出params为:

v1UdMgiG2PgS146seSwrcuicidNtpVNCL9ogx4K1r4Bdjp3GboV9tyIKh8PmfUduQFNgqj%2BZfcvI5vHQDEbEA1tqM56zy5yiGFcisEnuWqoqm4UI00XeDExtyra3RFHc

生成encSecKey:

已经让它固定了,不需要每次再生成了,固定为下面

814e4abf9c1c6a2af74a7ecca8843f3052626c5c054584352e3fd38a519bd659e687cf1c079e1aac5dd9d491af6b8abf92109862ada93dc7b0ef94a8ee79d557ff2a20512b87ce507e357861366b8542139c67896748852d4086104a8dfc99a2e2e0640b46a4357407b72407b2849b323425c6ed45a0222e69d551a2e59e15b7

再次强调,encSecKey固定是因为我们让第二次AES加密的密钥固定了,也就是说现在这个固定的encSecKey是AES密钥aaaabbbbccccdddd的密文

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。