<!DOCTYPE html><html lang="zh" data-theme="dark"><head><meta charset="utf-8"><meta name="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>JS 逆向网易云音乐 · Cytrogen 的个人博客</title><meta name="description" content="本文是一篇网易云音乐网页版 API 的逆向分析实战教程,旨在解决如何获取歌曲真实 .m4a 播放链接的问题。教程通过浏览器开发者工具,一步步追踪并剖析了其核心加密参数 params 和 encSecKey 的生成过程,深入分析了背后涉及的 AES 和 RSA 加密算法。最终,通过 Python 结合 PyExecJS 库调用复现的 JavaScript 加密逻辑,成功构造请求并获取到歌曲链接,同时还逆向了歌曲搜索接口。本文为对网页逆向、API分析和加解密技术感兴趣的开发者提供了一次完整的实战演练。"><link rel="icon" href="../favicon.png"><link rel="canonical" href="https://cytrogen.icu/posts/f8ce.html"><link rel="webmention" href="https://webmention.io/cytrogen.icu/webmention"><link rel="me" href="https://m.otter.homes/@Cytrogen"><link rel="me" href="https://github.com/cytrogen"><meta name="fediverse:creator" content="@Cytrogen@m.otter.homes"><link rel="preload" href="../fonts/opensans-regular-latin.woff2" as="font" type="font/woff2" crossorigin="anonymous"><style>@font-face {
font-family: 'Open Sans';
src: url('../fonts/opensans-regular-latin.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
size-adjust: 107%;
ascent-override: 97%;
descent-override: 25%;
line-gap-override: 0%;
}
</style><script>(function() {
try {
// 优先级:用户选择 > 系统偏好 > 默认浅色
const saved = localStorage.getItem('theme');
const theme = saved ||
(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.style.colorScheme = theme;
} catch (error) {
// 失败时使用默认主题,不阻塞渲染
document.documentElement.setAttribute('data-theme', 'light');
}
})();
</script><link rel="stylesheet" href="../css/ares.css"><script data-netlify-skip-bundle="true">(function() {
document.addEventListener('DOMContentLoaded', function() {
const theme = document.documentElement.getAttribute('data-theme');
const pageWrapper = document.getElementById('page-wrapper');
if (pageWrapper && theme) {
pageWrapper.setAttribute('data-theme', theme);
}
});
})();
</script><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 8.1.1"><link rel="alternate" href="atom.xml" title="Cytrogen 的个人博客" type="application/atom+xml">
</head><body><div id="page-wrapper"><a class="skip-link" href="#main-content">跳到主要内容</a><div class="wrap"><header><a class="logo-link" href="../index.html"><img src="../favicon.png" alt="logo"></a><div class="h-card visually-hidden"><img class="u-photo" src="https://cytrogen.icu/favicon.png" alt="Cytrogen"><a class="p-name u-url u-uid" href="https://cytrogen.icu">Cytrogen</a><p class="p-note">Cytrogen 的个人博客,Cytrogen's Blog</p><a class="u-url" rel="me noopener" target="_blank" href="https://m.otter.homes/@Cytrogen">Mastodon</a><a class="u-url" rel="me noopener" target="_blank" href="https://github.com/cytrogen">GitHub</a></div><nav class="site-nav"><div class="nav-main"><div class="nav-primary"><ul class="nav-list hidden-mobile"><li class="nav-item"><a class="nav-link" href="../index.html">首页</a></li></ul><div class="nav-tools"><div class="language-menu"><button class="language-toggle" type="button"><svg class="icon icon-globe" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855A7.97 7.97 0 0 0 10.855 12H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"></path></svg><span>中文</span></button><div class="language-dropdown"></div></div></div><div class="nav-controls"><div class="more-menu hidden-mobile"><button class="more-toggle" type="button"><span>更多</span><svg class="icon icon-chevron-down" width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 8.825c-.2 0-.4-.1-.5-.2l-3.3-3.3c-.3-.3-.3-.8 0-1.1s.8-.3 1.1 0l2.7 2.7 2.7-2.7c.3-.3.8-.3 1.1 0s.3.8 0 1.1l-3.3 3.3c-.1.1-.3.2-.5.2z"></path></svg></button><div class="more-dropdown"><ul class="dropdown-list"><li class="dropdown-item"><a class="nav-link" href="../archives/index.html">归档</a></li><li class="dropdown-item"><a class="nav-link" href="../categories/index.html">分类</a></li><li class="dropdown-item"><a class="nav-link" href="../tags/index.html">标签</a></li><li class="dropdown-item"><a class="nav-link" href="../about/index.html">关于</a></li><li class="dropdown-item"><a class="nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></div><div class="theme-switcher"><button class="theme-toggle" type="button" role="switch" aria-pressed="false" aria-label="切换主题"><div class="theme-icon moon-icon"><svg class="icon icon-moon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"></path></svg></div><div class="theme-icon sun-icon"><svg class="icon icon-sun" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"></path></svg></div></button></div><details class="mobile-menu-details hidden-desktop"><summary class="hamburger-menu" aria-label="nav.menu"><svg class="icon icon-bars" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"></path></svg><span class="menu-text">nav.menu</span></summary><div class="mobile-menu-dropdown"><ul class="mobile-nav-list"><li class="mobile-nav-item"><a class="mobile-nav-link" href="../index.html">首页</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../archives/index.html">归档</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../categories/index.html">分类</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../tags/index.html">标签</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../about/index.html">关于</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></details></div></div></div></nav></header><main class="container" id="main-content" tabindex="-1"><div class="post"><article class="post-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="author-avatar u-photo" src="../favicon.png" alt="Cytrogen"><span class="p-name">Cytrogen</span><a class="u-url" href="https://cytrogen.icu">https://cytrogen.icu</a></div><a class="post-permalink u-url u-uid visually-hidden" href="https://cytrogen.icu/posts/f8ce.html">永久链接</a><div class="p-summary visually-hidden"><p>该文章记录了我如何逆向网易云<s>并制作一个简易的播放器(鸽了)</s>。</p></div><div class="visually-hidden"><a class="p-category" href="../categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/">编程笔记</a><a class="p-category" href="../tags/Python/">Python</a><a class="p-category" href="../tags/JavaScript/">JavaScript</a><a class="p-category" href="../tags/%E7%BD%91%E9%A1%B5%E9%80%86%E5%90%91/">网页逆向</a></div><h1 class="post-title p-name">JS 逆向网易云音乐</h1><div class="post-info"><time class="post-date dt-published" datetime="2023-11-27T21:00:57.000Z">11/27/2023</time><time class="dt-updated visually-hidden" datetime="2026-02-09T17:16:54.729Z"></time></div><div class="post-content e-content"><html><head></head><body><p>该文章记录了我如何逆向网易云 <s>并制作一个简易的播放器(鸽了)</s>。</p>
<span id="more"></span>
<h1 id="逆向网易云"><a class="markdownIt-Anchor" href="#逆向网易云"></a> 逆向网易云</h1>
<p>用浏览器打开网易云的网站,随意挑选一首歌曲进行播放,同时检查网络选项卡中的响应。我们能看到媒体类型中有一个 <code>.m4a</code> 文件。直接用 Python 的 requests 爬取下来进行播放,够厚道,爬下来就能听。</p>
<p><img src="/posts/f8ce/1.png" alt=""><br>
<img src="/posts/f8ce/2.png" alt=""></p>
<p>当然在页面源代码里找这个 <code>.m4a</code> 文件是找不到的,不然也不会说要 <strong>逆向</strong> 网易云了。我们该如何找到这个 <code>.m4a</code> 文件的 URL 呢?继续看看网络选项卡里的请求:</p>
<p><img src="/posts/f8ce/3.png" alt=""></p>
<p>赫然出现这么一个请求,返回的 JSON 数据中有 <code>.m4a</code> 的链接。嗯,就是你了!看看负载:</p>
<p><img src="/posts/f8ce/4.png" alt=""></p>
<p><code>csrf_token</code> 为空,重点是表单数据的 <code>params</code> 和 <code>encSecKey</code>。其中的内容都是一大串反正不是明文的东西,那么逆向的目标就是找到这两个参数的生成方式。</p>
<p>原本想要直接在源代码里一个个找过去这两个参数,后来突然想到客户端反正都会朝 <code>https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=</code> 发送请求,那么直接在 XHR / 提取断点里选择所有包含着 <code>v1?csrf_token=</code> 的 URL 不就行了。</p>
<p>关注 <code>arguments</code> 的构造此时成为了我们的目标。</p>
<p><img src="/posts/f8ce/5.png" alt=""></p>
<p>用调用堆栈陆续向上查看,发现 <code>params</code> 和 <code>encSecKey</code> 依旧是加密过后的。哎,加把劲吧,继续向上查看。</p>
<p><img src="/posts/f8ce/6.png" alt=""></p>
<p>一直到这一步…… 观察其前面的代码能发现一个非常有意思的事情:</p>
<p><img src="/posts/f8ce/7.png" alt=""></p>
<ol>
<li>变量 <code>bKC1x</code> 被赋值</li>
<li><code>e1x.data</code> 被赋值时,<code>bKC1x</code> 被用到了,参数中还赫然写着 <code>params</code> 和 <code>encSecKey</code></li>
<li>根据我们之前查看的调用堆栈,<code>chF5K(X2x, e1x)</code> 的第二个参数必定是 <code>params</code> 和 <code>encSecKey</code> 的组合</li>
</ol>
<p>这说明什么?说明 <code>bKC1x</code> 就是生成 <code>params</code> 和 <code>encSecKey</code> 的关键!我们仔细分析一下它的构造:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> bKC1x = <span class="variable language_">window</span>.<span class="title function_">asrsea</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(i1x), <span class="title function_">bvh3x</span>([<span class="string">"流泪"</span>, <span class="string">"强"</span>]), <span class="title function_">bvh3x</span>(<span class="title class_">Rf5</span>k.<span class="property">md</span>), <span class="title function_">bvh3x</span>([<span class="string">"爱心"</span>, <span class="string">"女孩"</span>, <span class="string">"惊恐"</span>, <span class="string">"大笑"</span>]));</span><br></pre></td></tr></tbody></table></figure>
<p>其中第三个参数所使用的 <code>Rf5k.md</code> 的内容如下:</p>
<p><img src="/posts/f8ce/10.png" alt=""></p>
<blockquote>
<p>很想吐槽…… 这些字符串的意义是什么???</p>
</blockquote>
<p><code>bKC1x</code> 本身会生成一个字典,其中包含 <code>encText</code> 和 <code>encSecKey</code> 两个键。而屡次出现的 <code>bvh3x()</code> 函数的构造如下:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> bvh3x = <span class="keyword">function</span>(<span class="params">chL5Q</span>) {</span><br><span class="line"> <span class="keyword">var</span> m1x = [];</span><br><span class="line"> j1x.<span class="title function_">bg2x</span>(chL5Q, <span class="keyword">function</span>(<span class="params">chK5P</span>) {</span><br><span class="line"> m1x.<span class="title function_">push</span>(<span class="title class_">Rf5</span>k.<span class="property">emj</span>[chK5P])</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> m1x.<span class="title function_">join</span>(<span class="string">""</span>)</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure>
<p><img src="/posts/f8ce/8.png" alt=""></p>
<p>它的运作差不多是这样子的。</p>
<p><code>Rf5k.emj</code> 是一个字典,构造非常激寒:</p>
<p><img src="/posts/f8ce/9.png" alt=""></p>
<blockquote>
<p>…… 谁来告诉我这些键到底都是什么意思???</p>
</blockquote>
<p>也就是说 <code>bvh3x()</code> 函数接收参数,按照每个元素的字符串、对比 <code>Rf5k.emj</code> 字典中的键来返回对应的值,最后拼接成一个列表。</p>
<p>知道了 <code>bKC1x</code> 中后三个参数的生成方式,我们便只需要知道第一个参数 —— <code>JSON.stringify(i1x)</code> —— 是什么来头的了:</p>
<p><img src="/posts/f8ce/11.png" alt=""></p>
<p>手到擒来,这个 id 不就是歌曲 id 么?!</p>
<p>参数已经全部知晓,最后要看网易云如何加密它们。<code>window.asrsea()</code> 函数作为加密这些参数的老大哥,它的构造如下:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">d</span>(<span class="params">d, e, f, g</span>) {</span><br><span class="line"> <span class="keyword">var</span> h = {}</span><br><span class="line"> , i = <span class="title function_">a</span>(<span class="number">16</span>);</span><br><span class="line"> <span class="keyword">return</span> h.<span class="property">encText</span> = <span class="title function_">b</span>(d, g),</span><br><span class="line"> h.<span class="property">encText</span> = <span class="title function_">b</span>(h.<span class="property">encText</span>, i),</span><br><span class="line"> h.<span class="property">encSecKey</span> = <span class="title function_">c</span>(i, e, f),</span><br><span class="line"> h</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p><code>d()</code> 函数需要好好说道说道。接收的四个参数我们已述说过,这里不废话了。<code>d()</code> 先创建了一个空字典 <code>h</code>,接着创建了一个 <code>i</code>。要知道 <code>i</code> 的值,我们需要知道 <code>a()</code> 的内容:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">a</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, e, b = <span class="string">"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"</span>, c = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> (d = <span class="number">0</span>; a > d; d += <span class="number">1</span>)</span><br><span class="line"> e = <span class="title class_">Math</span>.<span class="title function_">random</span>() * b.<span class="property">length</span>,</span><br><span class="line"> e = <span class="title class_">Math</span>.<span class="title function_">floor</span>(e),</span><br><span class="line"> c += b.<span class="title function_">charAt</span>(e);</span><br><span class="line"> <span class="keyword">return</span> c</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>变量 <code>d</code>、<code>e</code>、<code>b</code> 都是字符串</li>
<li><code>for</code> 循环中 <code>d</code> 变成整数 0,每次循环加 1,直到 <code>a</code> 的值,也就是上面 <code>d()</code> 函数中传入的整数 16</li>
<li><code>e</code> 在每次循环都是一个随机数,有着 <code>b</code> 的长度,并且会被 <code>Math.floor()</code> 函数取整</li>
<li><code>c</code> 是一个空字符串,每次循环都会被 <code>b</code> 的第 <code>e</code> 个字符所填充</li>
</ul>
<p>用人话来说便是:<code>a()</code> 函数会 <strong>生成一个长度为 16 的随机字符串</strong>。</p>
<p>回到 <code>d()</code> 函数,<code>h.encText</code> 的值是 <code>b(d, g)</code>,而 <code>b()</code> 函数的构造如下:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">b</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(b)</span><br><span class="line"> , d = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="string">"0102030405060708"</span>)</span><br><span class="line"> , e = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(a)</span><br><span class="line"> , f = <span class="title class_">CryptoJS</span>.<span class="property">AES</span>.<span class="title function_">encrypt</span>(e, c, {</span><br><span class="line"> <span class="attr">iv</span>: d,</span><br><span class="line"> <span class="attr">mode</span>: <span class="title class_">CryptoJS</span>.<span class="property">mode</span>.<span class="property">CBC</span></span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> f.<span class="title function_">toString</span>()</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p><code>CryptoJS</code> 是一个 JavaScript 的加密算法库,这里不做过多介绍,后面会讲到如何引用。</p>
</blockquote>
<p>该函数先是声明了变量 <code>c</code>、<code>d</code> 和 <code>e</code> 这三个由不同的值被 UTF-8 编码后的字符串。接着声明了变量 <code>f</code> —— 一个由 AES.CBC 模式加密的 <code>e</code> —— 其密钥为 <code>c</code>、偏移量为 <code>d</code>。返回的 <code>f</code> 的字符串形式最终变成了我们的 <code>encText</code>。</p>
<p>值得注意的是,在 <code>d()</code> 函数里,<code>h.encText</code><strong>又</strong> 被塞进 <code>b()</code> 函数里加密了一次。</p>
<p>而 <code>h.encSecKey</code> 由 <code>c()</code> 函数生成,它的构造如下:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">c</span>(<span class="params">a, b, c</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, e;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">setMaxDigits</span>(<span class="number">131</span>),</span><br><span class="line"> d = <span class="keyword">new</span> <span class="title class_">RSAKeyPair</span>(b,<span class="string">""</span>,c),</span><br><span class="line"> e = <span class="title function_">encryptedString</span>(d, a)</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>在 <code>c()</code> 函数里,先是调用了 <code>setMaxDigits()</code> 函数;这个函数接收一个需要加密的字符串 <code>a</code>,一个公钥 <code>b</code>,以及生成 RSA 密钥对所需的另一个参数 <code>c</code>。它先是使用 <code>setMaxDigits()</code> 函数设置了 <code>BigInt</code> 可操作的最大位数为 131。然后使用提供的公钥 <code>b</code> 和参数 <code>c</code> 生成 RSA 密钥对 <code>d</code>。最后,它使用生成的密钥对加密了字符串 <code>a</code>。</p>
<p>问题又双叒叕来了,什么是 <code>setMaxDigits()</code>?什么是 <code>BigInt</code>?莫急,再再再来看一眼网易云的源代码:</p>
<p><img src="/posts/f8ce/12.png" alt=""></p>
<p><code>setMaxDigits()</code> 和以上提到的函数们有一个天大的区别:它是全局函数,无论在哪里都能被调用。而这种全局函数的定义在网易云的源代码中只有一处:第 89 行。我们可以直接把这第 89 行的内容全部复制粘贴下来使用。</p>
<details>
<summary>展开</summary>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">RSAKeyPair</span>(<span class="params">a, b, c</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">e</span> = <span class="title function_">biFromHex</span>(a),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">d</span> = <span class="title function_">biFromHex</span>(b),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">m</span> = <span class="title function_">biFromHex</span>(c),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">chunkSize</span> = <span class="number">2</span> * <span class="title function_">biHighIndex</span>(<span class="variable language_">this</span>.<span class="property">m</span>),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">radix</span> = <span class="number">16</span>,</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">barrett</span> = <span class="keyword">new</span> <span class="title class_">BarrettMu</span>(<span class="variable language_">this</span>.<span class="property">m</span>)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">twoDigit</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">return</span> (<span class="number">10</span> > a ? <span class="string">"0"</span> : <span class="string">""</span>) + <span class="title class_">String</span>(a)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">encryptedString</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> f, g, h, i, j, k, l, c = <span class="keyword">new</span> <span class="title class_">Array</span>, d = b.<span class="property">length</span>, e = <span class="number">0</span>; d > e; )</span><br><span class="line"> c[e] = b.<span class="title function_">charCodeAt</span>(e),</span><br><span class="line"> e++;</span><br><span class="line"> <span class="keyword">for</span> (; <span class="number">0</span> != c.<span class="property">length</span> % a.<span class="property">chunkSize</span>; )</span><br><span class="line"> c[e++] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (f = c.<span class="property">length</span>,</span><br><span class="line"> g = <span class="string">""</span>,</span><br><span class="line"> e = <span class="number">0</span>; f > e; e += a.<span class="property">chunkSize</span>) {</span><br><span class="line"> <span class="keyword">for</span> (j = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> h = <span class="number">0</span>,</span><br><span class="line"> i = e; i < e + a.<span class="property">chunkSize</span>; ++h)</span><br><span class="line"> j.<span class="property">digits</span>[h] = c[i++],</span><br><span class="line"> j.<span class="property">digits</span>[h] += c[i++] << <span class="number">8</span>;</span><br><span class="line"> k = a.<span class="property">barrett</span>.<span class="title function_">powMod</span>(j, a.<span class="property">e</span>),</span><br><span class="line"> l = <span class="number">16</span> == a.<span class="property">radix</span> ? <span class="title function_">biToHex</span>(k) : <span class="title function_">biToString</span>(k, a.<span class="property">radix</span>),</span><br><span class="line"> g += l + <span class="string">" "</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> g.<span class="title function_">substring</span>(<span class="number">0</span>, g.<span class="property">length</span> - <span class="number">1</span>)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">decryptedString</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> e, f, g, h, c = b.<span class="title function_">split</span>(<span class="string">" "</span>), d = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> (e = <span class="number">0</span>; e < c.<span class="property">length</span>; ++e)</span><br><span class="line"> <span class="keyword">for</span> (h = <span class="number">16</span> == a.<span class="property">radix</span> ? <span class="title function_">biFromHex</span>(c[e]) : <span class="title function_">biFromString</span>(c[e], a.<span class="property">radix</span>),</span><br><span class="line"> g = a.<span class="property">barrett</span>.<span class="title function_">powMod</span>(h, a.<span class="property">d</span>),</span><br><span class="line"> f = <span class="number">0</span>; f <= <span class="title function_">biHighIndex</span>(g); ++f)</span><br><span class="line"> d += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">255</span> & g.<span class="property">digits</span>[f], g.<span class="property">digits</span>[f] >> <span class="number">8</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span> == d.<span class="title function_">charCodeAt</span>(d.<span class="property">length</span> - <span class="number">1</span>) && (d = d.<span class="title function_">substring</span>(<span class="number">0</span>, d.<span class="property">length</span> - <span class="number">1</span>)),</span><br><span class="line"> d</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">setMaxDigits</span>(<span class="params">a</span>) {</span><br><span class="line"> maxDigits = a,</span><br><span class="line"> <span class="variable constant_">ZERO_ARRAY</span> = <span class="keyword">new</span> <span class="title class_">Array</span>(maxDigits);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> b = <span class="number">0</span>; b < <span class="variable constant_">ZERO_ARRAY</span>.<span class="property">length</span>; b++)</span><br><span class="line"> <span class="variable constant_">ZERO_ARRAY</span>[b] = <span class="number">0</span>;</span><br><span class="line"> bigZero = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> bigOne = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> bigOne.<span class="property">digits</span>[<span class="number">0</span>] = <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">BigInt</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">digits</span> = <span class="string">"boolean"</span> == <span class="keyword">typeof</span> a && <span class="number">1</span> == a ? <span class="literal">null</span> : <span class="variable constant_">ZERO_ARRAY</span>.<span class="title function_">slice</span>(<span class="number">0</span>),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">isNeg</span> = !<span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biFromDecimal</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> d, e, f, b = <span class="string">"-"</span> == a.<span class="title function_">charAt</span>(<span class="number">0</span>), c = b ? <span class="number">1</span> : <span class="number">0</span>; c < a.<span class="property">length</span> && <span class="string">"0"</span> == a.<span class="title function_">charAt</span>(c); )</span><br><span class="line"> ++c;</span><br><span class="line"> <span class="keyword">if</span> (c == a.<span class="property">length</span>)</span><br><span class="line"> d = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">for</span> (e = a.<span class="property">length</span> - c,</span><br><span class="line"> f = e % dpl10,</span><br><span class="line"> <span class="number">0</span> == f && (f = dpl10),</span><br><span class="line"> d = <span class="title function_">biFromNumber</span>(<span class="title class_">Number</span>(a.<span class="title function_">substr</span>(c, f))),</span><br><span class="line"> c += f; c < a.<span class="property">length</span>; )</span><br><span class="line"> d = <span class="title function_">biAdd</span>(<span class="title function_">biMultiply</span>(d, lr10), <span class="title function_">biFromNumber</span>(<span class="title class_">Number</span>(a.<span class="title function_">substr</span>(c, dpl10)))),</span><br><span class="line"> c += dpl10;</span><br><span class="line"> d.<span class="property">isNeg</span> = b</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biCopy</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> b = <span class="keyword">new</span> <span class="title class_">BigInt</span>(!<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">return</span> b.<span class="property">digits</span> = a.<span class="property">digits</span>.<span class="title function_">slice</span>(<span class="number">0</span>),</span><br><span class="line"> b.<span class="property">isNeg</span> = a.<span class="property">isNeg</span>,</span><br><span class="line"> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biFromNumber</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> c, b = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (b.<span class="property">isNeg</span> = <span class="number">0</span> > a,</span><br><span class="line"> a = <span class="title class_">Math</span>.<span class="title function_">abs</span>(a),</span><br><span class="line"> c = <span class="number">0</span>; a > <span class="number">0</span>; )</span><br><span class="line"> b.<span class="property">digits</span>[c++] = a & maxDigitVal,</span><br><span class="line"> a >>= biRadixBits;</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">reverseStr</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> c, b = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> (c = a.<span class="property">length</span> - <span class="number">1</span>; c > -<span class="number">1</span>; --c)</span><br><span class="line"> b += a.<span class="title function_">charAt</span>(c);</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biToString</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, e, c = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (c.<span class="property">digits</span>[<span class="number">0</span>] = b,</span><br><span class="line"> d = <span class="title function_">biDivideModulo</span>(a, c),</span><br><span class="line"> e = hexatrigesimalToChar[d[<span class="number">1</span>].<span class="property">digits</span>[<span class="number">0</span>]]; <span class="number">1</span> == <span class="title function_">biCompare</span>(d[<span class="number">0</span>], bigZero); )</span><br><span class="line"> d = <span class="title function_">biDivideModulo</span>(d[<span class="number">0</span>], c),</span><br><span class="line"> digit = d[<span class="number">1</span>].<span class="property">digits</span>[<span class="number">0</span>],</span><br><span class="line"> e += hexatrigesimalToChar[d[<span class="number">1</span>].<span class="property">digits</span>[<span class="number">0</span>]];</span><br><span class="line"> <span class="keyword">return</span> (a.<span class="property">isNeg</span> ? <span class="string">"-"</span> : <span class="string">""</span>) + <span class="title function_">reverseStr</span>(e)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biToDecimal</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> c, d, b = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (b.<span class="property">digits</span>[<span class="number">0</span>] = <span class="number">10</span>,</span><br><span class="line"> c = <span class="title function_">biDivideModulo</span>(a, b),</span><br><span class="line"> d = <span class="title class_">String</span>(c[<span class="number">1</span>].<span class="property">digits</span>[<span class="number">0</span>]); <span class="number">1</span> == <span class="title function_">biCompare</span>(c[<span class="number">0</span>], bigZero); )</span><br><span class="line"> c = <span class="title function_">biDivideModulo</span>(c[<span class="number">0</span>], b),</span><br><span class="line"> d += <span class="title class_">String</span>(c[<span class="number">1</span>].<span class="property">digits</span>[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">return</span> (a.<span class="property">isNeg</span> ? <span class="string">"-"</span> : <span class="string">""</span>) + <span class="title function_">reverseStr</span>(d)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">digitToHex</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> b = <span class="number">15</span></span><br><span class="line"> , c = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; <span class="number">4</span> > i; ++i)</span><br><span class="line"> c += hexToChar[a & b],</span><br><span class="line"> a >>>= <span class="number">4</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">reverseStr</span>(c)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biToHex</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, b = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="title function_">biHighIndex</span>(a),</span><br><span class="line"> d = <span class="title function_">biHighIndex</span>(a); d > -<span class="number">1</span>; --d)</span><br><span class="line"> b += <span class="title function_">digitToHex</span>(a.<span class="property">digits</span>[d]);</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">charToHex</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> h, b = <span class="number">48</span>, c = b + <span class="number">9</span>, d = <span class="number">97</span>, e = d + <span class="number">25</span>, f = <span class="number">65</span>, g = <span class="number">90</span>;</span><br><span class="line"> <span class="keyword">return</span> h = a >= b && c >= a ? a - b : a >= f && g >= a ? <span class="number">10</span> + a - f : a >= d && e >= a ? <span class="number">10</span> + a - d : <span class="number">0</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">hexToDigit</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, b = <span class="number">0</span>, c = <span class="title class_">Math</span>.<span class="title function_">min</span>(a.<span class="property">length</span>, <span class="number">4</span>);</span><br><span class="line"> <span class="keyword">for</span> (d = <span class="number">0</span>; c > d; ++d)</span><br><span class="line"> b <<= <span class="number">4</span>,</span><br><span class="line"> b |= <span class="title function_">charToHex</span>(a.<span class="title function_">charCodeAt</span>(d));</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biFromHex</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, e, b = <span class="keyword">new</span> <span class="title class_">BigInt</span>, c = a.<span class="property">length</span>;</span><br><span class="line"> <span class="keyword">for</span> (d = c,</span><br><span class="line"> e = <span class="number">0</span>; d > <span class="number">0</span>; d -= <span class="number">4</span>,</span><br><span class="line"> ++e)</span><br><span class="line"> b.<span class="property">digits</span>[e] = <span class="title function_">hexToDigit</span>(a.<span class="title function_">substr</span>(<span class="title class_">Math</span>.<span class="title function_">max</span>(d - <span class="number">4</span>, <span class="number">0</span>), <span class="title class_">Math</span>.<span class="title function_">min</span>(d, <span class="number">4</span>)));</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biFromString</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> g, h, i, j, c = <span class="string">"-"</span> == a.<span class="title function_">charAt</span>(<span class="number">0</span>), d = c ? <span class="number">1</span> : <span class="number">0</span>, e = <span class="keyword">new</span> <span class="title class_">BigInt</span>, f = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (f.<span class="property">digits</span>[<span class="number">0</span>] = <span class="number">1</span>,</span><br><span class="line"> g = a.<span class="property">length</span> - <span class="number">1</span>; g >= d; g--)</span><br><span class="line"> h = a.<span class="title function_">charCodeAt</span>(g),</span><br><span class="line"> i = <span class="title function_">charToHex</span>(h),</span><br><span class="line"> j = <span class="title function_">biMultiplyDigit</span>(f, i),</span><br><span class="line"> e = <span class="title function_">biAdd</span>(e, j),</span><br><span class="line"> f = <span class="title function_">biMultiplyDigit</span>(f, b);</span><br><span class="line"> <span class="keyword">return</span> e.<span class="property">isNeg</span> = c,</span><br><span class="line"> e</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biDump</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">return</span> (a.<span class="property">isNeg</span> ? <span class="string">"-"</span> : <span class="string">""</span>) + a.<span class="property">digits</span>.<span class="title function_">join</span>(<span class="string">" "</span>)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biAdd</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c, d, e, f;</span><br><span class="line"> <span class="keyword">if</span> (a.<span class="property">isNeg</span> != b.<span class="property">isNeg</span>)</span><br><span class="line"> b.<span class="property">isNeg</span> = !b.<span class="property">isNeg</span>,</span><br><span class="line"> c = <span class="title function_">biSubtract</span>(a, b),</span><br><span class="line"> b.<span class="property">isNeg</span> = !b.<span class="property">isNeg</span>;</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">for</span> (c = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> d = <span class="number">0</span>,</span><br><span class="line"> f = <span class="number">0</span>; f < a.<span class="property">digits</span>.<span class="property">length</span>; ++f)</span><br><span class="line"> e = a.<span class="property">digits</span>[f] + b.<span class="property">digits</span>[f] + d,</span><br><span class="line"> c.<span class="property">digits</span>[f] = <span class="number">65535</span> & e,</span><br><span class="line"> d = <span class="title class_">Number</span>(e >= biRadix);</span><br><span class="line"> c.<span class="property">isNeg</span> = a.<span class="property">isNeg</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biSubtract</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c, d, e, f;</span><br><span class="line"> <span class="keyword">if</span> (a.<span class="property">isNeg</span> != b.<span class="property">isNeg</span>)</span><br><span class="line"> b.<span class="property">isNeg</span> = !b.<span class="property">isNeg</span>,</span><br><span class="line"> c = <span class="title function_">biAdd</span>(a, b),</span><br><span class="line"> b.<span class="property">isNeg</span> = !b.<span class="property">isNeg</span>;</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">for</span> (c = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> e = <span class="number">0</span>,</span><br><span class="line"> f = <span class="number">0</span>; f < a.<span class="property">digits</span>.<span class="property">length</span>; ++f)</span><br><span class="line"> d = a.<span class="property">digits</span>[f] - b.<span class="property">digits</span>[f] + e,</span><br><span class="line"> c.<span class="property">digits</span>[f] = <span class="number">65535</span> & d,</span><br><span class="line"> c.<span class="property">digits</span>[f] < <span class="number">0</span> && (c.<span class="property">digits</span>[f] += biRadix),</span><br><span class="line"> e = <span class="number">0</span> - <span class="title class_">Number</span>(<span class="number">0</span> > d);</span><br><span class="line"> <span class="keyword">if</span> (-<span class="number">1</span> == e) {</span><br><span class="line"> <span class="keyword">for</span> (e = <span class="number">0</span>,</span><br><span class="line"> f = <span class="number">0</span>; f < a.<span class="property">digits</span>.<span class="property">length</span>; ++f)</span><br><span class="line"> d = <span class="number">0</span> - c.<span class="property">digits</span>[f] + e,</span><br><span class="line"> c.<span class="property">digits</span>[f] = <span class="number">65535</span> & d,</span><br><span class="line"> c.<span class="property">digits</span>[f] < <span class="number">0</span> && (c.<span class="property">digits</span>[f] += biRadix),</span><br><span class="line"> e = <span class="number">0</span> - <span class="title class_">Number</span>(<span class="number">0</span> > d);</span><br><span class="line"> c.<span class="property">isNeg</span> = !a.<span class="property">isNeg</span></span><br><span class="line"> } <span class="keyword">else</span></span><br><span class="line"> c.<span class="property">isNeg</span> = a.<span class="property">isNeg</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biHighIndex</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> b = a.<span class="property">digits</span>.<span class="property">length</span> - <span class="number">1</span>; b > <span class="number">0</span> && <span class="number">0</span> == a.<span class="property">digits</span>[b]; )</span><br><span class="line"> --b;</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biNumBits</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> e, b = <span class="title function_">biHighIndex</span>(a), c = a.<span class="property">digits</span>[b], d = (b + <span class="number">1</span>) * bitsPerDigit;</span><br><span class="line"> <span class="keyword">for</span> (e = d; e > d - bitsPerDigit && <span class="number">0</span> == (<span class="number">32768</span> & c); --e)</span><br><span class="line"> c <<= <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> e</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biMultiply</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, h, i, k, c = <span class="keyword">new</span> <span class="title class_">BigInt</span>, e = <span class="title function_">biHighIndex</span>(a), f = <span class="title function_">biHighIndex</span>(b);</span><br><span class="line"> <span class="keyword">for</span> (k = <span class="number">0</span>; f >= k; ++k) {</span><br><span class="line"> <span class="keyword">for</span> (d = <span class="number">0</span>,</span><br><span class="line"> i = k,</span><br><span class="line"> j = <span class="number">0</span>; e >= j; ++j,</span><br><span class="line"> ++i)</span><br><span class="line"> h = c.<span class="property">digits</span>[i] + a.<span class="property">digits</span>[j] * b.<span class="property">digits</span>[k] + d,</span><br><span class="line"> c.<span class="property">digits</span>[i] = h & maxDigitVal,</span><br><span class="line"> d = h >>> biRadixBits;</span><br><span class="line"> c.<span class="property">digits</span>[k + e + <span class="number">1</span>] = d</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> c.<span class="property">isNeg</span> = a.<span class="property">isNeg</span> != b.<span class="property">isNeg</span>,</span><br><span class="line"> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biMultiplyDigit</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c, d, e, f;</span><br><span class="line"> <span class="keyword">for</span> (result = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> c = <span class="title function_">biHighIndex</span>(a),</span><br><span class="line"> d = <span class="number">0</span>,</span><br><span class="line"> f = <span class="number">0</span>; c >= f; ++f)</span><br><span class="line"> e = result.<span class="property">digits</span>[f] + a.<span class="property">digits</span>[f] * b + d,</span><br><span class="line"> result.<span class="property">digits</span>[f] = e & maxDigitVal,</span><br><span class="line"> d = e >>> biRadixBits;</span><br><span class="line"> <span class="keyword">return</span> result.<span class="property">digits</span>[<span class="number">1</span> + c] = d,</span><br><span class="line"> result</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">arrayCopy</span>(<span class="params">a, b, c, d, e</span>) {</span><br><span class="line"> <span class="keyword">var</span> g, h, f = <span class="title class_">Math</span>.<span class="title function_">min</span>(b + e, a.<span class="property">length</span>);</span><br><span class="line"> <span class="keyword">for</span> (g = b,</span><br><span class="line"> h = d; f > g; ++g,</span><br><span class="line"> ++h)</span><br><span class="line"> c[h] = a[g]</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biShiftLeft</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> e, f, g, h, c = <span class="title class_">Math</span>.<span class="title function_">floor</span>(b / bitsPerDigit), d = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="title function_">arrayCopy</span>(a.<span class="property">digits</span>, <span class="number">0</span>, d.<span class="property">digits</span>, c, d.<span class="property">digits</span>.<span class="property">length</span> - c),</span><br><span class="line"> e = b % bitsPerDigit,</span><br><span class="line"> f = bitsPerDigit - e,</span><br><span class="line"> g = d.<span class="property">digits</span>.<span class="property">length</span> - <span class="number">1</span>,</span><br><span class="line"> h = g - <span class="number">1</span>; g > <span class="number">0</span>; --g,</span><br><span class="line"> --h)</span><br><span class="line"> d.<span class="property">digits</span>[g] = d.<span class="property">digits</span>[g] << e & maxDigitVal | (d.<span class="property">digits</span>[h] & highBitMasks[e]) >>> f;</span><br><span class="line"> <span class="keyword">return</span> d.<span class="property">digits</span>[<span class="number">0</span>] = d.<span class="property">digits</span>[g] << e & maxDigitVal,</span><br><span class="line"> d.<span class="property">isNeg</span> = a.<span class="property">isNeg</span>,</span><br><span class="line"> d</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biShiftRight</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> e, f, g, h, c = <span class="title class_">Math</span>.<span class="title function_">floor</span>(b / bitsPerDigit), d = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="title function_">arrayCopy</span>(a.<span class="property">digits</span>, c, d.<span class="property">digits</span>, <span class="number">0</span>, a.<span class="property">digits</span>.<span class="property">length</span> - c),</span><br><span class="line"> e = b % bitsPerDigit,</span><br><span class="line"> f = bitsPerDigit - e,</span><br><span class="line"> g = <span class="number">0</span>,</span><br><span class="line"> h = g + <span class="number">1</span>; g < d.<span class="property">digits</span>.<span class="property">length</span> - <span class="number">1</span>; ++g,</span><br><span class="line"> ++h)</span><br><span class="line"> d.<span class="property">digits</span>[g] = d.<span class="property">digits</span>[g] >>> e | (d.<span class="property">digits</span>[h] & lowBitMasks[e]) << f;</span><br><span class="line"> <span class="keyword">return</span> d.<span class="property">digits</span>[d.<span class="property">digits</span>.<span class="property">length</span> - <span class="number">1</span>] >>>= e,</span><br><span class="line"> d.<span class="property">isNeg</span> = a.<span class="property">isNeg</span>,</span><br><span class="line"> d</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biMultiplyByRadixPower</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">arrayCopy</span>(a.<span class="property">digits</span>, <span class="number">0</span>, c.<span class="property">digits</span>, b, c.<span class="property">digits</span>.<span class="property">length</span> - b),</span><br><span class="line"> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biDivideByRadixPower</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">arrayCopy</span>(a.<span class="property">digits</span>, b, c.<span class="property">digits</span>, <span class="number">0</span>, c.<span class="property">digits</span>.<span class="property">length</span> - b),</span><br><span class="line"> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biModuloByRadixPower</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">arrayCopy</span>(a.<span class="property">digits</span>, <span class="number">0</span>, c.<span class="property">digits</span>, <span class="number">0</span>, b),</span><br><span class="line"> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biCompare</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">if</span> (a.<span class="property">isNeg</span> != b.<span class="property">isNeg</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span> - <span class="number">2</span> * <span class="title class_">Number</span>(a.<span class="property">isNeg</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> c = a.<span class="property">digits</span>.<span class="property">length</span> - <span class="number">1</span>; c >= <span class="number">0</span>; --c)</span><br><span class="line"> <span class="keyword">if</span> (a.<span class="property">digits</span>[c] != b.<span class="property">digits</span>[c])</span><br><span class="line"> <span class="keyword">return</span> a.<span class="property">isNeg</span> ? <span class="number">1</span> - <span class="number">2</span> * <span class="title class_">Number</span>(a.<span class="property">digits</span>[c] > b.<span class="property">digits</span>[c]) : <span class="number">1</span> - <span class="number">2</span> * <span class="title class_">Number</span>(a.<span class="property">digits</span>[c] < b.<span class="property">digits</span>[c]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biDivideModulo</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> f, g, h, i, j, k, l, m, n, o, p, q, r, s, c = <span class="title function_">biNumBits</span>(a), d = <span class="title function_">biNumBits</span>(b), e = b.<span class="property">isNeg</span>;</span><br><span class="line"> <span class="keyword">if</span> (d > c)</span><br><span class="line"> <span class="keyword">return</span> a.<span class="property">isNeg</span> ? (f = <span class="title function_">biCopy</span>(bigOne),</span><br><span class="line"> f.<span class="property">isNeg</span> = !b.<span class="property">isNeg</span>,</span><br><span class="line"> a.<span class="property">isNeg</span> = !<span class="number">1</span>,</span><br><span class="line"> b.<span class="property">isNeg</span> = !<span class="number">1</span>,</span><br><span class="line"> g = <span class="title function_">biSubtract</span>(b, a),</span><br><span class="line"> a.<span class="property">isNeg</span> = !<span class="number">0</span>,</span><br><span class="line"> b.<span class="property">isNeg</span> = e) : (f = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> g = <span class="title function_">biCopy</span>(a)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Array</span>(f,g);</span><br><span class="line"> <span class="keyword">for</span> (f = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> g = a,</span><br><span class="line"> h = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(d / bitsPerDigit) - <span class="number">1</span>,</span><br><span class="line"> i = <span class="number">0</span>; b.<span class="property">digits</span>[h] < biHalfRadix; )</span><br><span class="line"> b = <span class="title function_">biShiftLeft</span>(b, <span class="number">1</span>),</span><br><span class="line"> ++i,</span><br><span class="line"> ++d,</span><br><span class="line"> h = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(d / bitsPerDigit) - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (g = <span class="title function_">biShiftLeft</span>(g, i),</span><br><span class="line"> c += i,</span><br><span class="line"> j = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(c / bitsPerDigit) - <span class="number">1</span>,</span><br><span class="line"> k = <span class="title function_">biMultiplyByRadixPower</span>(b, j - h); -<span class="number">1</span> != <span class="title function_">biCompare</span>(g, k); )</span><br><span class="line"> ++f.<span class="property">digits</span>[j - h],</span><br><span class="line"> g = <span class="title function_">biSubtract</span>(g, k);</span><br><span class="line"> <span class="keyword">for</span> (l = j; l > h; --l) {</span><br><span class="line"> <span class="keyword">for</span> (m = l >= g.<span class="property">digits</span>.<span class="property">length</span> ? <span class="number">0</span> : g.<span class="property">digits</span>[l],</span><br><span class="line"> n = l - <span class="number">1</span> >= g.<span class="property">digits</span>.<span class="property">length</span> ? <span class="number">0</span> : g.<span class="property">digits</span>[l - <span class="number">1</span>],</span><br><span class="line"> o = l - <span class="number">2</span> >= g.<span class="property">digits</span>.<span class="property">length</span> ? <span class="number">0</span> : g.<span class="property">digits</span>[l - <span class="number">2</span>],</span><br><span class="line"> p = h >= b.<span class="property">digits</span>.<span class="property">length</span> ? <span class="number">0</span> : b.<span class="property">digits</span>[h],</span><br><span class="line"> q = h - <span class="number">1</span> >= b.<span class="property">digits</span>.<span class="property">length</span> ? <span class="number">0</span> : b.<span class="property">digits</span>[h - <span class="number">1</span>],</span><br><span class="line"> f.<span class="property">digits</span>[l - h - <span class="number">1</span>] = m == p ? maxDigitVal : <span class="title class_">Math</span>.<span class="title function_">floor</span>((m * biRadix + n) / p),</span><br><span class="line"> r = f.<span class="property">digits</span>[l - h - <span class="number">1</span>] * (p * biRadix + q),</span><br><span class="line"> s = m * biRadixSquared + (n * biRadix + o); r > s; )</span><br><span class="line"> --f.<span class="property">digits</span>[l - h - <span class="number">1</span>],</span><br><span class="line"> r = f.<span class="property">digits</span>[l - h - <span class="number">1</span>] * (p * biRadix | q),</span><br><span class="line"> s = m * biRadix * biRadix + (n * biRadix + o);</span><br><span class="line"> k = <span class="title function_">biMultiplyByRadixPower</span>(b, l - h - <span class="number">1</span>),</span><br><span class="line"> g = <span class="title function_">biSubtract</span>(g, <span class="title function_">biMultiplyDigit</span>(k, f.<span class="property">digits</span>[l - h - <span class="number">1</span>])),</span><br><span class="line"> g.<span class="property">isNeg</span> && (g = <span class="title function_">biAdd</span>(g, k),</span><br><span class="line"> --f.<span class="property">digits</span>[l - h - <span class="number">1</span>])</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> g = <span class="title function_">biShiftRight</span>(g, i),</span><br><span class="line"> f.<span class="property">isNeg</span> = a.<span class="property">isNeg</span> != e,</span><br><span class="line"> a.<span class="property">isNeg</span> && (f = e ? <span class="title function_">biAdd</span>(f, bigOne) : <span class="title function_">biSubtract</span>(f, bigOne),</span><br><span class="line"> b = <span class="title function_">biShiftRight</span>(b, i),</span><br><span class="line"> g = <span class="title function_">biSubtract</span>(b, g)),</span><br><span class="line"> <span class="number">0</span> == g.<span class="property">digits</span>[<span class="number">0</span>] && <span class="number">0</span> == <span class="title function_">biHighIndex</span>(g) && (g.<span class="property">isNeg</span> = !<span class="number">1</span>),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Array</span>(f,g)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biDivide</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">biDivideModulo</span>(a, b)[<span class="number">0</span>]</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biModulo</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">biDivideModulo</span>(a, b)[<span class="number">1</span>]</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biMultiplyMod</span>(<span class="params">a, b, c</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">biModulo</span>(<span class="title function_">biMultiply</span>(a, b), c)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biPow</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> c = bigOne, d = a; ; ) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">0</span> != (<span class="number">1</span> & b) && (c = <span class="title function_">biMultiply</span>(c, d)),</span><br><span class="line"> b >>= <span class="number">1</span>,</span><br><span class="line"> <span class="number">0</span> == b)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> d = <span class="title function_">biMultiply</span>(d, d)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">biPowMod</span>(<span class="params">a, b, c</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> d = bigOne, e = a, f = b; ; ) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">0</span> != (<span class="number">1</span> & f.<span class="property">digits</span>[<span class="number">0</span>]) && (d = <span class="title function_">biMultiplyMod</span>(d, e, c)),</span><br><span class="line"> f = <span class="title function_">biShiftRight</span>(f, <span class="number">1</span>),</span><br><span class="line"> <span class="number">0</span> == f.<span class="property">digits</span>[<span class="number">0</span>] && <span class="number">0</span> == <span class="title function_">biHighIndex</span>(f))</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> e = <span class="title function_">biMultiplyMod</span>(e, e, c)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">BarrettMu</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">modulus</span> = <span class="title function_">biCopy</span>(a),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">k</span> = <span class="title function_">biHighIndex</span>(<span class="variable language_">this</span>.<span class="property">modulus</span>) + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">var</span> b = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> b.<span class="property">digits</span>[<span class="number">2</span> * <span class="variable language_">this</span>.<span class="property">k</span>] = <span class="number">1</span>,</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">mu</span> = <span class="title function_">biDivide</span>(b, <span class="variable language_">this</span>.<span class="property">modulus</span>),</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">bkplus1</span> = <span class="keyword">new</span> <span class="title class_">BigInt</span>,</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">bkplus1</span>.<span class="property">digits</span>[<span class="variable language_">this</span>.<span class="property">k</span> + <span class="number">1</span>] = <span class="number">1</span>,</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">modulo</span> = <span class="title class_">BarrettMu</span>_modulo,</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">multiplyMod</span> = <span class="title class_">BarrettMu</span>_multiplyMod,</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">powMod</span> = <span class="title class_">BarrettMu</span>_powMod</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">BarrettMu_modulo</span>(<span class="params">a</span>) {</span><br><span class="line"> <span class="keyword">var</span> i, b = <span class="title function_">biDivideByRadixPower</span>(a, <span class="variable language_">this</span>.<span class="property">k</span> - <span class="number">1</span>), c = <span class="title function_">biMultiply</span>(b, <span class="variable language_">this</span>.<span class="property">mu</span>), d = <span class="title function_">biDivideByRadixPower</span>(c, <span class="variable language_">this</span>.<span class="property">k</span> + <span class="number">1</span>), e = <span class="title function_">biModuloByRadixPower</span>(a, <span class="variable language_">this</span>.<span class="property">k</span> + <span class="number">1</span>), f = <span class="title function_">biMultiply</span>(d, <span class="variable language_">this</span>.<span class="property">modulus</span>), g = <span class="title function_">biModuloByRadixPower</span>(f, <span class="variable language_">this</span>.<span class="property">k</span> + <span class="number">1</span>), h = <span class="title function_">biSubtract</span>(e, g);</span><br><span class="line"> <span class="keyword">for</span> (h.<span class="property">isNeg</span> && (h = <span class="title function_">biAdd</span>(h, <span class="variable language_">this</span>.<span class="property">bkplus1</span>)),</span><br><span class="line"> i = <span class="title function_">biCompare</span>(h, <span class="variable language_">this</span>.<span class="property">modulus</span>) >= <span class="number">0</span>; i; )</span><br><span class="line"> h = <span class="title function_">biSubtract</span>(h, <span class="variable language_">this</span>.<span class="property">modulus</span>),</span><br><span class="line"> i = <span class="title function_">biCompare</span>(h, <span class="variable language_">this</span>.<span class="property">modulus</span>) >= <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> h</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">BarrettMu_multiplyMod</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> c = <span class="title function_">biMultiply</span>(a, b);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">modulo</span>(c)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">BarrettMu_powMod</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">var</span> d, e, c = <span class="keyword">new</span> <span class="title class_">BigInt</span>;</span><br><span class="line"> <span class="keyword">for</span> (c.<span class="property">digits</span>[<span class="number">0</span>] = <span class="number">1</span>,</span><br><span class="line"> d = a,</span><br><span class="line"> e = b; ; ) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">0</span> != (<span class="number">1</span> & e.<span class="property">digits</span>[<span class="number">0</span>]) && (c = <span class="variable language_">this</span>.<span class="title function_">multiplyMod</span>(c, d)),</span><br><span class="line"> e = <span class="title function_">biShiftRight</span>(e, <span class="number">1</span>),</span><br><span class="line"> <span class="number">0</span> == e.<span class="property">digits</span>[<span class="number">0</span>] && <span class="number">0</span> == <span class="title function_">biHighIndex</span>(e))</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> d = <span class="variable language_">this</span>.<span class="title function_">multiplyMod</span>(d, d)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> c</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> maxDigits, <span class="variable constant_">ZERO_ARRAY</span>, bigZero, bigOne, dpl10, lr10, hexatrigesimalToChar, hexToChar, highBitMasks, lowBitMasks, biRadixBase = <span class="number">2</span>, biRadixBits = <span class="number">16</span>, bitsPerDigit = biRadixBits, biRadix = <span class="number">65536</span>, biHalfRadix = biRadix >>> <span class="number">1</span>, biRadixSquared = biRadix * biRadix, maxDigitVal = biRadix - <span class="number">1</span>, maxInteger = <span class="number">9999999999999998</span>;</span><br><span class="line"><span class="title function_">setMaxDigits</span>(<span class="number">20</span>),</span><br><span class="line">dpl10 = <span class="number">15</span>,</span><br><span class="line">lr10 = <span class="title function_">biFromNumber</span>(<span class="number">1e15</span>),</span><br><span class="line">hexatrigesimalToChar = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="string">"0"</span>,<span class="string">"1"</span>,<span class="string">"2"</span>,<span class="string">"3"</span>,<span class="string">"4"</span>,<span class="string">"5"</span>,<span class="string">"6"</span>,<span class="string">"7"</span>,<span class="string">"8"</span>,<span class="string">"9"</span>,<span class="string">"a"</span>,<span class="string">"b"</span>,<span class="string">"c"</span>,<span class="string">"d"</span>,<span class="string">"e"</span>,<span class="string">"f"</span>,<span class="string">"g"</span>,<span class="string">"h"</span>,<span class="string">"i"</span>,<span class="string">"j"</span>,<span class="string">"k"</span>,<span class="string">"l"</span>,<span class="string">"m"</span>,<span class="string">"n"</span>,<span class="string">"o"</span>,<span class="string">"p"</span>,<span class="string">"q"</span>,<span class="string">"r"</span>,<span class="string">"s"</span>,<span class="string">"t"</span>,<span class="string">"u"</span>,<span class="string">"v"</span>,<span class="string">"w"</span>,<span class="string">"x"</span>,<span class="string">"y"</span>,<span class="string">"z"</span>),</span><br><span class="line">hexToChar = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="string">"0"</span>,<span class="string">"1"</span>,<span class="string">"2"</span>,<span class="string">"3"</span>,<span class="string">"4"</span>,<span class="string">"5"</span>,<span class="string">"6"</span>,<span class="string">"7"</span>,<span class="string">"8"</span>,<span class="string">"9"</span>,<span class="string">"a"</span>,<span class="string">"b"</span>,<span class="string">"c"</span>,<span class="string">"d"</span>,<span class="string">"e"</span>,<span class="string">"f"</span>),</span><br><span class="line">highBitMasks = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="number">0</span>,<span class="number">32768</span>,<span class="number">49152</span>,<span class="number">57344</span>,<span class="number">61440</span>,<span class="number">63488</span>,<span class="number">64512</span>,<span class="number">65024</span>,<span class="number">65280</span>,<span class="number">65408</span>,<span class="number">65472</span>,<span class="number">65504</span>,<span class="number">65520</span>,<span class="number">65528</span>,<span class="number">65532</span>,<span class="number">65534</span>,<span class="number">65535</span>),</span><br><span class="line">lowBitMasks = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="number">0</span>,<span class="number">1</span>,<span class="number">3</span>,<span class="number">7</span>,<span class="number">15</span>,<span class="number">31</span>,<span class="number">63</span>,<span class="number">127</span>,<span class="number">255</span>,<span class="number">511</span>,<span class="number">1023</span>,<span class="number">2047</span>,<span class="number">4095</span>,<span class="number">8191</span>,<span class="number">16383</span>,<span class="number">32767</span>,<span class="number">65535</span>);</span><br></pre></td></tr></tbody></table></figure>
</details>
<p>至此,整个网易云逆向的思路已清晰。我们可以开始用 Python 来实现它了。</p>
<h1 id="用js生成数据"><a class="markdownIt-Anchor" href="#用js生成数据"></a> 用 JS 生成数据</h1>
<p>既然我们已经明白了网易云的加密方式,那么我们就可以先用 JS 来生成 <code>params</code> 和 <code>encSecKey</code>,然后再传到 Python 来发出请求。</p>
<blockquote>
<p>我使用的是 PyCharm;你可以新建一个 <code>.js</code> 文件并且使用 <code>node.exe</code> 来运行 JS 代码。</p>
</blockquote>
<p>首要的便是引入 <code>CryptoJS</code>,与 Python 导包一样,我们需要先下载它。在终端中输入:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install crypto-js</span><br></pre></td></tr></tbody></table></figure>
<p>之后便是引入它:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> <span class="title class_">CryptoJS</span> = <span class="built_in">require</span>(<span class="string">"crypto-js"</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>接着复制粘贴之前说的那一大串全局函数以及 <code>a()</code>、<code>b()</code>、<code>c()</code>、<code>d()</code> 函数下去。</p>
<p><code>d()</code> 函数所需要的变量中有三个是固定的,我们可以先定义好:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">key_2 = <span class="string">'010001'</span>;</span><br><span class="line">key_3 = <span class="string">'00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'</span>;</span><br><span class="line">key_4 = <span class="string">'0CoJUm6Qyw8W8jud'</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>而第一个参数中歌曲的 id 是动态的,我们可以先填写一个固定的 id 进去:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">key_1 = <span class="string">'{"ids": "[2094817741]", "level": "standard", "encodeType": "aac", "csrf_token": ""}'</span></span><br></pre></td></tr></tbody></table></figure>
<p>最后打印一下结果:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">d</span>(key_1, key_2, key_3, key_4));</span><br></pre></td></tr></tbody></table></figure>
<p><code>params</code> 和 <code>encSecKey</code> 就这么简单地生成出来了。不过仅是生成出来是不够的,我们还需要把它们传到 Python 里去。</p>
<h1 id="用python发出请求"><a class="markdownIt-Anchor" href="#用python发出请求"></a> 用 Python 发出请求</h1>
<p>为了让 Python 那边取到的数据即拿即用,我悄咪咪地加了一个函数:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">main</span>(<span class="params">key</span>) {</span><br><span class="line"> result = <span class="title function_">d</span>(key, key_2, key_3, key_4);</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="string">'params'</span>: result[<span class="string">'encText'</span>],</span><br><span class="line"> <span class="string">'encSecKey'</span>: result[<span class="string">'encSecKey'</span>]</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p>参数 <code>key</code> 的内容会在 Python 中进行修改。</p>
</blockquote>
<p>那么要如何让 Python 调用这个函数呢?我们可以使用 <code>PyExecJS</code> 这个库:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> execjs</span><br><span class="line"></span><br><span class="line">js_code = <span class="built_in">open</span>(<span class="string">'文件.js'</span>, mode=<span class="string">'r'</span>, encoding=<span class="string">'utf-8'</span>).read()</span><br><span class="line">ctx = execjs.<span class="built_in">compile</span>(js_code)</span><br></pre></td></tr></tbody></table></figure>
<p>这样我们便可以调用 <code>.js</code> 文件中的 <code>main()</code> 函数了:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">song_id = <span class="built_in">input</span>(<span class="string">'输入歌曲id:'</span>)</span><br><span class="line">key = <span class="string">'{"ids": "[%s]", "level": "standard", "encodeType": "aac", "csrf_token": ""}'</span> % song_id</span><br><span class="line">result = ctx.call(<span class="string">'main'</span>, key)</span><br></pre></td></tr></tbody></table></figure>
<p>给网易云发送请求:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">form_data = {</span><br><span class="line"> <span class="string">'params'</span>: result[<span class="string">'params'</span>],</span><br><span class="line"> <span class="string">'encSecKey'</span>: result[<span class="string">'encSecKey'</span>]</span><br><span class="line">}</span><br><span class="line">response = requests.post(</span><br><span class="line"> url=<span class="string">'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='</span>,</span><br><span class="line"> headers=headers, <span class="comment"># 自己定义</span></span><br><span class="line"> data=form_data</span><br><span class="line">).json()</span><br><span class="line">m4a_url = response[<span class="string">'data'</span>][<span class="number">0</span>][<span class="string">'url'</span>]</span><br></pre></td></tr></tbody></table></figure>
<p>拿到了我们的 <code>.m4a</code> 链接后,该怎么做嘛…… 我想也不用多说了吧。</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">m4a_response = requests.get(m4a_url, headers=headers).content</span><br><span class="line"><span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(<span class="string">'music'</span>):</span><br><span class="line"> os.mkdir(<span class="string">'music'</span>)</span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'music/%s.m4a'</span> % song_id, mode=<span class="string">'wb'</span>) <span class="keyword">as</span> fp:</span><br><span class="line"> fp.write(m4a_response)</span><br></pre></td></tr></tbody></table></figure>
<p>网易云逆向大功告成!</p>
<h1 id="顺便逆向个歌曲id不过分吧"><a class="markdownIt-Anchor" href="#顺便逆向个歌曲id不过分吧"></a> 顺便逆向个歌曲 id 不过分吧</h1>
<p>在网易云中,当用户进行搜索时会出现这么一个请求:<code>https://music.163.com/weapi/search/suggest/web?csrf_token=</code>。和 <code>.m4a</code> 文件请求一样,这个请求也需要 <code>params</code> 和 <code>encSecKey</code> 两个参数。我们可以使用同样的方法来生成它们。</p>
<p>该请求会根据用户输入的关键词返回搜索结果:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">title = <span class="built_in">input</span>(<span class="string">'请输入歌曲名:'</span>)</span><br><span class="line">search_key = <span class="string">'{"s": "%s", "limit": "8", "csrf_token": ""}'</span> % title</span><br><span class="line">result = ctx.call(<span class="string">'main'</span>, search_key)</span><br></pre></td></tr></tbody></table></figure>
<p>然后我们就可以拿到搜索结果了:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">response = requests.post(</span><br><span class="line"> url=<span class="string">'https://music.163.com/weapi/search/suggest/web?csrf_token='</span>,</span><br><span class="line"> params=result,</span><br><span class="line"> headers=headers</span><br><span class="line">).json()</span><br><span class="line"><span class="keyword">return</span> response[<span class="string">'result'</span>][<span class="string">'songs'</span>] <span class="comment"># 返回歌曲列表,response['result']['songs'][数字]['id']就是我们上面自己定义的song_id,完全可以串起来用</span></span><br></pre></td></tr></tbody></table></figure></body></html></div></article></div></main><footer><div class="paginator"><a class="prev" href="2f6a.html">上一篇</a><a class="next" href="a4b5.html">下一篇</a></div><!-- Webmention 显示区域--><div class="webmention-section webmention-empty" data-page-url="posts/f8ce.html" data-full-url="https://cytrogen.icu/posts/f8ce.html" data-mode="static">
<h3 class="webmention-title">Webmentions (<span class="webmention-count">0</span>)</h3>
<div class="webmention-list"></div>
<span>暂无 Webmentions</span>
</div><div class="copyright"><p class="footer-links"><a href="../friends/index.html">友链</a><span class="footer-separator"> ·</span><a href="../links/index.html">邻邦</a><span class="footer-separator"> ·</span><a href="../contact/index.html">联络</a><span class="footer-separator"> ·</span><a href="../colophon/index.html">营造记</a><span class="footer-separator"> ·</span><a href="../atom.xml">RSS订阅</a></p><p>© 2025 - 2026 <a href="https://cytrogen.icu">Cytrogen</a>, powered by <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/cytrogen/hexo-theme-ares" target="_blank">hexo-theme-ares</a>.</p><p><a href="https://blogscn.fun" target="_blank" rel="noopener">BLOGS·CN</a></p></div></footer></div></div><a class="back-to-top" href="#top" aria-label="返回顶部"><svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M3.293 9.707a1 1 0 010-1.414L9.586 2a2 2 0 012.828 0l6.293 6.293a1 1 0 01-1.414 1.414L11 3.414V17a1 1 0 11-2 0V3.414L2.707 9.707a1 1 0 01-1.414 0z"></path></svg></a><script>document.addEventListener('DOMContentLoaded', function() {
const codeBlocks = document.querySelectorAll('figure.highlight');
codeBlocks.forEach(block => {
let caption = block.querySelector('figcaption');
if (!caption) {
caption = document.createElement('figcaption');
block.insertBefore(caption, block.firstChild);
}
const info = document.createElement('div');
info.className = 'info';
const filename = caption.querySelector('span');
if (filename) {
filename.className = 'filename';
info.appendChild(filename);
}
const lang = block.className.split(' ')[1];
if (lang) {
const langSpan = document.createElement('span');
langSpan.className = 'lang-name';
langSpan.textContent = lang;
info.appendChild(langSpan);
}
const sourceLink = caption.querySelector('a');
if (sourceLink) {
sourceLink.className = 'source-link';
info.appendChild(sourceLink);
}
const actions = document.createElement('div');
actions.className = 'actions';
const codeHeight = block.scrollHeight;
const threshold = 300;
if (codeHeight > threshold) {
block.classList.add('folded');
const toggleBtn = document.createElement('button');
toggleBtn.textContent = '展开';
toggleBtn.addEventListener('click', () => {
block.classList.toggle('folded');
toggleBtn.textContent = block.classList.contains('folded') ? '展开' : '折叠';
});
actions.appendChild(toggleBtn);
}
const copyBtn = document.createElement('button');
copyBtn.textContent = '复制';
copyBtn.addEventListener('click', async () => {
const codeLines = block.querySelectorAll('.code .line');
const code = Array.from(codeLines)
.map(line => line.textContent)
.join('\n')
.replace(/\n\n/g, '\n');
try {
await navigator.clipboard.writeText(code);
copyBtn.textContent = '已复制';
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.textContent = '复制';
copyBtn.classList.remove('copied');
}, 3000);
} catch (err) {
console.error('复制失败:', err);
copyBtn.textContent = '复制失败';
setTimeout(() => {
copyBtn.textContent = '复制';
}, 3000);
}
});
actions.appendChild(copyBtn);
caption.innerHTML = '';
caption.appendChild(info);
caption.appendChild(actions);
const markedLines = block.getAttribute('data-marked-lines');
if (markedLines) {
const lines = markedLines.split(',');
lines.forEach(range => {
if (range.includes('-')) {
const [start, end] = range.split('-').map(Number);
for (let i = start; i <= end; i++) {
const line = block.querySelector(`.line-${i}`);
if (line) line.classList.add('marked');
}
} else {
const line = block.querySelector(`.line-${range}`);
if (line) line.classList.add('marked');
}
});
}
});
});</script><script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script><script>(function() {
document.addEventListener('DOMContentLoaded', function() {
const themeToggle = document.querySelector('.theme-toggle');
if (!themeToggle) return;
const getCurrentTheme = () => {
return document.documentElement.getAttribute('data-theme') || 'light';
};
const updateUI = (theme) => {
const isDark = theme === 'dark';
themeToggle.setAttribute('aria-pressed', isDark.toString());
};
const setTheme = (theme) => {
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.style.colorScheme = theme;
const pageWrapper = document.getElementById('page-wrapper');
if (pageWrapper) {
pageWrapper.setAttribute('data-theme', theme);
}
// Find and remove the temporary anti-flicker style tag if it exists.
// This ensures the main stylesheet takes full control after the initial load.
const antiFlickerStyle = document.getElementById('anti-flicker-style');
if (antiFlickerStyle) {
antiFlickerStyle.remove();
}
localStorage.setItem('theme', theme);
updateUI(theme);
};
const toggleTheme = () => {
const current = getCurrentTheme();
const newTheme = current === 'light' ? 'dark' : 'light';
setTheme(newTheme);
};
updateUI(getCurrentTheme());
themeToggle.addEventListener('click', toggleTheme);
if (window.matchMedia) {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', function(e) {
if (!localStorage.getItem('theme')) {
const theme = e.matches ? 'dark' : 'light';
setTheme(theme);
}
});
}
});
})();
</script><script src="../js/details-toggle.js" defer></script><script>(function() {
document.addEventListener('DOMContentLoaded', function() {
const backToTopBtn = document.querySelector('.back-to-top');
if (!backToTopBtn) return;
const toggleButtonVisibility = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const shouldShow = scrollTop > 200;
if (shouldShow) {
backToTopBtn.classList.add('is-visible');
} else {
backToTopBtn.classList.remove('is-visible');
}
};
let ticking = false;
const handleScroll = () => {
if (!ticking) {
requestAnimationFrame(() => {
toggleButtonVisibility();
ticking = false;
});
ticking = true;
}
};
const scrollToTop = (event) => {
event.preventDefault();
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
window.addEventListener('scroll', handleScroll);
backToTopBtn.addEventListener('click', scrollToTop);
toggleButtonVisibility();
});
})();</script></body></html>