我正在将 ruby on rails 应用程序移植到 node.js,并且需要能够读取通过活动记录加密加密的数据。
看来使用的算法是aes-256-gcm,我这里有一个node.js脚本来加密和解密数据:
import crypto from 'crypto';
import config from './config';
const algorithm = 'aes-256-gcm';
const encrypt = (secret: string, originalData: string) => {
console.log('encrypting with ', {
secret,
originalData
});
const iv = crypto.randomBytes(16);
var crypt = crypto.createCipheriv(algorithm, Buffer.from(secret, 'base64'), iv);
var encoded = crypt.update(originalData, 'utf8', 'hex');
encoded += crypt.final('hex');
const at = crypt.getAuthTag();
return { encrypted: encoded, iv, at };
};
const decrypt = (secret: string, encryptedData: string, iv: string, at: string) => {
console.log('decrypting with ', {
secret,
encryptedData,
iv,
at
});
var crypt = crypto.createDecipheriv(algorithm, Buffer.from(secret, 'base64'), Buffer.from(iv, 'base64'));
crypt.setAuthTag(Buffer.from(at, 'base64'));
var decoded = crypt.update(encryptedData, 'hex', 'utf8');
decoded += crypt.final('utf8');
return decoded;
};
const secret = crypto.createHash('sha256').update('ThisIsASecretKey', 'ascii').digest();
const originalData = 'This is just a test to see what would happen';
const encryptionResult = encrypt(secret.toString('base64'), originalData);
const decryptionResult = decrypt(
secret.toString('base64'),
encryptionResult.encrypted,
encryptionResult.iv.toString('base64'),
encryptionResult.at.toString('base64')
);
这很好用,我得到了结果:
encrypting with {
secret: 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
originalData: 'This is just a test to see what would happen'
}
decrypting with {
secret: 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
encryptedData: '63eaf4dde9b1cc0e76d9d95725c85234ef2a742dd1c76a9579a8f03d20494cd85b658dcc3518b1ee9a5301b0',
iv: 'eloq0RQOnaFejiJzkQ7ybw==',
at: 'ylfqtCSRdMZLgnGC0wf3EA=='
}
Encryption data matches {
originalData: 'This is just a test to see what would happen',
encryptedData: '63eaf4dde9b1cc0e76d9d95725c85234ef2a742dd1c76a9579a8f03d20494cd85b658dcc3518b1ee9a5301b0',
decryptionResult: 'This is just a test to see what would happen'
}
但是,当我尝试使用 ruby 中的值时,它会抛出消息“不支持状态或无法验证数据”
我正在使用的 Rails 中的数据是从数据库中导出的,密钥是通过在 ruby 中运行以下命令导出的:
key_provider = ActiveRecord::Encryption.key_provider
key = key_provider.encryption_key
puts Base64.encode64(key.secret)
通过查看 ruby 源代码,这似乎是它加密/解密数据的方式:
require "openssl"
secret = Base64.strict_decode64("eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=")
clear_text = "This is some debug text"
puts "--------------- encrypt -------------"
CIPHER_TYPE = "aes-256-gcm"
cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
cipher.encrypt
cipher.key = secret
iv = cipher.random_iv
cipher.iv = iv
encrypted_data = clear_text.empty? ? clear_text.dup : cipher.update(clear_text)
encrypted_data << cipher.final
auth_tag = cipher.auth_tag
puts "clear_text="+clear_text
puts "secret="+Base64.strict_encode64(secret)
puts "iv="+Base64.strict_encode64(iv)
puts "auth_tag="+Base64.strict_encode64(auth_tag)
puts "encrypted_data="+Base64.strict_encode64(encrypted_data)
puts "--------------- /encrypt -------------"
puts "--------------- decrypt -------------"
begin
# secret = key.secret
# cipher = ActiveRecord::Encryption::Aes256Gcm.new(secret, deterministic: false)
# decrypted_data = cipher.decrypt(encrypted_message)
# puts decrypted_data
CIPHER_TYPE = "aes-256-gcm"
# encrypted_data = encrypted_message.payload
puts "encrypted_data=" + Base64.strict_encode64(encrypted_data)
# iv = encrypted_message.headers.iv
puts "iv=" + Base64.strict_encode64(iv)
# auth_tag = encrypted_message.headers.auth_tag
puts "auth_tag=" + Base64.strict_encode64(auth_tag)
cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
puts cipher
cipher.decrypt
cipher.key = secret
puts "secret=" + Base64.strict_encode64(secret)
cipher.iv = iv
cipher.auth_tag = auth_tag
cipher.auth_data = ""
decrypted_data = encrypted_data.empty? ? encrypted_data : cipher.update(encrypted_data)
decrypted_data << cipher.final
puts "decrypted_data=" + decrypted_data
end
puts "--------------- /decrypt -------------"
这给出了值:
app_1 | --------------- encrypt -------------
app_1 | clear_text=This is some debug text
app_1 | secret=eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=
app_1 | iv=377YrtFzBASSjvol
app_1 | auth_tag=QqQcyOhGKPP0sPFOANToFw==
app_1 | encrypted_data=LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=
app_1 | --------------- /encrypt -------------
app_1 | --------------- decrypt -------------
app_1 | encrypted_data=LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=
app_1 | iv=377YrtFzBASSjvol
app_1 | auth_tag=QqQcyOhGKPP0sPFOANToFw==
app_1 | #<OpenSSL::Cipher:0x0000558adf4ae830>
app_1 | secret=eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=
app_1 | decrypted_data=This is some debug text
app_1 | --------------- /decrypt -------------
但是在节点上运行这些值会给我同样的错误:
const debug = decrypt(
'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=',
'377YrtFzBASSjvol',
'qQcyOhGKPP0sPFOANToFw=='
);
Error: Unsupported state or unable to authenticate data
at Decipheriv.final (node:internal/crypto/cipher:193:29)
NodeJS 代码返回与 Ruby 代码相同的结果,如果
完整的 NodeJS 代码:
var crypto = require('crypto');
const algorithm = 'aes-256-gcm';
function encrypt(secret, originalData) {
console.log('encrypting with ', {
secret,
originalData
});
const iv = Buffer.from('377YrtFzBASSjvol', 'base64'); // crypto.randomBytes(16); // disabled for testing (in the final solution a random nonce MUST be applied for security reasons)
var crypt = crypto.createCipheriv(algorithm, Buffer.from(secret, 'base64'), iv);
var encoded = crypt.update(originalData, 'utf8', 'base64'); // Fix: Base64 encoding
encoded += crypt.final('base64'); // Fix: Base64 encoding
const at = crypt.getAuthTag();
return { encrypted: encoded, iv: iv.toString('base64'), at: at.toString('base64') };
};
function decrypt(secret, encryptedData, iv, at) {
console.log('decrypting with ', {
secret,
encryptedData,
iv,
at
});
var crypt = crypto.createDecipheriv(algorithm, Buffer.from(secret, 'base64'), Buffer.from(iv, 'base64'));
crypt.setAuthTag(Buffer.from(at, 'base64'));
var decoded = crypt.update(encryptedData, 'base64', 'utf8'); // Fix: Base64 encoding
decoded += crypt.final('utf8');
return decoded;
};
var originalData = 'This is some debug text';
var secret = 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs='; // Fix: No key derivation
const encryptionResult = encrypt(
secret,
originalData,
);
console.log(encryptionResult);
var secret = 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs='; // Fix: No key derivation
var encryptedData = 'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=';
var iv = '377YrtFzBASSjvol';
var at = 'QqQcyOhGKPP0sPFOANToFw==';
const decryptionResult = decrypt(
secret,
encryptedData,
iv,
at
);
console.log(decryptionResult);
输出:
encrypting with {
secret: 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
originalData: 'This is some debug text'
}
{
encrypted: 'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=',
iv: '377YrtFzBASSjvol',
at: 'QqQcyOhGKPP0sPFOANToFw=='
}
decrypting with {
secret: 'eKAyTQoTH0apq8+fsQYHSYelUy3mL34gl2M+rnvpXhs=',
encryptedData: 'LtbIG7tnBVtbMUlnvG+qtmoK2NgL+18=',
iv: '377YrtFzBASSjvol',
at: 'QqQcyOhGKPP0sPFOANToFw=='
}
This is some debug text
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句