Node.js で MySQL の AES_ENCRYPT 互換の暗号化
September 28, 2020
MySQL の AES_ENCRYPT 関数 #
https://dev.mysql.com/doc/refman/5.6/ja/encryption-functions.html#function_aes-encrypt
key_str にプレーンテキストを指定する場合 #
HEX 表現で以下の値が得られる。
mysql> SELECT HEX(AES_ENCRYPT('my_value', 'my_secret'));
+-------------------------------------------+
| HEX(AES_ENCRYPT('my_value', 'my_secret')) |
+-------------------------------------------+
| 6A6C5170A935FA5A70B8B1721EDAC3B7 |
+-------------------------------------------+
1 row in set (0.00 sec)
Node.js で同様の結果を得るロジックは以下の通り。
const crypto = require('crypto');
function convertCryptKey(strKey) {
let newKey = Buffer.from([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
strKey = Buffer.from(strKey);
for(let i=0; i < strKey.length; i++) newKey[i%16] ^= strKey[i];
return newKey;
}
const crypt_key = 'my_secret';
const c = crypto.createCipheriv("aes-128-ecb", convertCryptKey(crypt_key), "");
const b = c.update('my_value', 'utf8', 'hex') + c.final('hex');
const val = Buffer.from(b, 'hex');
console.log(val.toString('hex').toUpperCase());
6A6C5170A935FA5A70B8B1721EDAC3B7
mysqljs/mysql で INSERT して復号確認 #
上記 val
を mysqljs/mysql 経由で INSERT する。
const mysql = require('mysql');
const conn = require('mysql').createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'aes_encrypt_test'
});
const sql = `INSERT INTO aes_encrypt_test (col) VALUES (?)`;
conn.query(sql, val, (error, results) => {
if (error) throw error;
console.log(results);
conn.end();
});
MySQL 側で復号できている。
mysql> SELECT AES_DECRYPT(col, 'my_secret') FROM aes_encrypt_test;
+-------------------------------+
| AES_DECRYPT(col, 'my_secret') |
+-------------------------------+
| my_value |
+-------------------------------+
1 row in set (0.01 sec)
key_str に 128 ビット値のバイナリを指定する場合 #
mysql> SELECT HEX(AES_ENCRYPT('my_value', UNHEX('F3229A0B371ED2D9441B830D21A390C3')));
+-------------------------------------------------------------------------+
| HEX(AES_ENCRYPT('my_value', UNHEX('F3229A0B371ED2D9441B830D21A390C3'))) |
+-------------------------------------------------------------------------+
| BDECA05C489E3A5F63308C0F34D1DD08 |
+-------------------------------------------------------------------------+
1 row in set (0.00 sec)
crypt_key
を Buffer を利用して、以下のように変更すれば良い。
// const crypt_key = 'my_secret';
const crypt_key = Buffer.from('F3229A0B371ED2D9441B830D21A390C3', 'hex');
mysql> SELECT AES_DECRYPT(col, UNHEX('F3229A0B371ED2D9441B830D21A390C3')) FROM aes_encrypt_test;
+-------------------------------------------------------------+
| AES_DECRYPT(col, UNHEX('F3229A0B371ED2D9441B830D21A390C3')) |
+-------------------------------------------------------------+
| my_value |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
Hash 化したパスフレーズを指定する場合 #
mysql> SELECT HEX(AES_ENCRYPT('my_value', SHA2('my_secret',512)));
+-----------------------------------------------------+
| HEX(AES_ENCRYPT('my_value', SHA2('my_secret',512))) |
+-----------------------------------------------------+
| 8777A2DB65E26222698C5E829BE0946A |
+-----------------------------------------------------+
1 row in set (0.01 sec)
crypt_key
部分を以下に変更。
const crypt_key = crypto.createHash('sha512').update('my_secret').digest('hex');
mysql> SELECT AES_DECRYPT(col, SHA2('my_secret',512)) FROM aes_encrypt_test;
+-----------------------------------------+
| AES_DECRYPT(col, SHA2('my_secret',512)) |
+-----------------------------------------+
| my_value |
+-----------------------------------------+
1 row in set (0.00 sec)