我正在將 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)
uj5u.com熱心網友回復:
NodeJS 代碼回傳與 Ruby 代碼相同的結果,如果
- 不使用密鑰派生 (SHA256)
- 對于密文,應用 Base64 編碼而不是十六進制編碼
完整的 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
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/491381.html
標籤:节点.js 红宝石 加密 密码学 rails-activerecord
