JAVA版网易云音乐格式转换器

2024-03-27 00:20

本文主要是介绍JAVA版网易云音乐格式转换器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

网易云音乐下载的歌曲格式多为ncm,这种格式除了用网易云音乐App其他播放器无法播放。于是想寻求其格式转换的工具,搜索了下确实有相关工具,不过很多山寨工具需要收费。然后又试图寻求其他方式,经过一番调研发现这玩意其实早已经被人扒光了到处裸奔(我估摸着这个事情就是千防万防,家贼难防。因为基于目前ncm文件的加密方式,要根据其加密字节流去反推加密过程好像有点难,不知道搞破解的同学怎么看这个事情)。例如:《网易云VIP音乐NCM文件转MP3,C语言版本》https://blog.csdn.net/y123456wydhckd/article/details/128368486;于是索性自己动手搞个JAVA版的,然后顺带加上个重命名的功能。网易云音乐文件命名规则是:歌手名开头,这样下载后默认的排序就是按照歌手名,一直连着听某一个咖咖的歌谁都会觉得无趣(我一般都是开车的时候用U盘听歌),重命名的做法是:增加一个按文件名进行murmur哈希的前缀值,从而起到一个哈希散开的效果。

1. 网易云音乐文件加密概要

1.1 加密文件元数据定义

首先看下网易云音乐ncm文件元数据定义,其实通过NcmMetaData的定义及注释,大家就应该能大致知道如何去解密网易云音乐ncm文件了。

/*** NcmMetaData** @author chenx*/
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NcmMetaData {/*** 头信息:10 bytes* 数据结构不明(忽略)*/private byte[] magicHeader;/*** RC4密钥长度:4 bytes(字节小端排序)*/private int rc4KeyLength;/*** RC4密钥:var bytes* 1. 按字节对0x64异或。* 2. AES解密,去除填充部分。* 3. rc4Key硬编码干扰盐字符串(17字节):neteasecloudmusic* 4. RC4密钥: 剩余字节*/private Rc4Key rc4Key;/*** 音乐信息长度:4 bytes(字节小端排序)*/private int musicInfoLength;/*** 音乐信息:var bytes* 1. 按字节对0x63异或。* 2. 硬编码干扰盐字符串(22字节):163 key(Don't modify):* 3. Base64进行解码。* 4. AES解密。* 5. 硬编码Json前缀干扰字符串(6字节):music:* 6. Music对象Json字符串*/private CloudMusic cloudMusic;/*** CRC: 4 bytes*/private byte[] crc;/*** Gap: 5 bytes*/private byte[] gap;/*** 专辑图片大小:4 bytes(字节小端排序)*/private int albumImageSize;/*** 专辑图片:var bytes*/private byte[] albumImage;/*** 音频数据*/private byte[] audioData;
}

1.2 加密概要及总结

  • 加密概要
  1. 自定义了一个紧凑的数据结构,例如:10字节头、4字节密钥长度等;
  2. 自定义数据结构中的关键信息又进行自定义加密及编码,例如:音频数据加密密钥、音乐信息等;
  3. 自定义数据结构中加入了一些无用硬编码干扰盐字符串,例如:neteasecloudmusic、163 key(Don’t modify):等;
  4. NCM格式的加密文件中除了音频数据外还包含音乐附属信息,例如:专辑,歌手,歌名,图片等;
  5. 音频数据的加密密钥位于加密文件的自身之中,加密算法为性能相对AES较好的非标RC4加密算法;
  • 加密总结
    从以上几点可以看出其实网易云音乐NCM文件的加密其实基于都是一些经典老套路:
  • 通过自定义数据结构的方式将密钥置于加密文件自身之中,同时加入一些无关的盐做为干扰(网易云音乐有点low,都是一些硬编码的玩意);
  • 出于加解密效率考虑,选择了以异或运算为主的替换类加密算法(可以把异或运算理解为不进位的二进制加法,效率自然超高,对相同的东西进行二次异或即可得到原始值,因此基于异或的解密只需再来一次即可);
  • 对于密钥的管理则选择安全性较高的高级加密算法(网易云音乐选择的AES,一般来说对于密钥的管理推荐使用非对称的RSA或者ECC及其变种);

2. RC4加密算法

2.1 RC加密算法4简介

RC4 加密算法的核心思想是通过在初始状态下生成一个伪随机的字节流,然后将明文与这个字节流进行异或运算,从而得到密文。具体来说,RC4 算法包括两个主要步骤:
1. 密钥调度算法(Key Scheduling Algorithm,KSA):

  • 使用初始状态的 S-box(置换盒:Substitution Box)。
  • S-box 是一个包含 0 到 255 的数字的数组,初始状态下是有序的。
  • 根据给定的密钥,通过对 S-box 的多次置换和交换来打乱其顺序,生成一个混乱的 S-box。

2. 伪随机数生成算法(Pseudo-Random Generation Algorithm,PRGA):

  • 使用经过打乱的 S-box。
  • 利用 S-box 生成一个伪随机的字节流,这个字节流被用作密钥流。
  • 将明文与密钥流进行异或运算,得到密文。

2.2 RC加密算法4实现

在 Java 中,RC4 算法的实现通常并不包含在标准的 Java 加密库中,一个常用的 Java 加密库是 Bouncy Castle,Bouncy Castle 提供了丰富的密码学算法支持,包括 RC4。如果要使用Bouncy Castle进行标准RC4加解密,java11可以添加依赖(bouncycastle jdk版本太多了):

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15to18</artifactId><version>1.76</version>
</dependency>

需要补充说明的是:网易云音乐对于音频数据加密的RC4是一个非标的RC4,标准RC4中S-box(置换盒)是一个字节的数组,因此这里只能自己实现:

package cn.bossfriday.cloudmusic.converter.cipher;/*** RC4* <p>* RC4 加密算法的核心思想是通过在初始状态下生成一个伪随机的字节流,然后将明文与这个字节流进行异或运算,从而得到密文。* 具体来说,RC4 算法包括两个主要步骤:* 1. 密钥调度算法(Key Scheduling Algorithm,KSA):* * 使用初始状态的 S-box(置换盒: Substitution Box)。* * S-box 是一个包含 0 到 255 的数字的数组,初始状态下是有序的。* * 根据给定的密钥,通过对 S-box 的多次置换和交换来打乱其顺序,生成一个混乱的 S-box。* <p>* 2. 伪随机数生成算法(Pseudo-Random Generation Algorithm,PRGA):* * 使用经过打乱的 S-box。* * 利用 S-box 生成一个伪随机的字节流,这个字节流被用作密钥流。* * 将明文与密钥流进行异或运算,得到密文。** @author chenx*/
public class RC4 {private final int[] sBox = new int[256];/*** RC4密钥调度(RC4-KSA:Key Scheduling Algorithm)** @param key*/public void keySchedule(byte[] key) {int len = key.length;for (int i = 0; i < 256; i++) {this.sBox[i] = i;}int j = 0;for (int i = 0; i < 256; i++) {j = (j + this.sBox[i] + key[i % len]) & 0xff;int swap = this.sBox[i];this.sBox[i] = this.sBox[j];this.sBox[j] = swap;}}/*** RC4伪随机数生成(RC4-PRGA:Pseudo-Random Generation Algorithm)** @param data* @param length*/public void randomGenerate(byte[] data, int length) {int i = 0;int j = 0;for (int k = 0; k < length; k++) {i = (k + 1) & 0xff;j = (this.sBox[i] + i) & 0xff;data[k] ^= this.sBox[(this.sBox[i] + this.sBox[j]) & 0xff];}}
}

3. 源码及运行

3.1 源码

https://github.com/bossfriday/bossfriday-cloudmusic-converter

3.2 运行

为了方便大家本地调试,在项目中的ncm目录中已经放了3个ncm歌曲,大家可以按照以下方式进行本地调试:

  1. 运行:Bootstrap的main方法;
  2. 输入:1;
  3. 输入:ncm文件源文件夹路径、转换后文件夹路径;
    在这里插入图片描述

这篇关于JAVA版网易云音乐格式转换器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/850347

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Java字符串处理全解析(String、StringBuilder与StringBuffer)

《Java字符串处理全解析(String、StringBuilder与StringBuffer)》:本文主要介绍Java字符串处理全解析(String、StringBuilder与StringBu... 目录Java字符串处理全解析:String、StringBuilder与StringBuffer一、St

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt