Skip to content

Commit 758f829

Browse files
committed
support cacheing-sha2
1 parent f2fe8d9 commit 758f829

File tree

4 files changed

+77
-29
lines changed

4 files changed

+77
-29
lines changed

lib/auth_plugins/caching_sha2_password.js

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// https://mysqlserverteam.com/mysql-8-0-4-new-default-authentication-plugin-caching_sha2_password/
44

55
const PLUGIN_NAME = 'caching_sha2_password';
6-
const crypto = require('crypto');
6+
const crypto = require('../utils/crypto');
77
const { xor, xorRotating } = require('../auth_41');
88

99
const REQUEST_SERVER_KEY_PACKET = Buffer.from([2]);
@@ -15,28 +15,22 @@ const STATE_TOKEN_SENT = 1;
1515
const STATE_WAIT_SERVER_KEY = 2;
1616
const STATE_FINAL = -1;
1717

18-
function sha256(msg) {
19-
const hash = crypto.createHash('sha256');
20-
hash.update(msg);
21-
return hash.digest();
22-
}
23-
24-
function calculateToken(password, scramble) {
18+
async function calculateToken(password, scramble) {
2519
if (!password) {
2620
return Buffer.alloc(0);
2721
}
28-
const stage1 = sha256(Buffer.from(password));
29-
const stage2 = sha256(stage1);
30-
const stage3 = sha256(Buffer.concat([stage2, scramble]));
22+
const stage1 = await crypto.sha256(Buffer.from(password));
23+
const stage2 = await crypto.sha256(stage1);
24+
const stage3 = await crypto.sha256(Buffer.concat([stage2, scramble]));
3125
return xor(stage1, stage3);
3226
}
3327

34-
function encrypt(password, scramble, key) {
28+
async function encrypt(password, scramble, key) {
3529
const stage1 = xorRotating(
3630
Buffer.from(`${password}\0`, 'utf8'),
3731
scramble
3832
);
39-
return crypto.publicEncrypt(key, stage1);
33+
return await crypto.publicEncrypt(key, stage1);
4034
}
4135

4236
module.exports = (pluginOptions = {}) => ({ connection }) => {
@@ -45,18 +39,18 @@ module.exports = (pluginOptions = {}) => ({ connection }) => {
4539

4640
const password = connection.config.password;
4741

48-
const authWithKey = serverKey => {
49-
const _password = encrypt(password, scramble, serverKey);
42+
const authWithKey = async serverKey => {
43+
const _password = await encrypt(password, scramble, serverKey);
5044
state = STATE_FINAL;
5145
return _password;
5246
};
5347

54-
return data => {
48+
return async data => {
5549
switch (state) {
5650
case STATE_INITIAL:
5751
scramble = data.slice(0, 20);
5852
state = STATE_TOKEN_SENT;
59-
return calculateToken(password, scramble);
53+
return await calculateToken(password, scramble);
6054

6155
case STATE_TOKEN_SENT:
6256
if (FAST_AUTH_SUCCESS_PACKET.equals(data)) {
@@ -76,7 +70,7 @@ module.exports = (pluginOptions = {}) => ({ connection }) => {
7670

7771
// if client provides key we can save one extra roundrip on first connection
7872
if (pluginOptions.serverPublicKey) {
79-
return authWithKey(pluginOptions.serverPublicKey);
73+
return await authWithKey(pluginOptions.serverPublicKey);
8074
}
8175

8276
state = STATE_WAIT_SERVER_KEY;
@@ -89,7 +83,7 @@ module.exports = (pluginOptions = {}) => ({ connection }) => {
8983
if (pluginOptions.onServerPublicKey) {
9084
pluginOptions.onServerPublicKey(data);
9185
}
92-
return authWithKey(data);
86+
return await authWithKey(data);
9387
case STATE_FINAL:
9488
throw new Error(
9589
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`

lib/auth_plugins/sha256_password.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
const PLUGIN_NAME = 'sha256_password';
4-
const crypto = require('crypto');
4+
const crypto = require('../utils/crypto');
55
const { xorRotating } = require('../auth_41');
66

77
const REQUEST_SERVER_KEY_PACKET = Buffer.from([1]);
@@ -10,12 +10,12 @@ const STATE_INITIAL = 0;
1010
const STATE_WAIT_SERVER_KEY = 1;
1111
const STATE_FINAL = -1;
1212

13-
function encrypt(password, scramble, key) {
13+
async function encrypt(password, scramble, key) {
1414
const stage1 = xorRotating(
1515
Buffer.from(`${password}\0`, 'utf8'),
1616
scramble
1717
);
18-
return crypto.publicEncrypt(key, stage1);
18+
return await crypto.publicEncrypt(key, stage1);
1919
}
2020

2121
module.exports = (pluginOptions = {}) => ({ connection }) => {
@@ -24,19 +24,19 @@ module.exports = (pluginOptions = {}) => ({ connection }) => {
2424

2525
const password = connection.config.password;
2626

27-
const authWithKey = serverKey => {
28-
const _password = encrypt(password, scramble, serverKey);
27+
const authWithKey = async serverKey => {
28+
const _password = await encrypt(password, scramble, serverKey);
2929
state = STATE_FINAL;
3030
return _password;
3131
};
3232

33-
return data => {
33+
return async data => {
3434
switch (state) {
3535
case STATE_INITIAL:
3636
scramble = data.slice(0, 20);
3737
// if client provides key we can save one extra roundrip on first connection
3838
if (pluginOptions.serverPublicKey) {
39-
return authWithKey(pluginOptions.serverPublicKey);
39+
return await authWithKey(pluginOptions.serverPublicKey);
4040
}
4141

4242
state = STATE_WAIT_SERVER_KEY;
@@ -46,7 +46,7 @@ module.exports = (pluginOptions = {}) => ({ connection }) => {
4646
if (pluginOptions.onServerPublicKey) {
4747
pluginOptions.onServerPublicKey(data);
4848
}
49-
return authWithKey(data);
49+
return await authWithKey(data);
5050
case STATE_FINAL:
5151
throw new Error(
5252
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`

lib/utils/nodecrypto.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ async function sha1(msg,msg1,msg2) {
1616
return hash.digest();
1717
}
1818

19+
async function sha256(msg) {
20+
const hash = nodeCrypto.createHash('sha256');
21+
hash.update(msg);
22+
return hash.digest();
23+
}
24+
25+
async function publicEncrypt(key,buffer) {
26+
return nodeCrypto.publicEncrypt(key,buffer);
27+
}
28+
1929
module.exports = {
20-
sha1
30+
sha1,
31+
sha256,
32+
publicEncrypt
2133
}

lib/utils/webcrypto.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,48 @@ async function sha1(msg,msg1,msg2) {
3434
return Buffer.from(arrayBuffer)
3535
}
3636

37+
async function sha256(msg) {
38+
const arrayBuffer = await subtleCrypto.digest('SHA-256', typeof msg === 'string' ? textEncoder.encode(msg) : msg)
39+
return Buffer.from(arrayBuffer)
40+
}
41+
42+
function decodeBase64(b64) {
43+
const binString = atob(b64);
44+
const size = binString.length;
45+
const bytes = new Uint8Array(size);
46+
for (let i = 0; i < size; i++) {
47+
bytes[i] = binString.charCodeAt(i);
48+
}
49+
return bytes;
50+
}
51+
52+
// need more test
53+
async function publicEncrypt(key, data) {
54+
const pemHeader = "-----BEGIN PUBLIC KEY-----\n";
55+
const pemFooter = "\n-----END PUBLIC KEY-----";
56+
key = key.trim();
57+
key = key.substring(pemHeader.length, key.length - pemFooter.length);
58+
59+
const importedKey = await subtleCrypto.importKey(
60+
"spki",
61+
decodeBase64(key),
62+
{ name: "RSA-OAEP", hash: "SHA-256" },
63+
false,
64+
["encrypt"],
65+
);
66+
67+
const encryptedData = await subtleCrypto.encrypt(
68+
{
69+
name: "RSA-OAEP",
70+
},
71+
importedKey,
72+
data,
73+
);
74+
return Buffer.from(encryptedData)
75+
}
76+
3777
module.exports = {
38-
sha1
78+
sha1,
79+
sha256,
80+
publicEncrypt
3981
}

0 commit comments

Comments
 (0)