问题:我们必须加密某个表(Postgres)上的某个列。它必须可以在我们的 Nodejs/sequelize 应用层的 SQL 查询和中解密。加密可以发生在任一层,但必须可以从任一层进行解码。
我遇到的问题(我确信这是用户错误)是,如果我在数据库中加密,我只能在数据库中解密,对于节点也是如此。
我尝试在 postgres 中使用
PGP_SYM_ENCRYPT
和 ENCRYPT
,在节点中使用 crypto
和 crypto-js/aes
。我已经得到它的解密没有错误,但返回乱码。
到目前为止我尝试过的一些事情(测试键是
thirtytwocharsthirtytwocharsplus
):
set() {
this.setDataValue('field', seq.cast(seq.fn('PGP_SYM_ENCRYPT', val,
config.AES_KEY), 'text'))
}
这正确地写入了字段,使得 PGP_SYM_DECRYPT 能够解密它,但是(显然?)没有办法告诉 Sequelize 用函数调用包装字段名称,所以我觉得有很多额外的 js 是可以避免的
const decipher = crypto.createDecipher('aes256', config.AES_KEY)
decipher.setAutoPadding(false);
return decipher.update(new Buffer(this.getDataValue('field', 'binary'), 'binary', 'ascii')) + decipher.final('ascii')
这将解码该字段,但返回乱码 (
�Mq��8Ya�b
) 而不是值 (test
)
aes.encrypt('test', config.AES_KEY)
aes.decrypt(field, config.AES_KEY).toString(CryptoJS.enc.Utf8)
这可以很好地加密,解密也很好,但是在尝试解密时 Postgres 会出错(使用
PGP_SYM_DECRYPT
或 DECRYPT
)。将结果字段转换为 ::TEXT
并将其粘贴到在线 AES 解密器中将返回预期值。
我真的想避免向我们的节点存储库/查询添加一堆样板,我真的觉得这应该可行。使用相同的加密算法应该会产生相同的结果
任何轻推或指示将不胜感激
Postgres 对于原始加密函数的文档相当不清楚。经过几次尝试和失败,我成功地在 Nodejs 中复制了大部分逻辑。
这是我使用的程序。
const crypto = require('crypto');
const iv = Buffer.alloc(16); // zeroed-out iv
function encrypt(plainText, algorithm, key) {
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(plainText, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
function decrypt(encrypted, algorithm, key) {
const decrypt = crypto.createDecipheriv(algorithm, key, iv);
let text = decrypt.update(encrypted, 'base64', 'utf8');
text += decrypt.final('utf8')
return text;
}
const originalText = "hello world";
const userKey = 'abcd'
const algorithm = 'aes-128-cbc';
const paddedKey = Buffer.concat([Buffer.from(userKey), Buffer.alloc(12)]); // make it 128 bits key
const hw = encrypt(originalText, algorithm, paddedKey);
console.log("original", originalText);
console.log("encrypted:", hw);
console.log("decoded: ", decrypt(hw, algorithm, paddedKey).toString());
这里还列出了未记录的 postgres 原始函数的内容:
aes-192-cbc
将用于加密如果 Postgres 有这些函数的适当文档,那么用应用程序语言(Javascript 或 Java)复制它会更容易。
我花了很多时间让它工作,我想我应该在这里发布我的完整打字稿解决方案,并希望为其他人节省一些时间。
这些函数对可存储在 postgres
text
或 varchar
字段中的字符串进行加密和解密。
import * as openpgp from 'openpgp';
const key = '<your-encryption-key>';
const hexPrefix = `${String.fromCharCode(92)}x`; // postgres needs a \x prefix
export async function encrypt(plainText: string): Promise<string> {
const message = await openpgp.createMessage({ text: plainText });
const encryptedBinary = await openpgp.encrypt({
message,
passwords: key,
format: 'binary',
config: {
preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256,
preferredCompressionAlgorithm: openpgp.enums.compression.zip,
},
});
const encryptedHex = Buffer.from(encryptedBinary).toString('hex');
return `${hexPrefix}${encryptedHex}`;
}
export async function decrypt(hexFromPostgres: string): Promise<string> {
const trimmedHex = hexFromPostgres.slice(hexPrefix.length); // remove `\x' from beginning
const binaryToDecrypt = Uint8Array.from(Buffer.from(trimmedHex, 'hex'));
const decrypted = await openpgp.decrypt({
message: await openpgp.readMessage({ binaryMessage: binaryToDecrypt }),
passwords: key,
});
return decrypted.data;
}
可以在 postgres 中对字符串进行加密和解密
pgp_sym_encrypt('message to encrypt', '<your-encryption-key', 'compress-algo=1, cipher-algo=aes256')
pgp_sym_decrypt(<column-name>::bytea, '<your-encryption-key')
好的,我已经成功了,希望能正常
我所做的是:
在node中使用
crypto.createCipheriv('aes-256-cbc', new Buffer(config.AES_KEY), iv)
加密,在pgsql中使用encrypt_iv
加密并在数据库中存储为hex
,并使用crypto.createDecipheriv
/decrypt_iv
解密为text
/utf8
我不知道我错过了哪一部分,但是在指定
aes256
、使用 iv
方法以及翻转十六进制/文本之间,它似乎有效。
👍
对我来说,它采用了上面 KLPainter 建议的类似方法 https://stackoverflow.com/a/75861980/13757228
但是稍微修正一下,如下:
const key = "<your-encryption-key>";
const decrypt = async (hexFromPostgres) => {
try {
// issue was here it removes 3/4 chars instead of just 2 chars so I manually removed the '\x' and defined it as trimmedHex
// const trimmedHex = hexFromPostgres.slice(hexPrefix.length);
// remove `\x' from beginning
// hexFromPostgres = "\x92eb5bf752d8dthisiissample";
const trimmedHex = "92eb5bf752d8dthisiissample";
const binaryToDecrypt = Uint8Array.from(Buffer.from(trimmedHex, "hex"));
const encryptedMsg = await openpgp.readMessage({
binaryMessage: binaryToDecrypt,
});
const decrypted = await openpgp.decrypt({
message: encryptedMsg,
passwords: [key], // here added key in array
format: "binary", // defined the format as binary
});
const string = new TextDecoder().decode(decrypted.data);
console.log(string);
return string;
} catch (e) {
console.log("---error while decryption: ", e);
}
return `test`;
};
希望这对您有帮助