From 1e96a1a586cee2bce9883a50eb8fc9dfb70fb602 Mon Sep 17 00:00:00 2001 From: MurakamiShinyu Date: Wed, 12 Jul 2023 14:32:02 +0900 Subject: [PATCH] refactor: remove "sha1.ts" and use crypto.subtle.digest() instead --- packages/core/src/vivliostyle/base.ts | 35 ------ packages/core/src/vivliostyle/epub.ts | 36 +++--- packages/core/src/vivliostyle/sha1.ts | 156 -------------------------- 3 files changed, 23 insertions(+), 204 deletions(-) delete mode 100644 packages/core/src/vivliostyle/sha1.ts diff --git a/packages/core/src/vivliostyle/base.ts b/packages/core/src/vivliostyle/base.ts index 4ff42cb52..bf8bb058e 100644 --- a/packages/core/src/vivliostyle/base.ts +++ b/packages/core/src/vivliostyle/base.ts @@ -571,41 +571,6 @@ export function numberCompare(a: number, b: number): number { return a - b; } -export const base64Chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -export function appendBase64(sb: StringBuffer, data: string): void { - const length = data.length; - const length3 = Math.floor(length / 3) * 3; - for (let i = 0; i < length3; i += 3) { - const c1 = data.charCodeAt(i) & 255; - const c2 = data.charCodeAt(i + 1) & 255; - const c3 = data.charCodeAt(i + 2) & 255; - sb.append(base64Chars.charAt(c1 >> 2)); - sb.append(base64Chars.charAt(((c1 << 4) | (c2 >> 4)) & 63)); - sb.append(base64Chars.charAt(((c2 << 2) | (c3 >> 6)) & 63)); - sb.append(base64Chars.charAt(c3 & 63)); - } - switch (length - length3) { - case 1: { - const p1 = data.charCodeAt(length3) & 255; - sb.append(base64Chars.charAt(p1 >> 2)); - sb.append(base64Chars.charAt((p1 << 4) & 63)); - sb.append("=="); - break; - } - case 2: { - const q1 = data.charCodeAt(length3) & 255; - const q2 = data.charCodeAt(length3 + 1) & 255; - sb.append(base64Chars.charAt(q1 >> 2)); - sb.append(base64Chars.charAt(((q1 << 4) | (q2 >> 4)) & 63)); - sb.append(base64Chars.charAt((q2 << 2) & 63)); - sb.append("="); - break; - } - } -} - /** * Index array using key function. First encountered item wins on collision. * Elements with empty and null keys are dropped. diff --git a/packages/core/src/vivliostyle/epub.ts b/packages/core/src/vivliostyle/epub.ts index 0bd1a82b0..f3beebd28 100644 --- a/packages/core/src/vivliostyle/epub.ts +++ b/packages/core/src/vivliostyle/epub.ts @@ -32,7 +32,6 @@ import * as Font from "./font"; import * as Logging from "./logging"; import * as Net from "./net"; import * as OPS from "./ops"; -import * as SHA1 from "./sha1"; import * as Task from "./task"; import * as Toc from "./toc"; import * as Vgen from "./vgen"; @@ -469,25 +468,36 @@ export function getOPFItemId(item: OPFItem): string | null { } export function makeDeobfuscator(uid: string): (p1: Blob) => Task.Result { - // TODO: use UTF8 of uid - const sha1Sum = SHA1.bytesToSHA1Int8(uid); return (blob) => { const frame = Task.newFrame("deobfuscator") as Task.Frame; - const head = blob.slice(0, 1040); - const tail = blob.slice(1040, blob.size); - Net.readBlob(head).then((buf) => { - const dataView = new DataView(buf); - for (let k = 0; k < dataView.byteLength; k++) { - let b = dataView.getUint8(k); - b ^= sha1Sum[k % 20]; - dataView.setUint8(k, b); - } - frame.finish(Net.makeBlob([dataView, tail])); + makeDigest("SHA-1", uid).then((hash) => { + const head = blob.slice(0, 1040); + const tail = blob.slice(1040, blob.size); + Net.readBlob(head).then((buf) => { + const dataView = new DataView(buf); + for (let k = 0; k < dataView.byteLength; k++) { + let b = dataView.getUint8(k); + b ^= hash[k % 20]; + dataView.setUint8(k, b); + } + frame.finish(Net.makeBlob([dataView, tail])); + }); }); return frame.result(); }; } +function makeDigest(algorithm: string, str: string): Task.Result { + const frame = Task.newFrame("makeDigest") as Task.Frame; + const continuation = frame.suspend(); + window.crypto.subtle + .digest(algorithm, new TextEncoder().encode(str)) + .then((buf) => { + continuation.schedule(new Uint8Array(buf)); + }); + return frame.result(); +} + type RawMeta = { [key: string]: RawMetaItem[]; }; diff --git a/packages/core/src/vivliostyle/sha1.ts b/packages/core/src/vivliostyle/sha1.ts deleted file mode 100644 index a627c51b4..000000000 --- a/packages/core/src/vivliostyle/sha1.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright 2013 Google, Inc. - * Copyright 2017 Trim-marks Inc. - * Copyright 2019 Vivliostyle Foundation - * - * Vivliostyle.js is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Vivliostyle.js is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Vivliostyle.js. If not, see . - * - * @fileoverview Sha1 - Calculate SHA1 hash of the given content. - */ -import * as Base from "./base"; - -/** - * @return big-endian byte sequence - */ -export function encode32(n: number): string { - return String.fromCharCode( - (n >>> 24) & 255, - (n >>> 16) & 255, - (n >>> 8) & 255, - n & 255, - ); -} - -/** - * @param bytes big-endian byte sequence - */ -export function decode32(bytes: string): number { - // Important facts: "".charCodeAt(0) == NaN, NaN & 0xFF == 0 - const b0 = bytes.charCodeAt(0) & 255; - const b1 = bytes.charCodeAt(1) & 255; - const b2 = bytes.charCodeAt(2) & 255; - const b3 = bytes.charCodeAt(3) & 255; - return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; -} - -/** - * @param bytes chars with codes 0 - 255 that represent message byte values - * @return big-endian uint32 numbers representing sha1 hash - */ -export function bytesToSHA1Int32(bytes: string): number[] { - const sb = new Base.StringBuffer(); - sb.append(bytes); - let appendCount = (55 - bytes.length) & 63; - sb.append("\u0080"); - while (appendCount > 0) { - appendCount--; - sb.append("\x00"); - } - sb.append("\x00\x00\x00\x00"); - sb.append(encode32(bytes.length * 8)); - bytes = sb.toString(); - const h = [1732584193, 4023233417, 2562383102, 271733878, 3285377520]; - const w = - /** @type Array. */ - [] as number[]; - let i: number; - for (let bi = 0; bi < bytes.length; bi += 64) { - for (i = 0; i < 16; i++) { - w[i] = decode32(bytes.substr(bi + 4 * i, 4)); - } - for (; i < 80; i++) { - const q = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; - w[i] = (q << 1) | (q >>> 31); - } - let a = h[0]; - let b = h[1]; - let c = h[2]; - let d = h[3]; - let e = h[4]; - let f: number; - for (i = 0; i < 80; i++) { - if (i < 20) { - f = ((b & c) | (~b & d)) + 1518500249; - } else if (i < 40) { - f = (b ^ c ^ d) + 1859775393; - } else if (i < 60) { - f = ((b & c) | (b & d) | (c & d)) + 2400959708; - } else { - f = (b ^ c ^ d) + 3395469782; - } - f += ((a << 5) | (a >>> 27)) + e + w[i]; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = f; - } - h[0] = (h[0] + a) | 0; - h[1] = (h[1] + b) | 0; - h[2] = (h[2] + c) | 0; - h[3] = (h[3] + d) | 0; - h[4] = (h[4] + e) | 0; - } - return h; -} - -/** - * @param bytes chars with codes 0 - 255 that represent message byte values - * @return uint8 numbers representing sha1 hash - */ -export function bytesToSHA1Int8(bytes: string): number[] { - const h = bytesToSHA1Int32(bytes); - const res = []; - for (const n of h) { - res.push((n >>> 24) & 255, (n >>> 16) & 255, (n >>> 8) & 255, n & 255); - } - return res; -} - -/** - * @param bytes chars with codes 0 - 255 that represent message byte values - * @return chars with codes 0 - 255 equal to SHA1 hash of the input - */ -export function bytesToSHA1Bytes(bytes: string): string { - const h = bytesToSHA1Int32(bytes); - const sb = new Base.StringBuffer(); - for (let i = 0; i < h.length; i++) { - sb.append(encode32(h[i])); - } - return sb.toString(); -} - -/** - * @param bytes chars with codes 0 - 255 that represent message byte values - * @return hex-encoded SHA1 hash - */ -export function bytesToSHA1Hex(bytes: string): string { - const sha1 = bytesToSHA1Bytes(bytes); - const sb = new Base.StringBuffer(); - for (let i = 0; i < sha1.length; i++) { - sb.append((sha1.charCodeAt(i) | 256).toString(16).substr(1)); - } - return sb.toString(); -} - -/** - * @param bytes chars with codes 0 - 255 that represent message byte values - * @return base64-encoded SHA1 hash of the input - */ -export function bytesToSHA1Base64(bytes: string): string { - const sha1 = bytesToSHA1Bytes(bytes); - const sb = new Base.StringBuffer(); - Base.appendBase64(sb, sha1); - return sb.toString(); -}