Files
LingChair/client/static/crypto-es@3.1.0/core.mjs
2025-09-06 23:28:50 +08:00

584 lines
16 KiB
JavaScript

//#region src/core.ts
const crypto = (typeof globalThis !== "undefined" ? globalThis : void 0)?.crypto || (typeof global !== "undefined" ? global : void 0)?.crypto || (typeof window !== "undefined" ? window : void 0)?.crypto || (typeof self !== "undefined" ? self : void 0)?.crypto || (typeof frames !== "undefined" ? frames : void 0)?.[0]?.crypto;
/**
* Random word array generator function
*/
let randomWordArray;
if (crypto) randomWordArray = (nBytes) => {
const words = [];
for (let i = 0; i < nBytes; i += 4) words.push(crypto.getRandomValues(new Uint32Array(1))[0]);
return new WordArray(words, nBytes);
};
else randomWordArray = (nBytes) => {
const words = [];
const r = (m_w) => {
let _m_w = m_w;
let _m_z = 987654321;
const mask = 4294967295;
return () => {
_m_z = 36969 * (_m_z & 65535) + (_m_z >> 16) & mask;
_m_w = 18e3 * (_m_w & 65535) + (_m_w >> 16) & mask;
let result = (_m_z << 16) + _m_w & mask;
result /= 4294967296;
result += .5;
return result * (Math.random() > .5 ? 1 : -1);
};
};
let rcache;
for (let i = 0; i < nBytes; i += 4) {
const _r = r((rcache || Math.random()) * 4294967296);
rcache = _r() * 987654071;
words.push(_r() * 4294967296 | 0);
}
return new WordArray(words, nBytes);
};
/**
* Base class for inheritance.
* Provides basic object-oriented programming utilities.
*/
var Base = class {
/**
* Creates a new instance of this class with the provided arguments.
* This is a factory method that provides an alternative to using 'new'.
*
* @param args - Arguments to pass to the constructor
* @returns A new instance of this class
* @static
* @example
* ```javascript
* const instance = MyType.create(arg1, arg2);
* ```
*/
static create(...args) {
return new this(...args);
}
/**
* Copies properties from the provided object into this instance.
* Performs a shallow merge of properties.
*
* @param properties - The properties to mix in
* @returns This instance for method chaining
* @example
* ```javascript
* instance.mixIn({ field: 'value', another: 123 });
* ```
*/
mixIn(properties) {
return Object.assign(this, properties);
}
/**
* Creates a deep copy of this object.
*
* @returns A clone of this instance
* @example
* ```javascript
* const clone = instance.clone();
* ```
*/
clone() {
const clone = new this.constructor();
Object.assign(clone, this);
return clone;
}
};
/**
* An array of 32-bit words.
* This is the core data structure used throughout the library for representing binary data.
*
* @property words - The array of 32-bit words
* @property sigBytes - The number of significant bytes in this word array
*/
var WordArray = class extends Base {
/** The array of 32-bit words */
words;
/** The number of significant bytes in this word array */
sigBytes;
/**
* Initializes a newly created word array.
* Can accept various input formats including regular arrays, typed arrays, and ArrayBuffers.
*
* @param words - An array of 32-bit words, typed array, or ArrayBuffer
* @param sigBytes - The number of significant bytes in the words (defaults to words.length * 4)
* @example
* ```javascript
* const wordArray = new WordArray();
* const wordArray = new WordArray([0x00010203, 0x04050607]);
* const wordArray = new WordArray([0x00010203, 0x04050607], 6);
* const wordArray = new WordArray(new Uint8Array([1, 2, 3, 4]));
* ```
*/
constructor(words = [], sigBytes) {
super();
if (words instanceof ArrayBuffer) {
const typedArray = new Uint8Array(words);
this._initFromUint8Array(typedArray);
return;
}
if (ArrayBuffer.isView(words)) {
let uint8Array;
if (words instanceof Uint8Array) uint8Array = words;
else uint8Array = new Uint8Array(words.buffer, words.byteOffset, words.byteLength);
this._initFromUint8Array(uint8Array);
return;
}
this.words = words;
this.sigBytes = sigBytes !== void 0 ? sigBytes : this.words.length * 4;
}
/**
* Initialize from Uint8Array
* @private
*/
_initFromUint8Array(typedArray) {
const typedArrayByteLength = typedArray.byteLength;
const words = [];
for (let i = 0; i < typedArrayByteLength; i += 1) words[i >>> 2] |= typedArray[i] << 24 - i % 4 * 8;
this.words = words;
this.sigBytes = typedArrayByteLength;
}
/**
* Creates a word array filled with cryptographically strong random bytes.
* Uses Web Crypto API if available, falls back to Math.random() if not.
*
* @param nBytes - The number of random bytes to generate
* @returns The random word array
* @static
* @example
* ```javascript
* const randomBytes = WordArray.random(16); // Generate 16 random bytes
* ```
*/
static random = randomWordArray;
/**
* Converts this word array to a string using the specified encoding.
*
* @param encoder - The encoding strategy to use (defaults to Hex)
* @returns The stringified word array
* @example
* ```javascript
* const hexString = wordArray.toString();
* const base64String = wordArray.toString(Base64);
* const utf8String = wordArray.toString(Utf8);
* ```
*/
toString(encoder = Hex) {
return encoder.stringify(this);
}
/**
* Concatenates a word array to this word array.
* Modifies this word array in place.
*
* @param wordArray - The word array to append
* @returns This word array for method chaining
* @example
* ```javascript
* wordArray1.concat(wordArray2);
* const combined = wordArray1.concat(wordArray2).concat(wordArray3);
* ```
*/
concat(wordArray) {
const thisWords = this.words;
const thatWords = wordArray.words;
const thisSigBytes = this.sigBytes;
const thatSigBytes = wordArray.sigBytes;
this.clamp();
if (thisSigBytes % 4) for (let i = 0; i < thatSigBytes; i += 1) {
const thatByte = thatWords[i >>> 2] >>> 24 - i % 4 * 8 & 255;
thisWords[thisSigBytes + i >>> 2] |= thatByte << 24 - (thisSigBytes + i) % 4 * 8;
}
else for (let i = 0; i < thatSigBytes; i += 4) thisWords[thisSigBytes + i >>> 2] = thatWords[i >>> 2];
this.sigBytes += thatSigBytes;
return this;
}
/**
* Removes insignificant bits from the end of the word array.
* This ensures the word array only contains the exact number of significant bytes.
*
* @example
* ```javascript
* wordArray.clamp();
* ```
*/
clamp() {
const { words, sigBytes } = this;
words[sigBytes >>> 2] &= 4294967295 << 32 - sigBytes % 4 * 8;
words.length = Math.ceil(sigBytes / 4);
}
/**
* Creates a copy of this word array.
*
* @returns The cloned word array
* @example
* ```javascript
* const clone = wordArray.clone();
* ```
*/
clone() {
const clone = super.clone();
clone.words = this.words.slice(0);
return clone;
}
};
/**
* Hex encoding strategy.
* Converts between word arrays and hexadecimal strings.
*/
const Hex = {
stringify(wordArray) {
const { words, sigBytes } = wordArray;
const hexChars = [];
for (let i = 0; i < sigBytes; i += 1) {
const bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
hexChars.push((bite >>> 4).toString(16));
hexChars.push((bite & 15).toString(16));
}
return hexChars.join("");
},
parse(hexStr) {
const hexStrLength = hexStr.length;
const words = [];
for (let i = 0; i < hexStrLength; i += 2) words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << 24 - i % 8 * 4;
return new WordArray(words, hexStrLength / 2);
}
};
/**
* Latin1 encoding strategy.
* Converts between word arrays and Latin-1 (ISO-8859-1) strings.
*/
const Latin1 = {
stringify(wordArray) {
const { words, sigBytes } = wordArray;
const latin1Chars = [];
for (let i = 0; i < sigBytes; i += 1) {
const bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
latin1Chars.push(String.fromCharCode(bite));
}
return latin1Chars.join("");
},
parse(latin1Str) {
const latin1StrLength = latin1Str.length;
const words = [];
for (let i = 0; i < latin1StrLength; i += 1) words[i >>> 2] |= (latin1Str.charCodeAt(i) & 255) << 24 - i % 4 * 8;
return new WordArray(words, latin1StrLength);
}
};
/**
* UTF-8 encoding strategy.
* Converts between word arrays and UTF-8 strings.
*/
const Utf8 = {
stringify(wordArray) {
try {
return decodeURIComponent(escape(Latin1.stringify(wordArray)));
} catch (e) {
throw new Error("Malformed UTF-8 data");
}
},
parse(utf8Str) {
return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
}
};
/**
* Abstract buffered block algorithm template.
* Provides a base implementation for algorithms that process data in fixed-size blocks.
*
* @property _minBufferSize - The number of blocks that should be kept unprocessed in the buffer
*/
var BufferedBlockAlgorithm = class extends Base {
/** The number of blocks that should be kept unprocessed in the buffer */
_minBufferSize = 0;
/** The data buffer */
_data;
/** The number of bytes in the data buffer */
_nDataBytes;
constructor() {
super();
}
/**
* Resets this block algorithm's data buffer to its initial state.
*
* @example
* ```javascript
* bufferedBlockAlgorithm.reset();
* ```
*/
reset() {
this._data = new WordArray();
this._nDataBytes = 0;
}
/**
* Adds new data to this block algorithm's buffer.
*
* @param data - The data to append (strings are converted to WordArray using UTF-8)
* @example
* ```javascript
* bufferedBlockAlgorithm._append('data');
* bufferedBlockAlgorithm._append(wordArray);
* ```
*/
_append(data) {
let m_data;
if (typeof data === "string") m_data = Utf8.parse(data);
else m_data = data;
this._data.concat(m_data);
this._nDataBytes += m_data.sigBytes;
}
/**
* Processes available data blocks.
* This method invokes _doProcessBlock(dataWords, offset), which must be implemented by a concrete subtype.
*
* @param doFlush - Whether all blocks and partial blocks should be processed
* @returns The processed data
* @example
* ```javascript
* const processedData = bufferedBlockAlgorithm._process();
* const processedData = bufferedBlockAlgorithm._process(true); // Flush
* ```
*/
_process(doFlush) {
let processedWords;
const data = this._data;
const dataWords = data.words;
const dataSigBytes = data.sigBytes;
const blockSizeBytes = this.blockSize * 4;
let nBlocksReady = dataSigBytes / blockSizeBytes;
if (doFlush) nBlocksReady = Math.ceil(nBlocksReady);
else nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
const nWordsReady = nBlocksReady * this.blockSize;
const nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
if (nWordsReady) {
for (let offset = 0; offset < nWordsReady; offset += this.blockSize) this._doProcessBlock(dataWords, offset);
processedWords = dataWords.splice(0, nWordsReady);
data.sigBytes -= nBytesReady;
}
return new WordArray(processedWords || [], nBytesReady);
}
/**
* Creates a copy of this object.
*
* @returns The clone
* @example
* ```javascript
* const clone = bufferedBlockAlgorithm.clone();
* ```
*/
clone() {
const clone = super.clone();
clone._data = this._data.clone();
return clone;
}
};
/**
* Abstract hasher template.
* Base class for all hash algorithm implementations.
*
* @property blockSize - The number of 32-bit words this hasher operates on (default: 16 = 512 bits)
*/
var Hasher = class extends BufferedBlockAlgorithm {
/** The number of 32-bit words this hasher operates on */
blockSize = 512 / 32;
/** Configuration options */
cfg;
/** The hash result */
_hash;
/**
* Initializes a newly created hasher.
*
* @param cfg - Configuration options
*/
constructor(cfg) {
super();
this.cfg = Object.assign({}, cfg);
this.reset();
}
/**
* Creates a shortcut function to a hasher's object interface.
*
* @param SubHasher - The hasher class to create a helper for
* @returns The shortcut function
* @static
* @example
* ```javascript
* const SHA256 = Hasher._createHelper(SHA256Algo);
* ```
*/
static _createHelper(SubHasher) {
return (message, cfg) => {
return new SubHasher(cfg).finalize(message);
};
}
/**
* Creates a shortcut function to the HMAC's object interface.
*
* @param SubHasher - The hasher class to use in this HMAC helper
* @returns The shortcut function
* @static
* @example
* ```javascript
* const HmacSHA256 = Hasher._createHmacHelper(SHA256Algo);
* ```
*/
static _createHmacHelper(SubHasher) {
return (message, key) => {
return new HMAC(SubHasher, key).finalize(message);
};
}
/**
* Resets this hasher to its initial state.
*
* @example
* ```javascript
* hasher.reset();
* ```
*/
reset() {
super.reset();
this._doReset();
}
/**
* Updates this hasher with a message.
*
* @param messageUpdate - The message to append
* @returns This hasher instance for method chaining
* @example
* ```javascript
* hasher.update('message');
* hasher.update(wordArray);
* ```
*/
update(messageUpdate) {
this._append(messageUpdate);
this._process();
return this;
}
/**
* Finalizes the hash computation.
* Note that the finalize operation is effectively a destructive, read-once operation.
*
* @param messageUpdate - An optional final message update
* @returns The computed hash
* @example
* ```javascript
* const hash = hasher.finalize();
* const hash = hasher.finalize('message');
* const hash = hasher.finalize(wordArray);
* ```
*/
finalize(messageUpdate) {
if (messageUpdate) this._append(messageUpdate);
const hash = this._doFinalize();
return hash;
}
};
/**
* Base class for 32-bit hash algorithms.
* Hash algorithms that operate on 32-bit words should extend this class.
*/
var Hasher32 = class extends Hasher {};
/**
* Base class for 64-bit hash algorithms.
* Hash algorithms that operate on 64-bit words should extend this class.
*/
var Hasher64 = class extends Hasher {};
/**
* HMAC (Hash-based Message Authentication Code) algorithm.
* Provides message authentication using a cryptographic hash function and a secret key.
*/
var HMAC = class HMAC extends Base {
/** The inner hasher instance */
_hasher;
/** The outer key */
_oKey;
/** The inner key */
_iKey;
/**
* Initializes a newly created HMAC.
*
* @param SubHasher - The hash algorithm class to use
* @param key - The secret key
* @example
* ```javascript
* const hmac = new HMAC(SHA256Algo, 'secret key');
* ```
*/
constructor(SubHasher, key) {
super();
const hasher = new SubHasher();
this._hasher = hasher;
let _key;
if (typeof key === "string") _key = Utf8.parse(key);
else _key = key;
const hasherBlockSize = hasher.blockSize;
const hasherBlockSizeBytes = hasherBlockSize * 4;
if (_key.sigBytes > hasherBlockSizeBytes) _key = hasher.finalize(_key);
_key.clamp();
const oKey = _key.clone();
this._oKey = oKey;
const iKey = _key.clone();
this._iKey = iKey;
const oKeyWords = oKey.words;
const iKeyWords = iKey.words;
for (let i = 0; i < hasherBlockSize; i += 1) {
oKeyWords[i] ^= 1549556828;
iKeyWords[i] ^= 909522486;
}
oKey.sigBytes = hasherBlockSizeBytes;
iKey.sigBytes = hasherBlockSizeBytes;
this.reset();
}
static create(...args) {
const [SubHasher, key] = args;
return new HMAC(SubHasher, key);
}
/**
* Resets this HMAC to its initial state.
*
* @example
* ```javascript
* hmac.reset();
* ```
*/
reset() {
const hasher = this._hasher;
hasher.reset();
hasher.update(this._iKey);
}
/**
* Updates this HMAC with a message.
*
* @param messageUpdate - The message to append
* @returns This HMAC instance for method chaining
* @example
* ```javascript
* hmac.update('message');
* hmac.update(wordArray);
* ```
*/
update(messageUpdate) {
this._hasher.update(messageUpdate);
return this;
}
/**
* Finalizes the HMAC computation.
* Note that the finalize operation is effectively a destructive, read-once operation.
*
* @param messageUpdate - An optional final message update
* @returns The computed HMAC
* @example
* ```javascript
* const hmacValue = hmac.finalize();
* const hmacValue = hmac.finalize('message');
* const hmacValue = hmac.finalize(wordArray);
* ```
*/
finalize(messageUpdate) {
const hasher = this._hasher;
const innerHash = hasher.finalize(messageUpdate);
hasher.reset();
const hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
return hmac;
}
};
//#endregion
export { Base, BufferedBlockAlgorithm, HMAC, Hasher, Hasher32, Hasher64, Hex, Latin1, Utf8, WordArray };
//# sourceMappingURL=core.mjs.map