refactor: project file structure
This commit is contained in:
57
src/include/aes.h
Normal file
57
src/include/aes.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
class AES
|
||||
{
|
||||
|
||||
public:
|
||||
AES();
|
||||
AES(const unsigned char *key);
|
||||
virtual ~AES();
|
||||
void encrypt(const unsigned char data[16], unsigned char out[16]);
|
||||
void decrypt(const unsigned char data[16], unsigned char out[16]);
|
||||
|
||||
private:
|
||||
//
|
||||
int mNb;
|
||||
|
||||
// word length of the secret key used in one turn
|
||||
int mNk;
|
||||
|
||||
// number of turns
|
||||
int mNr;
|
||||
|
||||
// the secret key,which can be 16bytes,24bytes or 32bytes
|
||||
unsigned char mKey[32];
|
||||
|
||||
// the extended key,which can be 176bytes,208bytes,240bytes
|
||||
unsigned char mW[60][4];
|
||||
|
||||
static unsigned char sBox[];
|
||||
static unsigned char invSBox[];
|
||||
// constant
|
||||
static unsigned char rcon[];
|
||||
void setKey(const unsigned char *key);
|
||||
|
||||
void subBytes(unsigned char state[][4]);
|
||||
void shiftRows(unsigned char state[][4]);
|
||||
void mixColumns(unsigned char state[][4]);
|
||||
void addRoundKey(unsigned char state[][4], unsigned char w[][4]);
|
||||
|
||||
void invSubBytes(unsigned char state[][4]);
|
||||
void invShiftRows(unsigned char state[][4]);
|
||||
void invMixColumns(unsigned char state[][4]);
|
||||
|
||||
void keyExpansion();
|
||||
|
||||
//
|
||||
unsigned char GF28Multi(unsigned char s, unsigned char a);
|
||||
|
||||
void rotWord(unsigned char w[]);
|
||||
void subWord(unsigned char w[]);
|
||||
|
||||
// get the secret key
|
||||
void getKeyAt(unsigned char key[][4], int i);
|
||||
};
|
||||
97
src/include/base64.h
Normal file
97
src/include/base64.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef _MACARON_BASE64_H_
|
||||
#define _MACARON_BASE64_H_
|
||||
#include <cstdint>
|
||||
|
||||
#include <string>
|
||||
|
||||
static const char sEncodingTable[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
static const unsigned char kDecodingTable[] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
|
||||
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
|
||||
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
|
||||
};
|
||||
|
||||
class Base64 {
|
||||
public:
|
||||
|
||||
static std::string Encode(const std::string data) {
|
||||
size_t in_len = data.size();
|
||||
size_t out_len = 4 * ((in_len + 2) / 3);
|
||||
std::string ret(out_len, '\0');
|
||||
size_t i;
|
||||
char *p = const_cast<char*>(ret.c_str());
|
||||
|
||||
for (i = 0; i < in_len - 2; i += 3) {
|
||||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
|
||||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
|
||||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)];
|
||||
*p++ = sEncodingTable[data[i + 2] & 0x3F];
|
||||
}
|
||||
if (i < in_len) {
|
||||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
|
||||
if (i == (in_len - 1)) {
|
||||
*p++ = sEncodingTable[((data[i] & 0x3) << 4)];
|
||||
*p++ = '=';
|
||||
}
|
||||
else {
|
||||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
|
||||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
|
||||
}
|
||||
*p++ = '=';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::string Decode(const std::string& input, std::string& out) {
|
||||
size_t in_len = input.size();
|
||||
if (in_len % 4 != 0) return "Input data size is not a multiple of 4";
|
||||
|
||||
size_t out_len = in_len / 4 * 3;
|
||||
if (input[in_len - 1] == '=') out_len--;
|
||||
if (input[in_len - 2] == '=') out_len--;
|
||||
|
||||
out.resize(out_len);
|
||||
|
||||
for (size_t i = 0, j = 0; i < in_len;) {
|
||||
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
|
||||
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
|
||||
|
||||
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF;
|
||||
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF;
|
||||
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _MACARON_BASE64_H_ */
|
||||
277
src/include/cJSON.h
Normal file
277
src/include/cJSON.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 7
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type __stdcall
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
|
||||
#endif
|
||||
#else /* !WIN32 */
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check if the item is a string and return its valuestring */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/arrray that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
17
src/include/color.h
Normal file
17
src/include/color.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#define RESET "\033[0m"
|
||||
#define BLACK "\033[30m" /* Black */
|
||||
#define RED "\033[31m" /* Red */
|
||||
#define GREEN "\033[32m" /* Green */
|
||||
#define YELLOW "\033[33m" /* Yellow */
|
||||
#define BLUE "\033[34m" /* Blue */
|
||||
#define MAGENTA "\033[35m" /* Magenta */
|
||||
#define CYAN "\033[36m" /* Cyan */
|
||||
#define WHITE "\033[37m" /* White */
|
||||
#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */
|
||||
#define BOLDRED "\033[1m\033[31m" /* Bold Red */
|
||||
#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */
|
||||
#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */
|
||||
#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */
|
||||
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
|
||||
#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */
|
||||
#define BOLDWHITE "\033[1m\033[37m" /* Bold White */
|
||||
71
src/include/ncmcrypt.h
Normal file
71
src/include/ncmcrypt.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "aes.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
class NeteaseMusicMetadata {
|
||||
|
||||
private:
|
||||
std::string mAlbum;
|
||||
std::string mArtist;
|
||||
std::string mFormat;
|
||||
std::string mName;
|
||||
int mDuration;
|
||||
int mBitrate;
|
||||
|
||||
private:
|
||||
cJSON* mRaw;
|
||||
|
||||
public:
|
||||
NeteaseMusicMetadata(cJSON*);
|
||||
~NeteaseMusicMetadata();
|
||||
const std::string& name() const { return mName; }
|
||||
const std::string& album() const { return mAlbum; }
|
||||
const std::string& artist() const { return mArtist; }
|
||||
const std::string& format() const { return mFormat; }
|
||||
const int duration() const { return mDuration; }
|
||||
const int bitrate() const { return mBitrate; }
|
||||
|
||||
};
|
||||
|
||||
class NeteaseCrypt {
|
||||
|
||||
private:
|
||||
static const unsigned char sCoreKey[17];
|
||||
static const unsigned char sModifyKey[17];
|
||||
static const unsigned char mPng[8];
|
||||
enum NcmFormat { MP3, FLAC };
|
||||
|
||||
private:
|
||||
std::string mFilepath;
|
||||
std::filesystem::path mDumpFilepath;
|
||||
NcmFormat mFormat;
|
||||
std::string mImageData;
|
||||
std::ifstream mFile;
|
||||
unsigned char mKeyBox[256];
|
||||
NeteaseMusicMetadata* mMetaData;
|
||||
|
||||
private:
|
||||
bool isNcmFile();
|
||||
bool openFile(std::string const&);
|
||||
int read(char *s, std::streamsize n);
|
||||
void buildKeyBox(unsigned char *key, int keyLen);
|
||||
std::string mimeType(std::string& data);
|
||||
|
||||
public:
|
||||
const std::string& filepath() const { return mFilepath; }
|
||||
const std::filesystem::path dumpFilepath() const { return mDumpFilepath; }
|
||||
|
||||
public:
|
||||
NeteaseCrypt(std::string const&);
|
||||
~NeteaseCrypt();
|
||||
|
||||
public:
|
||||
void Dump();
|
||||
void FixMetadata();
|
||||
};
|
||||
7
src/include/platform.h
Normal file
7
src/include/platform.h
Normal file
@@ -0,0 +1,7 @@
|
||||
# ifdef _WIN32
|
||||
/*
|
||||
* Win32-specific argv initialization that splits OS-supplied UNICODE
|
||||
* command line string to array of UTF8-encoded strings.
|
||||
*/
|
||||
void win32_utf8argv(int *argc, char **argv[]);
|
||||
# endif
|
||||
124
src/main.cpp
Normal file
124
src/main.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "ncmcrypt.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "platform.h"
|
||||
#endif
|
||||
|
||||
#include "color.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
void displayHelp()
|
||||
{
|
||||
std::cout << "Usage: ncmdump [-d] [-h] file1 file2 ..." << std::endl;
|
||||
std::cout << "Options:" << std::endl;
|
||||
std::cout << " -d Process files in a folder (requires folder path)" << std::endl;
|
||||
std::cout << " -h, --help Display this help message" << std::endl;
|
||||
}
|
||||
|
||||
void processFile(const fs::path &filePath)
|
||||
{
|
||||
if (fs::exists(filePath) == false)
|
||||
{
|
||||
std::cerr << BOLDRED << "Error: " << RESET << "file '" << filePath.u8string() << "' does not exist." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NeteaseCrypt crypt(filePath.u8string());
|
||||
crypt.Dump();
|
||||
crypt.FixMetadata();
|
||||
|
||||
std::cout << BOLDGREEN << "Done: " << RESET << "'" << crypt.dumpFilepath().u8string() << "'" << std::endl;
|
||||
}
|
||||
catch (const std::invalid_argument &e)
|
||||
{
|
||||
std::cerr << BOLDRED << "Exception: " << RESET << RED << e.what() << RESET << " '" << filePath.u8string() << "'" << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << BOLDRED << "Unexpected exception while processing file: " << RESET << filePath.u8string() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void processFilesInFolder(const fs::path &folderPath)
|
||||
{
|
||||
for (const auto &entry : fs::directory_iterator(folderPath))
|
||||
{
|
||||
if (fs::is_regular_file(entry.status()))
|
||||
{
|
||||
processFile(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
win32_utf8argv(&argc, &argv);
|
||||
#endif
|
||||
if (argc <= 1)
|
||||
{
|
||||
displayHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<fs::path> files;
|
||||
bool processFolders = false;
|
||||
|
||||
bool folderProvided = false;
|
||||
|
||||
#define COMPARE_STR(s1, s2) (strcmp(s1, s2) == 0)
|
||||
#define HELP_SHORT "-h"
|
||||
#define HELP_LONG "--help"
|
||||
#define PROCESS_FOLDER "-d"
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (COMPARE_STR(argv[i], HELP_SHORT) || COMPARE_STR(argv[i], HELP_LONG))
|
||||
{
|
||||
displayHelp();
|
||||
return 0;
|
||||
}
|
||||
else if (COMPARE_STR(argv[i], PROCESS_FOLDER))
|
||||
{
|
||||
processFolders = true;
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-')
|
||||
{
|
||||
folderProvided = true;
|
||||
processFilesInFolder(argv[i + 1]);
|
||||
// Skip the folder name
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: -d option requires a folder path." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::path path = fs::u8path(argv[i]);
|
||||
files.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &file : files)
|
||||
{
|
||||
if (processFolders && fs::is_directory(file))
|
||||
{
|
||||
processFilesInFolder(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
processFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
412
src/ncmcrypt.cpp
Normal file
412
src/ncmcrypt.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
#include "ncmcrypt.h"
|
||||
#include "aes.h"
|
||||
#include "base64.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#define TAGLIB_STATIC
|
||||
#include "taglib/toolkit/tfile.h"
|
||||
#include "taglib/mpeg/mpegfile.h"
|
||||
#include "taglib/flac/flacfile.h"
|
||||
#include "taglib/mpeg/id3v2/frames/attachedpictureframe.h"
|
||||
#include "taglib/mpeg/id3v2/id3v2tag.h"
|
||||
#include "taglib/tag.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
const unsigned char NeteaseCrypt::sCoreKey[17] = {0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57, 0};
|
||||
const unsigned char NeteaseCrypt::sModifyKey[17] = {0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28, 0};
|
||||
|
||||
const unsigned char NeteaseCrypt::mPng[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||
|
||||
static void aesEcbDecrypt(const unsigned char *key, std::string &src, std::string &dst)
|
||||
{
|
||||
int n, i;
|
||||
|
||||
unsigned char out[16];
|
||||
|
||||
n = src.length() >> 4;
|
||||
|
||||
dst.clear();
|
||||
|
||||
AES aes(key);
|
||||
|
||||
for (i = 0; i < n - 1; i++)
|
||||
{
|
||||
aes.decrypt((unsigned char *)src.c_str() + (i << 4), out);
|
||||
dst += std::string((char *)out, 16);
|
||||
}
|
||||
|
||||
aes.decrypt((unsigned char *)src.c_str() + (i << 4), out);
|
||||
char pad = out[15];
|
||||
if (pad > 16)
|
||||
{
|
||||
pad = 0;
|
||||
}
|
||||
dst += std::string((char *)out, 16 - pad);
|
||||
}
|
||||
|
||||
static void replace(std::string &str, const std::string &from, const std::string &to)
|
||||
{
|
||||
if (from.empty())
|
||||
return;
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = str.find(from, start_pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
NeteaseMusicMetadata::~NeteaseMusicMetadata()
|
||||
{
|
||||
cJSON_Delete(mRaw);
|
||||
}
|
||||
|
||||
NeteaseMusicMetadata::NeteaseMusicMetadata(cJSON *raw)
|
||||
{
|
||||
if (!raw)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON *swap;
|
||||
int artistLen, i;
|
||||
|
||||
mRaw = raw;
|
||||
|
||||
swap = cJSON_GetObjectItem(raw, "musicName");
|
||||
if (swap)
|
||||
{
|
||||
mName = std::string(cJSON_GetStringValue(swap));
|
||||
}
|
||||
|
||||
swap = cJSON_GetObjectItem(raw, "album");
|
||||
if (swap)
|
||||
{
|
||||
mAlbum = std::string(cJSON_GetStringValue(swap));
|
||||
}
|
||||
|
||||
swap = cJSON_GetObjectItem(raw, "artist");
|
||||
if (swap)
|
||||
{
|
||||
artistLen = cJSON_GetArraySize(swap);
|
||||
|
||||
i = 0;
|
||||
for (i = 0; i < artistLen; i++)
|
||||
{
|
||||
auto artist = cJSON_GetArrayItem(swap, i);
|
||||
if (cJSON_GetArraySize(artist) > 0)
|
||||
{
|
||||
if (!mArtist.empty())
|
||||
{
|
||||
mArtist += "/";
|
||||
}
|
||||
mArtist += std::string(cJSON_GetStringValue(cJSON_GetArrayItem(artist, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
swap = cJSON_GetObjectItem(raw, "bitrate");
|
||||
if (swap)
|
||||
{
|
||||
mBitrate = swap->valueint;
|
||||
}
|
||||
|
||||
swap = cJSON_GetObjectItem(raw, "duration");
|
||||
if (swap)
|
||||
{
|
||||
mDuration = swap->valueint;
|
||||
}
|
||||
|
||||
swap = cJSON_GetObjectItem(raw, "format");
|
||||
if (swap)
|
||||
{
|
||||
mFormat = std::string(cJSON_GetStringValue(swap));
|
||||
}
|
||||
}
|
||||
|
||||
bool NeteaseCrypt::openFile(std::string const &path)
|
||||
{
|
||||
mFile.open(std::filesystem::u8path(path), std::ios::in | std::ios::binary);
|
||||
if (!mFile.is_open())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool NeteaseCrypt::isNcmFile()
|
||||
{
|
||||
unsigned int header;
|
||||
|
||||
mFile.read(reinterpret_cast<char *>(&header), sizeof(header));
|
||||
if (header != (unsigned int)0x4e455443)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mFile.read(reinterpret_cast<char *>(&header), sizeof(header));
|
||||
if (header != (unsigned int)0x4d414446)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NeteaseCrypt::read(char *s, std::streamsize n)
|
||||
{
|
||||
mFile.read(s, n);
|
||||
|
||||
int gcount = mFile.gcount();
|
||||
|
||||
if (gcount <= 0)
|
||||
{
|
||||
throw std::invalid_argument("Can't read file");
|
||||
}
|
||||
|
||||
return gcount;
|
||||
}
|
||||
|
||||
void NeteaseCrypt::buildKeyBox(unsigned char *key, int keyLen)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
mKeyBox[i] = (unsigned char)i;
|
||||
}
|
||||
|
||||
unsigned char swap = 0;
|
||||
unsigned char c = 0;
|
||||
unsigned char last_byte = 0;
|
||||
unsigned char key_offset = 0;
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
swap = mKeyBox[i];
|
||||
c = ((swap + last_byte + key[key_offset++]) & 0xff);
|
||||
if (key_offset >= keyLen)
|
||||
key_offset = 0;
|
||||
mKeyBox[i] = mKeyBox[c];
|
||||
mKeyBox[c] = swap;
|
||||
last_byte = c;
|
||||
}
|
||||
}
|
||||
|
||||
std::string NeteaseCrypt::mimeType(std::string &data)
|
||||
{
|
||||
if (memcmp(data.c_str(), mPng, 8) == 0)
|
||||
{
|
||||
return std::string("image/png");
|
||||
}
|
||||
|
||||
return std::string("image/jpeg");
|
||||
}
|
||||
|
||||
void NeteaseCrypt::FixMetadata()
|
||||
{
|
||||
|
||||
TagLib::File *audioFile;
|
||||
TagLib::Tag *tag;
|
||||
TagLib::ByteVector vector(mImageData.c_str(), mImageData.length());
|
||||
|
||||
if (mFormat == NeteaseCrypt::MP3)
|
||||
{
|
||||
audioFile = new TagLib::MPEG::File(mDumpFilepath.c_str());
|
||||
tag = dynamic_cast<TagLib::MPEG::File *>(audioFile)->ID3v2Tag(true);
|
||||
|
||||
if (mImageData.length() > 0)
|
||||
{
|
||||
TagLib::ID3v2::AttachedPictureFrame *frame = new TagLib::ID3v2::AttachedPictureFrame;
|
||||
|
||||
frame->setMimeType(mimeType(mImageData));
|
||||
frame->setPicture(vector);
|
||||
|
||||
dynamic_cast<TagLib::ID3v2::Tag *>(tag)->addFrame(frame);
|
||||
}
|
||||
}
|
||||
else if (mFormat == NeteaseCrypt::FLAC)
|
||||
{
|
||||
audioFile = new TagLib::FLAC::File(mDumpFilepath.c_str());
|
||||
tag = audioFile->tag();
|
||||
|
||||
if (mImageData.length() > 0)
|
||||
{
|
||||
TagLib::FLAC::Picture *cover = new TagLib::FLAC::Picture;
|
||||
cover->setMimeType(mimeType(mImageData));
|
||||
cover->setType(TagLib::FLAC::Picture::FrontCover);
|
||||
cover->setData(vector);
|
||||
|
||||
dynamic_cast<TagLib::FLAC::File *>(audioFile)->addPicture(cover);
|
||||
}
|
||||
}
|
||||
|
||||
if (mMetaData != NULL)
|
||||
{
|
||||
tag->setTitle(TagLib::String(mMetaData->name(), TagLib::String::UTF8));
|
||||
tag->setArtist(TagLib::String(mMetaData->artist(), TagLib::String::UTF8));
|
||||
tag->setAlbum(TagLib::String(mMetaData->album(), TagLib::String::UTF8));
|
||||
}
|
||||
|
||||
tag->setComment(TagLib::String("Create by netease copyright protected dump tool. author 5L", TagLib::String::UTF8));
|
||||
|
||||
audioFile->save();
|
||||
}
|
||||
|
||||
void NeteaseCrypt::Dump()
|
||||
{
|
||||
mDumpFilepath = std::filesystem::u8path(mFilepath);
|
||||
|
||||
std::vector<unsigned char> buffer(0x8000);
|
||||
|
||||
std::ofstream output;
|
||||
|
||||
while (!mFile.eof())
|
||||
{
|
||||
int n = read((char *)buffer.data(), buffer.size());
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int j = (i + 1) & 0xff;
|
||||
buffer[i] ^= mKeyBox[(mKeyBox[j] + mKeyBox[(mKeyBox[j] + j) & 0xff]) & 0xff];
|
||||
}
|
||||
|
||||
if (!output.is_open())
|
||||
{
|
||||
// identify format
|
||||
// ID3 format mp3
|
||||
if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x33)
|
||||
{
|
||||
mDumpFilepath = mDumpFilepath.replace_extension("mp3");
|
||||
mFormat = NeteaseCrypt::MP3;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDumpFilepath = mDumpFilepath.replace_extension("flac");
|
||||
mFormat = NeteaseCrypt::FLAC;
|
||||
}
|
||||
|
||||
output.open(mDumpFilepath, output.out | output.binary);
|
||||
}
|
||||
|
||||
output.write((char *)buffer.data(), n);
|
||||
}
|
||||
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
|
||||
NeteaseCrypt::~NeteaseCrypt()
|
||||
{
|
||||
if (mMetaData != NULL)
|
||||
{
|
||||
delete mMetaData;
|
||||
}
|
||||
|
||||
mFile.close();
|
||||
}
|
||||
|
||||
NeteaseCrypt::NeteaseCrypt(std::string const &path)
|
||||
{
|
||||
if (!openFile(path))
|
||||
{
|
||||
throw std::invalid_argument("Can't open file");
|
||||
}
|
||||
|
||||
if (!isNcmFile())
|
||||
{
|
||||
throw std::invalid_argument("Not netease protected file");
|
||||
}
|
||||
|
||||
if (!mFile.seekg(2, mFile.cur))
|
||||
{
|
||||
throw std::invalid_argument("Can't seek file");
|
||||
}
|
||||
|
||||
mFilepath = path;
|
||||
|
||||
unsigned int n;
|
||||
read(reinterpret_cast<char *>(&n), sizeof(n));
|
||||
|
||||
if (n <= 0)
|
||||
{
|
||||
throw std::invalid_argument("Broken NCM file");
|
||||
}
|
||||
|
||||
std::vector<char> keydata(n);
|
||||
read(keydata.data(), n);
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
keydata[i] ^= 0x64;
|
||||
}
|
||||
|
||||
std::string rawKeyData(keydata.begin(), keydata.end());
|
||||
std::string mKeyData;
|
||||
|
||||
aesEcbDecrypt(sCoreKey, rawKeyData, mKeyData);
|
||||
|
||||
buildKeyBox((unsigned char *)mKeyData.c_str() + 17, mKeyData.length() - 17);
|
||||
|
||||
read(reinterpret_cast<char *>(&n), sizeof(n));
|
||||
|
||||
if (n <= 0)
|
||||
{
|
||||
std::cout << "[Warn] " << path << " missing metadata infomation can't fix some infomation!" << std::endl;
|
||||
|
||||
mMetaData = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<char> modifyData(n);
|
||||
read(modifyData.data(), n);
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
modifyData[i] ^= 0x63;
|
||||
}
|
||||
|
||||
std::string swapModifyData;
|
||||
std::string modifyOutData;
|
||||
std::string modifyDecryptData;
|
||||
|
||||
swapModifyData = std::string(modifyData.begin() + 22, modifyData.end());
|
||||
|
||||
// escape `163 key(Don't modify):`
|
||||
Base64::Decode(swapModifyData, modifyOutData);
|
||||
|
||||
aesEcbDecrypt(sModifyKey, modifyOutData, modifyDecryptData);
|
||||
|
||||
// escape `music:`
|
||||
modifyDecryptData = std::string(modifyDecryptData.begin() + 6, modifyDecryptData.end());
|
||||
|
||||
// std::cout << modifyDecryptData << std::endl;
|
||||
|
||||
mMetaData = new NeteaseMusicMetadata(cJSON_Parse(modifyDecryptData.c_str()));
|
||||
}
|
||||
|
||||
// skip crc32 & unuse charset
|
||||
if (!mFile.seekg(9, mFile.cur))
|
||||
{
|
||||
throw std::invalid_argument("can't seek file");
|
||||
}
|
||||
|
||||
read(reinterpret_cast<char *>(&n), sizeof(n));
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
char *imageData = (char *)malloc(n);
|
||||
read(imageData, n);
|
||||
|
||||
mImageData = std::string(imageData, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "[Warn] " << path << " missing album can't fix album image!" << std::endl;
|
||||
}
|
||||
}
|
||||
296
src/platform/win32_init.cpp
Normal file
296
src/platform/win32_init.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(CP_UTF8)
|
||||
|
||||
static UINT saved_cp;
|
||||
static int newargc;
|
||||
static char **newargv;
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
SetConsoleOutputCP(saved_cp);
|
||||
|
||||
for (i = 0; i < newargc; i++)
|
||||
free(newargv[i]);
|
||||
|
||||
free(newargv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Incrementally [re]allocate newargv and keep it NULL-terminated.
|
||||
*/
|
||||
static int validate_argv(int argc)
|
||||
{
|
||||
static int size = 0;
|
||||
|
||||
if (argc >= size) {
|
||||
char **ptr;
|
||||
|
||||
while (argc >= size)
|
||||
size += 64;
|
||||
|
||||
ptr = (char**)realloc(newargv, size * sizeof(newargv[0]));
|
||||
if (ptr == NULL)
|
||||
return 0;
|
||||
|
||||
(newargv = ptr)[argc] = NULL;
|
||||
} else {
|
||||
newargv[argc] = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_glob(WCHAR *wstr, int wlen)
|
||||
{
|
||||
int i, slash, udlen;
|
||||
WCHAR saved_char;
|
||||
WIN32_FIND_DATAW data;
|
||||
HANDLE h;
|
||||
|
||||
/*
|
||||
* Note that we support wildcard characters only in filename part
|
||||
* of the path, and not in directories. Windows users are used to
|
||||
* this, that's why recursive glob processing is not implemented.
|
||||
*/
|
||||
/*
|
||||
* Start by looking for last slash or backslash, ...
|
||||
*/
|
||||
for (slash = 0, i = 0; i < wlen; i++)
|
||||
if (wstr[i] == L'/' || wstr[i] == L'\\')
|
||||
slash = i + 1;
|
||||
/*
|
||||
* ... then look for asterisk or question mark in the file name.
|
||||
*/
|
||||
for (i = slash; i < wlen; i++)
|
||||
if (wstr[i] == L'*' || wstr[i] == L'?')
|
||||
break;
|
||||
|
||||
if (i == wlen)
|
||||
return 0; /* definitely not a glob */
|
||||
|
||||
saved_char = wstr[wlen];
|
||||
wstr[wlen] = L'\0';
|
||||
h = FindFirstFileW(wstr, &data);
|
||||
wstr[wlen] = saved_char;
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return 0; /* not a valid glob, just pass... */
|
||||
|
||||
if (slash)
|
||||
udlen = WideCharToMultiByte(CP_UTF8, 0, wstr, slash,
|
||||
NULL, 0, NULL, NULL);
|
||||
else
|
||||
udlen = 0;
|
||||
|
||||
do {
|
||||
int uflen;
|
||||
char *arg;
|
||||
|
||||
/*
|
||||
* skip over . and ..
|
||||
*/
|
||||
if (data.cFileName[0] == L'.') {
|
||||
if ((data.cFileName[1] == L'\0') ||
|
||||
(data.cFileName[1] == L'.' && data.cFileName[2] == L'\0'))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!validate_argv(newargc + 1))
|
||||
break;
|
||||
|
||||
/*
|
||||
* -1 below means "scan for trailing '\0' *and* count it",
|
||||
* so that |uflen| covers even trailing '\0'.
|
||||
*/
|
||||
uflen = WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1,
|
||||
NULL, 0, NULL, NULL);
|
||||
|
||||
arg = (char*)malloc(udlen + uflen);
|
||||
if (arg == NULL)
|
||||
break;
|
||||
|
||||
if (udlen)
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, slash,
|
||||
arg, udlen, NULL, NULL);
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1,
|
||||
arg + udlen, uflen, NULL, NULL);
|
||||
|
||||
newargv[newargc++] = arg;
|
||||
} while (FindNextFileW(h, &data));
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void win32_utf8argv(int *argc, char **argv[])
|
||||
{
|
||||
const WCHAR *wcmdline;
|
||||
WCHAR *warg, *wend, *p;
|
||||
int wlen, ulen, valid = 1;
|
||||
char *arg;
|
||||
|
||||
newargc = 0;
|
||||
newargv = NULL;
|
||||
if (!validate_argv(newargc))
|
||||
return;
|
||||
|
||||
wcmdline = GetCommandLineW();
|
||||
if (wcmdline == NULL) return;
|
||||
|
||||
/*
|
||||
* make a copy of the command line, since we might have to modify it...
|
||||
*/
|
||||
wlen = wcslen(wcmdline);
|
||||
p = (WCHAR*)_alloca((wlen + 1) * sizeof(WCHAR));
|
||||
wcscpy(p, wcmdline);
|
||||
|
||||
while (*p != L'\0') {
|
||||
int in_quote = 0;
|
||||
|
||||
if (*p == L' ' || *p == L'\t') {
|
||||
p++; /* skip over whitespace */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: because we may need to fiddle with the number of backslashes,
|
||||
* the argument string is copied into itself. This is safe because
|
||||
* the number of characters will never expand.
|
||||
*/
|
||||
warg = wend = p;
|
||||
while (*p != L'\0'
|
||||
&& (in_quote || (*p != L' ' && *p != L'\t'))) {
|
||||
switch (*p) {
|
||||
case L'\\':
|
||||
/*
|
||||
* Microsoft documentation on how backslashes are treated
|
||||
* is:
|
||||
*
|
||||
* + Backslashes are interpreted literally, unless they
|
||||
* immediately precede a double quotation mark.
|
||||
* + If an even number of backslashes is followed by a double
|
||||
* quotation mark, one backslash is placed in the argv array
|
||||
* for every pair of backslashes, and the double quotation
|
||||
* mark is interpreted as a string delimiter.
|
||||
* + If an odd number of backslashes is followed by a double
|
||||
* quotation mark, one backslash is placed in the argv array
|
||||
* for every pair of backslashes, and the double quotation
|
||||
* mark is "escaped" by the remaining backslash, causing a
|
||||
* literal double quotation mark (") to be placed in argv.
|
||||
*
|
||||
* Ref: https://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
*
|
||||
* Though referred page doesn't mention it, multiple qouble
|
||||
* quotes are also special. Pair of double quotes in quoted
|
||||
* string is counted as single double quote.
|
||||
*/
|
||||
{
|
||||
const WCHAR *q = p;
|
||||
int i;
|
||||
|
||||
while (*p == L'\\')
|
||||
p++;
|
||||
|
||||
if (*p == L'"') {
|
||||
int i;
|
||||
|
||||
for (i = (p - q) / 2; i > 0; i--)
|
||||
*wend++ = L'\\';
|
||||
|
||||
/*
|
||||
* if odd amount of backslashes before the quote,
|
||||
* said quote is part of the argument, not a delimiter
|
||||
*/
|
||||
if ((p - q) % 2 == 1)
|
||||
*wend++ = *p++;
|
||||
} else {
|
||||
for (i = p - q; i > 0; i--)
|
||||
*wend++ = L'\\';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L'"':
|
||||
/*
|
||||
* Without the preceding backslash (or when preceded with an
|
||||
* even number of backslashes), the double quote is a simple
|
||||
* string delimiter and just slightly change the parsing state
|
||||
*/
|
||||
if (in_quote && p[1] == L'"')
|
||||
*wend++ = *p++;
|
||||
else
|
||||
in_quote = !in_quote;
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Any other non-delimiter character is just taken verbatim
|
||||
*/
|
||||
*wend++ = *p++;
|
||||
}
|
||||
}
|
||||
|
||||
wlen = wend - warg;
|
||||
|
||||
if (wlen == 0 || !process_glob(warg, wlen)) {
|
||||
if (!validate_argv(newargc + 1)) {
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ulen = 0;
|
||||
if (wlen > 0) {
|
||||
ulen = WideCharToMultiByte(CP_UTF8, 0, warg, wlen,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (ulen <= 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
arg = (char*)malloc(ulen + 1);
|
||||
if (arg == NULL) {
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wlen > 0)
|
||||
WideCharToMultiByte(CP_UTF8, 0, warg, wlen,
|
||||
arg, ulen, NULL, NULL);
|
||||
arg[ulen] = '\0';
|
||||
|
||||
newargv[newargc++] = arg;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
saved_cp = GetConsoleOutputCP();
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
*argc = newargc;
|
||||
*argv = newargv;
|
||||
|
||||
atexit(cleanup);
|
||||
} else if (newargv != NULL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < newargc; i++)
|
||||
free(newargv[i]);
|
||||
|
||||
free(newargv);
|
||||
|
||||
newargc = 0;
|
||||
newargv = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#else
|
||||
void win32_utf8argv(int *argc, char **argv[])
|
||||
{ return; }
|
||||
#endif
|
||||
305
src/utils/aes.cpp
Normal file
305
src/utils/aes.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
#include "aes.h"
|
||||
|
||||
unsigned char AES::sBox[] =
|
||||
{ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //a
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //b
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //c
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //d
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //e
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 //f
|
||||
};
|
||||
unsigned char AES::invSBox[] =
|
||||
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, //0
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, //1
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, //2
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, //3
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, //4
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, //5
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, //6
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, //7
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, //8
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, //9
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, //a
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, //b
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, //c
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, //d
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, //e
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d //f
|
||||
};
|
||||
|
||||
unsigned char AES::rcon[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
|
||||
|
||||
AES::AES()
|
||||
{
|
||||
//If no key is input,use the default key
|
||||
unsigned char key[16] = {
|
||||
0x0f, 0x15, 0x71, 0xc9,
|
||||
0x47, 0xd9, 0xe8, 0x59,
|
||||
0x0c, 0xb7, 0xad, 0xd6,
|
||||
0xaf, 0x7f, 0x67, 0x98
|
||||
};
|
||||
setKey(key);
|
||||
keyExpansion();
|
||||
}
|
||||
|
||||
AES::AES(const unsigned char *key){
|
||||
setKey(key);
|
||||
keyExpansion();
|
||||
}
|
||||
|
||||
void AES::setKey(const unsigned char key[]){
|
||||
mNb = 4;
|
||||
mNk = 4;
|
||||
mNr = 10;
|
||||
memcpy(mKey, key, mNk * 4);
|
||||
}
|
||||
|
||||
void AES::keyExpansion() {
|
||||
//the first mNk words will be filled in mW derictly
|
||||
for (int i = 0; i < mNk; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
//arranged vertically
|
||||
mW[i][j] = mKey[j+i*4];
|
||||
}
|
||||
}
|
||||
|
||||
//generate the secret key words
|
||||
for (int i = mNk; i < mNb*(mNr + 1); i++){
|
||||
//last secret key word
|
||||
unsigned char pre_w[4];
|
||||
|
||||
for (int k = 0; k < 4; k++){
|
||||
pre_w[k] = mW[i-1][k];
|
||||
}
|
||||
|
||||
if(i%mNk == 0){
|
||||
rotWord(pre_w);
|
||||
subWord(pre_w);
|
||||
pre_w[0] = pre_w[0] ^= rcon[i / mNk - 1];
|
||||
}
|
||||
else if ((mNk>6)&&(i%mNk==4)){
|
||||
subWord(pre_w);
|
||||
}
|
||||
|
||||
for (int k = 0; k < 4; k++){
|
||||
mW[i][k] = pre_w[k] ^ mW[i-mNk][k];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AES::subBytes(unsigned char state[][4])
|
||||
{
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] = sBox[state[i][j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::shiftRows(unsigned char state[][4])
|
||||
{
|
||||
unsigned char t[4];
|
||||
for (int i = 1; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
t[j] = state[i][(i + j) % 4];
|
||||
}
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] = t[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::mixColumns(unsigned char state[][4])
|
||||
{
|
||||
unsigned char t[4];
|
||||
for (int j = 0; j < 4; j++){
|
||||
for (int i = 0; i < 4; i++){
|
||||
t[i] = state[i][j];
|
||||
}
|
||||
for (int i = 0; i < 4; i++){
|
||||
state[i][j] = GF28Multi(t[i], 0x02)
|
||||
^ GF28Multi(t[(i + 1) % 4], 0x03)
|
||||
^ GF28Multi(t[(i + 2) % 4], 0x01)
|
||||
^ GF28Multi(t[(i + 3) % 4], 0x01);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::addRoundKey(unsigned char state[][4], unsigned char w[][4])
|
||||
{
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] ^= w[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::invSubBytes(unsigned char state[][4])
|
||||
{
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] = invSBox[state[i][j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::invShiftRows(unsigned char state[][4])
|
||||
{
|
||||
unsigned char t[4];
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
t[j] = state[i][(j-i + 4) % 4];
|
||||
}
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] = t[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::invMixColumns(unsigned char state[][4])
|
||||
{
|
||||
unsigned char t[4];
|
||||
//calculate columns by columns
|
||||
for (int j = 0; j < 4; j++){
|
||||
for (int i = 0; i < 4; i++){
|
||||
t[i] = state[i][j];
|
||||
}
|
||||
for (int i = 0; i < 4; i++){
|
||||
state[i][j] = GF28Multi(t[i], 0x0e)
|
||||
^ GF28Multi(t[(i+1)%4],0x0b)
|
||||
^ GF28Multi(t[(i+2)%4],0x0d)
|
||||
^ GF28Multi(t[(i+3)%4],0x09);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AES::rotWord(unsigned char w[])
|
||||
{
|
||||
unsigned char t;
|
||||
t = w[0];
|
||||
w[0] = w[1];
|
||||
w[1] = w[2];
|
||||
w[2] = w[3];
|
||||
w[3] = t;
|
||||
}
|
||||
|
||||
void AES::subWord(unsigned char w[])
|
||||
{
|
||||
for (int i = 0; i < 4; i++){
|
||||
w[i] = sBox[w[i]];
|
||||
}
|
||||
}
|
||||
|
||||
//calculate the least significant unsigned char only for we only need
|
||||
//the least significant byte
|
||||
unsigned char AES::GF28Multi(unsigned char s,unsigned char a){
|
||||
unsigned char t[4];
|
||||
unsigned char result = 0;
|
||||
t[0] = s;
|
||||
|
||||
//calculate s*{02},s*{03},s*{04}
|
||||
for (int i = 1; i < 4; i++){
|
||||
t[i] = t[i - 1] << 1;
|
||||
if (t[i - 1] & 0x80){
|
||||
t[i] ^= 0x1b;
|
||||
}
|
||||
}
|
||||
//multiply a and s bit by bit and sum together
|
||||
for (int i = 0; i < 4; i++){
|
||||
if ((a >> i) & 0x01){
|
||||
result ^= t[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AES::encrypt(const unsigned char data[16], unsigned char out[16])
|
||||
{
|
||||
unsigned char state[4][4];
|
||||
unsigned char key[4][4];
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] = data[i+j*4];
|
||||
}
|
||||
}
|
||||
|
||||
getKeyAt(key, 0);
|
||||
|
||||
addRoundKey(state, key);
|
||||
|
||||
for (int i = 1; i <= mNr; i++){
|
||||
subBytes(state);
|
||||
shiftRows(state);
|
||||
if (i != mNr){
|
||||
mixColumns(state);
|
||||
}
|
||||
getKeyAt(key, i);
|
||||
addRoundKey(state, key);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
out[i+j*4] = state[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES::decrypt(const unsigned char data[16], unsigned char out[16])
|
||||
{
|
||||
unsigned char state[4][4];
|
||||
unsigned char key[4][4];
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
state[i][j] = data[i+j*4];
|
||||
}
|
||||
}
|
||||
|
||||
getKeyAt(key, mNr);
|
||||
addRoundKey(state,key);
|
||||
|
||||
for (int i = (mNr - 1); i >= 0; i--){
|
||||
invShiftRows(state);
|
||||
invSubBytes(state);
|
||||
getKeyAt(key, i);
|
||||
addRoundKey(state,key);
|
||||
if (i){
|
||||
invMixColumns(state);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
out[i + j * 4] = state[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get the secret key for round "index",which will
|
||||
//be arranged vetically
|
||||
void AES::getKeyAt(unsigned char key[][4], int index){
|
||||
for (int i = index*4; i < index*4+4; i++){
|
||||
for (int j = 0; j < 4; j++){
|
||||
key[j][i-index*4] = mW[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AES::~AES()
|
||||
{
|
||||
}
|
||||
2932
src/utils/cJSON.cpp
Normal file
2932
src/utils/cJSON.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user