从节点脚本读取Ruby主动记录加密
我正在将Ruby放置在Rails Application到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中的值时,传达消息“未支撑状态或无法验证数据”,
我使用的来自数据库的数据的数据是从数据库中导出的,并且通过在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)
I'm porting a ruby on rails application to node.js, and need to be able to read the data encrypted via active record encryption.
It seems that the algorithm used is aes-256-gcm, and I've got a node.js script here to encrypt and decrypt data:
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')
);
This works fine and I get the result:
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'
}
However when I try and use the values from ruby it throws the message "Unsupported state or unable to authenticate data"
The data from rails I'm using is exported from the database, with the key exported via running the following in ruby:
key_provider = ActiveRecord::Encryption.key_provider
key = key_provider.encryption_key
puts Base64.encode64(key.secret)
And from looking through the ruby source code this appears to be how it encrypts/decrypts the data:
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 -------------"
Which gives the values:
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 -------------
However running these values on node gives me the same error:
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
NodeJS代码返回与Ruby Code相同的结果,如果
完整的Nodejs代码:
输出:输出:输出:输出:
The NodeJS code returns the same results as the Ruby code if
Full NodeJS code:
Output: