Postgres 和 Node 之间的加密/解密

问题描述 投票:0回答:4

问题:我们必须加密某个表(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 解密器中将返回预期值。

真的想避免向我们的节点存储库/查询添加一堆样板,我真的觉得这应该可行。使用相同的加密算法应该会产生相同的结果

任何轻推或指示将不胜感激

node.js postgresql encryption aes
4个回答
3
投票

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 原始函数的内容:

  • 密钥将自动填充以匹配 3 个长度之一:128 位、192 位、256 位
  • 当密钥长度超过限制时,算法自动升级。例如如果密钥超过128位,
    aes-192-cbc
    将用于加密
  • 如果密钥超过256位,它将被截断为256位。

如果 Postgres 有这些函数的适当文档,那么用应用程序语言(Javascript 或 Java)复制它会更容易。


1
投票

我花了很多时间让它工作,我想我应该在这里发布我的完整打字稿解决方案,并希望为其他人节省一些时间。

这些函数对可存储在 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')

0
投票

好的,我已经成功了,希望能正常

我所做的是:

在node中使用

crypto.createCipheriv('aes-256-cbc', new Buffer(config.AES_KEY), iv)
加密,在pgsql中使用
encrypt_iv
加密并在数据库中存储为
hex
,并使用
crypto.createDecipheriv
/
decrypt_iv
解密为
text
/
utf8

我不知道我错过了哪一部分,但是在指定

aes256
、使用
iv
方法以及翻转十六进制/文本之间,它似乎有效。

👍


0
投票

对我来说,它采用了上面 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`;
};

希望这对您有帮助

© www.soinside.com 2019 - 2024. All rights reserved.