SPB Git forge

spb/admin-ka

Public
41commits 1branches 0releases
172.9 MBsize
maindefault branch
20 days agolast push
JavaScript 65.5% Python 17.8% CSS 13% HTML 3.7%
5.8 KB · 179 lines javascript
Raw Blame History
1export class AESECBCipher {2    constructor() {3        this._key = null;4    }56    get algorithm() {7        return { name: "AES-ECB" };8    }910    static async importKey(key, _algorithm, extractable, keyUsages) {11        const cipher = new AESECBCipher;12        await cipher._importKey(key, extractable, keyUsages);13        return cipher;14    }1516    async _importKey(key, extractable, keyUsages) {17        this._key = await window.crypto.subtle.importKey(18            "raw", key, {name: "AES-CBC"}, extractable, keyUsages);19    }2021    async encrypt(_algorithm, plaintext) {22        const x = new Uint8Array(plaintext);23        if (x.length % 16 !== 0 || this._key === null) {24            return null;25        }26        const n = x.length / 16;27        for (let i = 0; i < n; i++) {28            const y = new Uint8Array(await window.crypto.subtle.encrypt({29                name: "AES-CBC",30                iv: new Uint8Array(16),31            }, this._key, x.slice(i * 16, i * 16 + 16))).slice(0, 16);32            x.set(y, i * 16);33        }34        return x;35    }36}3738export class AESEAXCipher {39    constructor() {40        this._rawKey = null;41        this._ctrKey = null;42        this._cbcKey = null;43        this._zeroBlock = new Uint8Array(16);44        this._prefixBlock0 = this._zeroBlock;45        this._prefixBlock1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);46        this._prefixBlock2 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);47    }4849    get algorithm() {50        return { name: "AES-EAX" };51    }5253    async _encryptBlock(block) {54        const encrypted = await window.crypto.subtle.encrypt({55            name: "AES-CBC",56            iv: this._zeroBlock,57        }, this._cbcKey, block);58        return new Uint8Array(encrypted).slice(0, 16);59    }6061    async _initCMAC() {62        const k1 = await this._encryptBlock(this._zeroBlock);63        const k2 = new Uint8Array(16);64        const v = k1[0] >>> 6;65        for (let i = 0; i < 15; i++) {66            k2[i] = (k1[i + 1] >> 6) | (k1[i] << 2);67            k1[i] = (k1[i + 1] >> 7) | (k1[i] << 1);68        }69        const lut = [0x0, 0x87, 0x0e, 0x89];70        k2[14] ^= v >>> 1;71        k2[15] = (k1[15] << 2) ^ lut[v];72        k1[15] = (k1[15] << 1) ^ lut[v >> 1];73        this._k1 = k1;74        this._k2 = k2;75    }7677    async _encryptCTR(data, counter) {78        const encrypted = await window.crypto.subtle.encrypt({79            name: "AES-CTR",80            counter: counter,81            length: 12882        }, this._ctrKey, data);83        return new Uint8Array(encrypted);84    }8586    async _decryptCTR(data, counter) {87        const decrypted = await window.crypto.subtle.decrypt({88            name: "AES-CTR",89            counter: counter,90            length: 12891        }, this._ctrKey, data);92        return new Uint8Array(decrypted);93    }9495    async _computeCMAC(data, prefixBlock) {96        if (prefixBlock.length !== 16) {97            return null;98        }99        const n = Math.floor(data.length / 16);100        const m = Math.ceil(data.length / 16);101        const r = data.length - n * 16;102        const cbcData = new Uint8Array((m + 1) * 16);103        cbcData.set(prefixBlock);104        cbcData.set(data, 16);105        if (r === 0) {106            for (let i = 0; i < 16; i++) {107                cbcData[n * 16 + i] ^= this._k1[i];108            }109        } else {110            cbcData[(n + 1) * 16 + r] = 0x80;111            for (let i = 0; i < 16; i++) {112                cbcData[(n + 1) * 16 + i] ^= this._k2[i];113            }114        }115        let cbcEncrypted = await window.crypto.subtle.encrypt({116            name: "AES-CBC",117            iv: this._zeroBlock,118        }, this._cbcKey, cbcData);119120        cbcEncrypted = new Uint8Array(cbcEncrypted);121        const mac = cbcEncrypted.slice(cbcEncrypted.length - 32, cbcEncrypted.length - 16);122        return mac;123    }124125    static async importKey(key, _algorithm, _extractable, _keyUsages) {126        const cipher = new AESEAXCipher;127        await cipher._importKey(key);128        return cipher;129    }130131    async _importKey(key) {132        this._rawKey = key;133        this._ctrKey = await window.crypto.subtle.importKey(134            "raw", key, {name: "AES-CTR"}, false, ["encrypt", "decrypt"]);135        this._cbcKey = await window.crypto.subtle.importKey(136            "raw", key, {name: "AES-CBC"}, false, ["encrypt"]);137        await this._initCMAC();138    }139140    async encrypt(algorithm, message) {141        const ad = algorithm.additionalData;142        const nonce = algorithm.iv;143        const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0);144        const encrypted = await this._encryptCTR(message, nCMAC);145        const adCMAC = await this._computeCMAC(ad, this._prefixBlock1);146        const mac = await this._computeCMAC(encrypted, this._prefixBlock2);147        for (let i = 0; i < 16; i++) {148            mac[i] ^= nCMAC[i] ^ adCMAC[i];149        }150        const res = new Uint8Array(16 + encrypted.length);151        res.set(encrypted);152        res.set(mac, encrypted.length);153        return res;154    }155156    async decrypt(algorithm, data) {157        const encrypted = data.slice(0, data.length - 16);158        const ad = algorithm.additionalData;159        const nonce = algorithm.iv;160        const mac = data.slice(data.length - 16);161        const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0);162        const adCMAC = await this._computeCMAC(ad, this._prefixBlock1);163        const computedMac = await this._computeCMAC(encrypted, this._prefixBlock2);164        for (let i = 0; i < 16; i++) {165            computedMac[i] ^= nCMAC[i] ^ adCMAC[i];166        }167        if (computedMac.length !== mac.length) {168            return null;169        }170        for (let i = 0; i < mac.length; i++) {171            if (computedMac[i] !== mac[i]) {172                return null;173            }174        }175        const res = await this._decryptCTR(encrypted, nCMAC);176        return res;177    }178}179