Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
Jixun Wu | 016daa67a5 | |
Jixun Wu | 0b6165ef99 | |
Jixun Wu | 6031d31ac6 | |
Jixun Wu | 1dadf19431 | |
Jixun | b982f7114c | |
Jixun | f82ff8216b | |
Jixun | d00e205612 | |
Jixun | b387b07dbd | |
Jixun | 73ece28e90 | |
Jixun | 29885decca | |
Jixun | a0642714e3 | |
Jixun | bcd8590426 | |
Jixun | 76ea7ffb38 |
|
@ -14,8 +14,7 @@ jobs:
|
|||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16.x'
|
||||
registry-url: 'https://npm.pkg.github.com'
|
||||
scope: '@unlock-music'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- name: 📦 Install Dependencies
|
||||
run: npm ci
|
||||
- name: 🧾 Test
|
||||
|
@ -28,7 +27,7 @@ jobs:
|
|||
name: package
|
||||
path: '*.tgz'
|
||||
- name: 🚀 Publish Package
|
||||
run: npm publish
|
||||
run: npm publish --access public
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
|
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -1,4 +1,22 @@
|
|||
## v0.0.1
|
||||
## v0.0.1-R5
|
||||
|
||||
### Bug Fix
|
||||
|
||||
- Return null instead of throw an error on unsupported file.
|
||||
|
||||
## v0.0.1-R4
|
||||
|
||||
### Bug Fix
|
||||
|
||||
- Change of package name back to `@unlock-music` namespace.
|
||||
|
||||
## v0.0.1-R3
|
||||
|
||||
### Bug Fix
|
||||
|
||||
- remove static modifier to work with elder babel
|
||||
|
||||
## v0.0.1-R2
|
||||
|
||||
### New feature:
|
||||
|
||||
|
|
27
README.md
27
README.md
|
@ -1,5 +1,32 @@
|
|||
# JOOX-Crypto
|
||||
|
||||
Joox 加密处理库。
|
||||
|
||||
支持的加密版本:
|
||||
|
||||
- `E!04` - 加密版本 v4
|
||||
|
||||
## 安装 & 使用 (Install & Usage)
|
||||
|
||||
```sh
|
||||
npm i --save @unlock-music/joox-crypto
|
||||
```
|
||||
|
||||
```js
|
||||
const jooxFactory = require('@unlock-music-gh/joox-crypto');
|
||||
|
||||
const data = new Uint8Array(...);
|
||||
const decryptor = jooxFactory(data, '00000000000000000000000000000000');
|
||||
if (!decryptor) throw new Error('不支持的加密方案或不是 joox 加密的文件。');
|
||||
|
||||
/** @type {Uint8Array[]} */
|
||||
const decrypted = decryptor.decryptFile(data);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## English
|
||||
|
||||
A package to decrypt joox encrypted file.
|
||||
|
||||
Supported varient:
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "joox-crypto",
|
||||
"version": "1.0.0",
|
||||
"name": "@unlock-music/joox-crypto",
|
||||
"version": "0.0.1-R5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "joox-crypto",
|
||||
"version": "1.0.0",
|
||||
"name": "@unlock-music/joox-crypto",
|
||||
"version": "0.0.1-R5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crypto-js": "^4.1.1"
|
||||
|
@ -3338,9 +3338,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ms": {
|
||||
|
@ -6944,9 +6944,9 @@
|
|||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@unlock-music/joox-crypto",
|
||||
"type": "commonjs",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.1-R5",
|
||||
"description": "Crypto library to decrypt joox encrypted music files.",
|
||||
"main": "src/index.js",
|
||||
"types": "src/index.d.ts",
|
||||
|
@ -12,10 +12,7 @@
|
|||
"test": "jest -w 50% src",
|
||||
"prepare": "simple-git-hooks"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com"
|
||||
},
|
||||
"repository": "git://github.com/unlock-music/joox-crypto.git",
|
||||
"repository": "github:unlock-music/joox-crypto.git",
|
||||
"keywords": [
|
||||
"joox"
|
||||
],
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
const DecryptorV4 = require("../crypto/DecryptorV4");
|
||||
const jooxFactory = require("../index");
|
||||
|
||||
describe("package entry", () => {
|
||||
it("should return null on unsupported file", () => {
|
||||
const input = Buffer.from("E!99........", "utf-8");
|
||||
const decryptor = jooxFactory(input, "".padStart(32, "0"));
|
||||
expect(decryptor).toBeNull();
|
||||
});
|
||||
|
||||
it("should return an encryptor on v4 magic file", () => {
|
||||
const input = Buffer.from("E!04........", "utf-8");
|
||||
const decryptor = jooxFactory(input, "".padStart(32, "0"));
|
||||
expect(decryptor).toBeInstanceOf(DecryptorV4);
|
||||
});
|
||||
});
|
|
@ -1,9 +1,9 @@
|
|||
const { Uint8ArrayEncoder } = require("./utils");
|
||||
const { getAESSecretKey, decryptAESBlock } = require("./AES");
|
||||
|
||||
class DecryptorV4 {
|
||||
static BLOCK_SIZE = 0x100000 /* data size */ + 0x10 /* padding */;
|
||||
const BLOCK_SIZE = 0x100000 /* data size */ + 0x10; /* padding */
|
||||
|
||||
class DecryptorV4 {
|
||||
/**
|
||||
* Derive key from a given seed (user uuid 2)
|
||||
* @param {string} encryptionSeed
|
||||
|
@ -12,15 +12,6 @@ class DecryptorV4 {
|
|||
this.aesKey = getAESSecretKey(encryptionSeed, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if encryption is supported.
|
||||
* @param {Uint8Array} fileBody File body for detection
|
||||
*/
|
||||
static detect(fileBody) {
|
||||
const magic = Uint8ArrayEncoder.toUTF8(fileBody.slice(0, 4));
|
||||
return magic === "E!04";
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a given file.
|
||||
* @param {Uint8Array} fileBody file body
|
||||
|
@ -38,7 +29,7 @@ class DecryptorV4 {
|
|||
let bytesToDecrypt = fileBody.length;
|
||||
let i = /* magic */ 4 + /* orig_size */ 8;
|
||||
while (bytesToDecrypt > 0) {
|
||||
const blockSize = Math.min(DecryptorV4.BLOCK_SIZE, bytesToDecrypt);
|
||||
const blockSize = Math.min(BLOCK_SIZE, bytesToDecrypt);
|
||||
const block = fileBody.subarray(i, i + blockSize);
|
||||
const blockDecrypted = decryptAESBlock(this.aesKey, block);
|
||||
blocks.push(blockDecrypted);
|
||||
|
@ -50,4 +41,13 @@ class DecryptorV4 {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if encryption is supported.
|
||||
* @param {Uint8Array} fileBody File body for detection
|
||||
*/
|
||||
DecryptorV4.detect = (fileBody) => {
|
||||
const magic = Uint8ArrayEncoder.toUTF8(fileBody.slice(0, 4));
|
||||
return magic === "E!04";
|
||||
};
|
||||
|
||||
module.exports = DecryptorV4;
|
||||
|
|
|
@ -5,7 +5,7 @@ function jooxFactory(fileBody, seed) {
|
|||
return new DecryptorV4(seed);
|
||||
}
|
||||
|
||||
throw new Error("input file not supported or invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = jooxFactory;
|
||||
|
|
Loading…
Reference in New Issue