-
Notifications
You must be signed in to change notification settings - Fork 2
/
auth_41.ts
111 lines (87 loc) · 2.91 KB
/
auth_41.ts
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
SERVER: public_seed=create_random_string()
send(public_seed)
CLIENT: recv(public_seed)
hash_stage1=sha1("password")
hash_stage2=sha1(hash_stage1)
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
// this three steps are done in scramble()
send(reply)
SERVER: recv(reply)
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
candidate_hash2=sha1(hash_stage1)
check(candidate_hash2==hash_stage2)
server stores sha1(sha1(password)) ( hash_stag2)
*/
import {
Buffer,
createHash,
} from "../deps.ts";
function sha1(msg: Buffer|string, msg1?: Buffer|string, msg2?: Buffer|string) {
const hash = createHash('sha1');
hash.update(msg);
if (msg1) {
hash.update(msg1);
}
if (msg2) {
hash.update(msg2);
}
return hash.digest() as Buffer;
}
export function xor(a: Buffer|string, b: Buffer|string) {
if (!Buffer.isBuffer(a)) {
a = Buffer.from(a, 'binary');
}
if (!Buffer.isBuffer(b)) {
b = Buffer.from(b, 'binary');
}
const result = Buffer.allocUnsafe(a.length);
for (let i = 0; i < a.length; i++) {
result[i] = a[i] ^ b[i];
}
return result;
}
function token(password: string, scramble1: Buffer, scramble2: Buffer) {
// TODO: use buffers (not sure why strings here)
if (!password) {
return Buffer.alloc(0);
}
const stage1 = sha1(password);
return calculateTokenFromPasswordSha(stage1, scramble1, scramble2);
}
export function calculateTokenFromPasswordSha(
passwordSha: Buffer|string,
scramble1: Buffer,
scramble2: Buffer,
) {
// we use AUTH 41 here, and we need only the bytes we just need.
const authPluginData1 = scramble1.slice(0, 8);
const authPluginData2 = scramble2.slice(0, 12);
const stage2 = sha1(passwordSha);
const stage3 = sha1(authPluginData1, authPluginData2, stage2);
return xor(stage3, passwordSha);
}
export const calculateToken = token;
export function verifyToken(publicSeed1: string | Buffer, publicSeed2: string | Buffer, token: string | Buffer, doubleSha: string | Buffer) {
const hashStage1 = xor(token, sha1(publicSeed1, publicSeed2, doubleSha));
const candidateHash2 = sha1(hashStage1);
return candidateHash2.compare(Buffer.from(doubleSha)) === 0;
}
export function doubleSha1(password: string) {
return sha1(sha1(password));
}
export function xorRotating(a: string | Buffer, seed: string | Buffer) {
if (!Buffer.isBuffer(a)) {
a = Buffer.from(a, 'binary');
}
if (!Buffer.isBuffer(seed)) {
seed = Buffer.from(seed, 'binary');
}
const result = Buffer.allocUnsafe(a.length);
const seedLen = seed.length;
for (let i = 0; i < a.length; i++) {
result[i] = a[i] ^ seed[i % seedLen];
}
return result;
}