mirror of
https://github.com/ubicloud/ubicloud.git
synced 2025-10-04 13:52:06 +08:00
Previously, wrapped DEKs written to `data_encryption_key.json` were encoded using `Base64.encode64`, which inserted a newline every 60 characters and always appended a trailing newline. Later, this was changed to `Base64.strict_encode64`, which produces a single uninterrupted string. While `Base64.decode64` can handle both formats, `Base64.strict_decode64` fails if newlines are present. Since `StorageKeyEncryption.read_encrypted_dek` is called when starting old VMs after a server reboot, it must remain backward compatible. This change updates `StorageKeyEncryption.read_encrypted_dek` to use `Base64.decode64`.
113 lines
3.1 KiB
Ruby
113 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../lib/storage_key_encryption"
|
|
require "openssl"
|
|
require "base64"
|
|
|
|
RSpec.describe StorageKeyEncryption do
|
|
subject(:sek) {
|
|
algorithm = "aes-256-gcm"
|
|
cipher = OpenSSL::Cipher.new(algorithm)
|
|
described_class.new({
|
|
"algorithm" => algorithm,
|
|
"key" => Base64.encode64(cipher.random_key),
|
|
"init_vector" => Base64.encode64(cipher.random_iv),
|
|
"auth_data" => "Ubicloud-Test-Auth"
|
|
})
|
|
}
|
|
|
|
it "can unwrap a wrapped key" do
|
|
key = "abcdefgh01234567abcdefgh01234567"
|
|
expect(sek.unwrap_key(sek.wrap_key(key))).to eq(key)
|
|
end
|
|
|
|
it "can wrap a key" do
|
|
dek = OpenSSL::Cipher.new("aes-256-xts").random_key.unpack1("H*")
|
|
r1 = sek.wrap_key(dek[..63])
|
|
expect(r1[0].length).to eq(64)
|
|
expect(r1[1].length).to eq(16)
|
|
r2 = sek.wrap_key(dek[64..])
|
|
expect(r2[0].length).to eq(64)
|
|
expect(r2[1].length).to eq(16)
|
|
end
|
|
|
|
it "fails if algorithm is not aes-256-gcm" do
|
|
sek2 = described_class.new({
|
|
"algorithm" => "aes256-wrap",
|
|
:key => "123",
|
|
:init_vector => "456"
|
|
})
|
|
|
|
expect {
|
|
sek2.unwrap_key("some key")
|
|
}.to raise_error RuntimeError, "currently only aes-256-gcm is supported"
|
|
|
|
expect {
|
|
sek2.wrap_key("some key")
|
|
}.to raise_error RuntimeError, "currently only aes-256-gcm is supported"
|
|
end
|
|
|
|
it "fails if auth_tag is not 16" do
|
|
key = "abcdefgh01234567abcdefgh01234567"
|
|
wrapped = sek.wrap_key(key)
|
|
wrapped[1] = wrapped[1][0]
|
|
|
|
expect {
|
|
sek.unwrap_key(wrapped)
|
|
}.to raise_error RuntimeError, "Invalid auth_tag size: 1"
|
|
end
|
|
|
|
describe "#read_encrypted_dek" do
|
|
let(:dek) {
|
|
k = OpenSSL::Cipher.new("aes-256-xts").random_key.unpack1("H*")
|
|
{key: k[..63], key2: k[64..]}
|
|
}
|
|
|
|
let(:wrapped_dek) {
|
|
{
|
|
key: sek.wrap_key(dek[:key]),
|
|
key2: sek.wrap_key(dek[:key2])
|
|
}
|
|
}
|
|
|
|
it "can read a file generated using strict_encode64" do
|
|
expect(File).to receive(:read).with("key-file").and_return(
|
|
JSON.pretty_generate({
|
|
cipher: "AES_XTS",
|
|
key: [
|
|
Base64.strict_encode64(wrapped_dek[:key][0]),
|
|
Base64.strict_encode64(wrapped_dek[:key][1])
|
|
],
|
|
key2: [
|
|
Base64.strict_encode64(wrapped_dek[:key2][0]),
|
|
Base64.strict_encode64(wrapped_dek[:key2][1])
|
|
]
|
|
})
|
|
)
|
|
|
|
read_key = sek.read_encrypted_dek("key-file")
|
|
expect(read_key[:key]).to eq(dek[:key])
|
|
expect(read_key[:key2]).to eq(dek[:key2])
|
|
end
|
|
|
|
it "can read a file generated using encode64" do
|
|
expect(File).to receive(:read).with("key-file").and_return(
|
|
JSON.pretty_generate({
|
|
cipher: "AES_XTS",
|
|
key: [
|
|
Base64.encode64(wrapped_dek[:key][0]),
|
|
Base64.encode64(wrapped_dek[:key][1])
|
|
],
|
|
key2: [
|
|
Base64.encode64(wrapped_dek[:key2][0]),
|
|
Base64.encode64(wrapped_dek[:key2][1])
|
|
]
|
|
})
|
|
)
|
|
|
|
read_key = sek.read_encrypted_dek("key-file")
|
|
expect(read_key[:key]).to eq(dek[:key])
|
|
expect(read_key[:key2]).to eq(dek[:key2])
|
|
end
|
|
end
|
|
end
|