CH-J Server Managerserver management over SSH
Menu
Published source

CH-J Server Manager

Browse directories and files for a specific application release.

Download source ZIP
CH-J Proprietary Software License 1.14

Source is provided under the CH-J Proprietary Software License 1.14. Its availability does not change the license terms or grant additional rights.

7,4 KB · 233 linesDownload file
1/**
2 * (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
3 *
4 * An implementation of the Tiger hash function. It specifically
5 * supports the original PHP implementation that swapped byte order
6 * (endianness) of the resulting digest to keep backwards
7 * compatibility:
8 * https://github.com/facebook/hhvm/blob/281303d/hphp/runtime/ext/hash/ext_hash.cpp#L94-L97
9 *
10 * More on the Tiger algorithm:
11 * https://www.cs.technion.ac.il/~biham/Reports/Tiger/tiger/node3.html
12 * https://www.cl.cam.ac.uk/~rja14/Papers/tiger.pdf
13 * https://www.cl.cam.ac.uk/~rja14/Papers/tigersb.pdf
14 *
15 * Implementation in C:
16 * https://www.cs.technion.ac.il/~biham/Reports/Tiger/tiger/node7.html
17 *
18 * @emails oncall+i18n_fbt_js
19 * Flow does not support BigInt yet
20 *
21 * @noflow
22 */
24/* eslint-disable no-bitwise */
25/* global BigInt */
27'use strict';
29const {t1, t2, t3, t4} = require('./TigerTables');
31const uint = BigInt.asUintN.bind(BigInt, 64);
32const U64 = 0xffffffffffffffffn;
34// Turn a buffer into a Tiger-padded array of 64-bit words
35function _getMessage(buffer /*: Buffer*/) /*: Array<BigInt>*/ {
36 const words = [];
37 let word = 0n;
38 let byteLen = 0n;
39 for (const c of buffer) {
40 const b = byteLen++ & 0x7n;
41 word |= BigInt(c) << (b << 3n);
42 if (byteLen % 8n == 0n) {
43 words.push(word);
44 word = 0n;
45 }
46 }
47 // Store original size (in bits)
48 const bitSize = (byteLen << 3n) & U64;
50 // Pad our message with a byte of 0x1 ala MD4 (Tiger1) padding
51 const b = byteLen & 0x7n;
52 if (b) {
53 word |= 0x1n << (b << 3n);
54 words.push(word);
55 byteLen += 8n - b;
56 } else {
57 words.push(0x1n);
58 byteLen += 8n;
59 }
61 for (byteLen %= 64n; byteLen < 56n; byteLen += 8n) {
62 words.push(0n);
63 }
64 words.push(bitSize);
65 return words;
68// BigInt.toString will naturally elide leading zero's. Add them back
69const ZERO_FILL = '000000000000000';
70function _zeroFill(n /*: {value: BigInt}*/) {
71 const str = n.value.toString(16);
72 return ZERO_FILL.substr(0, 16 - str.length) + str;
75// The registers a, b, c concatenated as a string yield the inverted byte order.
76// Reverse the byte order of the concatenated digest string with an inversion
77// lookup.
78// prettier-ignore
79const inversion = [
80 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1,
81 30, 31, 28, 29, 26, 27, 24, 25, 22, 23, 20, 21, 18, 19, 16, 17,
82 46, 47, 44, 45, 42, 43, 40, 41, 38, 39, 36, 37, 34, 35, 32, 33
83];
85class Tiger {
86 constructor(
87 digestBitLen /*: number*/, // 128, 160, 192
88 // For additional passes after the first 3. For 'Tiger,4' we'd pass 1 here
89 extraPasses /*: number*/ = 0,
90 // PHP originally had the final byte-order of the digest inverted. If this
91 // old behavior is desired, set this to true.
92 invertByte /*: boolean*/ = false,
93 // Encoding to which to convert JS's internal string before hashing.
94 // Defaults to encoding the string to UTF-8. To use the string as the
95 // native UTF-16, pass Tiger.UTF16 = 'utf16le'.
96 encoding /*: string*/ = Tiger.UTF8,
97 ) {
98 this._digestBitLen = digestBitLen;
99 this._extraPasses = extraPasses;
100 this._invertByte = invertByte;
101 this._encoding = encoding;
102 }
104 // The use of uint(...) and & U64 here are to ensure we maintain unsigned
105 // 64-bit behavior. We're ensuring BigInt's implementation doesn't exceed 64
106 // bits (when multiplying, adding, or shifting left) and doesn't go negative
107 // (when subtracting). Negative numbers aren't a problem for bitwise & and |
108 // operations, but BigInt will 1-fill the most-significant bits when shifting
109 // right, whereas an unsigned word would have 0-filled.
110 _keySchedule() {
111 this._x0 = uint(this._x0 - (this._x7 ^ 0xa5a5a5a5a5a5a5a5n));
112 this._x1 ^= this._x0;
113 this._x2 = (this._x2 + this._x1) & U64;
114 this._x3 = uint(this._x3 - (this._x2 ^ ((~this._x1 << 19n) & U64)));
115 this._x4 ^= this._x3;
116 this._x5 = (this._x5 + this._x4) & U64;
117 this._x6 = uint(this._x6 - (this._x5 ^ (uint(~this._x4) >> 23n)));
118 this._x7 ^= this._x6;
119 this._x0 = (this._x0 + this._x7) & U64;
120 this._x1 = uint(this._x1 - (this._x0 ^ (~this._x7 << 19n)));
121 this._x2 ^= this._x1;
122 this._x3 = (this._x3 + this._x2) & U64;
123 this._x4 = uint(this._x4 - (this._x3 ^ (uint(~this._x2) >> 23n)));
124 this._x5 ^= this._x4;
125 this._x6 = (this._x6 + this._x5) & U64;
126 this._x7 = uint(this._x7 - (this._x6 ^ 0x0123456789abcdefn));
127 }
129 _save() {
130 this._aa = this._a.value;
131 this._bb = this._b.value;
132 this._cc = this._c.value;
133 }
135 _feedforward() {
136 this._a.value ^= this._aa;
137 this._b.value = uint(this._b.value - this._bb);
138 this._c.value = (this._c.value + this._cc) & U64;
139 }
141 _compress() {
142 this._save();
143 this._pass(this._a, this._b, this._c, 5n);
144 this._keySchedule();
145 this._pass(this._c, this._a, this._b, 7n);
146 this._keySchedule();
147 this._pass(this._b, this._c, this._a, 9n);
148 for (let pass = 0; pass < this._extraPasses; ++pass) {
149 this._keySchedule();
150 this._pass(this._a, this._b, this._c, 9n);
151 const tmpa = this._a;
152 this._a = this._c;
153 this._c = this._b;
154 this._b = tmpa;
155 }
156 this._feedforward();
157 }
159 _round(a, b, c, x, mul) {
160 c.value ^= x;
161 const d = c.value;
162 const d_0 = d & 0xffn;
163 const d_1 = (d >> 8n) & 0xffn;
164 const d_2 = (d >> 16n) & 0xffn;
165 const d_3 = (d >> 24n) & 0xffn;
166 const d_4 = (d >> 32n) & 0xffn;
167 const d_5 = (d >> 40n) & 0xffn;
168 const d_6 = (d >> 48n) & 0xffn;
169 const d_7 = (d >> 56n) & 0xffn;
170 a.value = uint(a.value - (t1[d_0] ^ t2[d_2] ^ t3[d_4] ^ t4[d_6]));
171 b.value = (b.value + (t4[d_1] ^ t3[d_3] ^ t2[d_5] ^ t1[d_7])) & U64;
172 b.value = (b.value * mul) & U64;
173 }
175 _pass(a, b, c, mul) {
176 this._round(a, b, c, this._x0, mul);
177 this._round(b, c, a, this._x1, mul);
178 this._round(c, a, b, this._x2, mul);
179 this._round(a, b, c, this._x3, mul);
180 this._round(b, c, a, this._x4, mul);
181 this._round(c, a, b, this._x5, mul);
182 this._round(a, b, c, this._x6, mul);
183 this._round(b, c, a, this._x7, mul);
184 }
186 _split(message, block) {
187 this._x0 = message[block];
188 this._x1 = message[block + 1];
189 this._x2 = message[block + 2];
190 this._x3 = message[block + 3];
191 this._x4 = message[block + 4];
192 this._x5 = message[block + 5];
193 this._x6 = message[block + 6];
194 this._x7 = message[block + 7];
195 }
197 hash(input /*: string*/) /*: string*/ {
198 // Tiger's supplied implementation in C makes heavy use of imperative macros
199 // that overwrite the state of old values; specifically the `round` macro.
200 // this doesn't map to the lexical scoping and pass-by-value semantics of
201 // functions in JavaScript when passing primitives. Here, we mimic "inout"
202 // params or "references" with lightweight objects.
203 this._a = {value: 0x0123456789abcdefn};
204 this._b = {value: 0xfedcba9876543210n};
205 this._c = {value: 0xf096a5b4c3b2e187n};
206 const words = _getMessage(Buffer.from(input, this._encoding));
208 for (let block = 0; block < words.length; block += 8) {
209 this._split(words, block);
210 this._compress();
211 }
213 const digest = [this._a, this._b, this._c].map(n => _zeroFill(n)).join('');
214 const chars = this._digestBitLen / 4;
215 if (!this._invertByte) {
216 let inverted = '';
217 for (let i = 0; i < digest.length && i < chars; ++i) {
218 inverted += digest[inversion[i]];
219 }
220 return inverted;
221 }
222 return digest.substr(0, chars);
223 }
226Tiger.L128 = 128;
227Tiger.L160 = 160;
228Tiger.L192 = 192;
230Tiger.UTF8 = 'utf8';
231Tiger.UTF16 = 'utf16le';
233module.exports = Tiger;

SHA-256: 13dca90f874c4179bff7ab038ca65a28a56a382e36688967c74c159daeea456d

Archive SHA-256: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0