src/lib/y2storage/planned/can_be_encrypted.rb
# Copyright (c) [2015-2017] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.
require "yast"
require "y2storage/secret_attributes"
require "y2storage/encryption"
module Y2Storage
module Planned
# Mixin for planned devices that can have an encryption layer on top.
# @see Planned::Device
module CanBeEncrypted
include SecretAttributes
# This value matches Storage::Luks.metadata_size, which is not exposed in
# the libstorage API
ENCRYPTION_OVERHEAD = DiskSize.MiB(2)
private_constant :ENCRYPTION_OVERHEAD
# @!attribute encryption_method
# @return [EncryptionMethod::Base, nil] method used to encrypt the device. If is nil,
# it means the device will not be encrypted
attr_accessor :encryption_method
# @!attribute encryption_password
# @return [String, nil] password used to encrypt the device.
secret_attr :encryption_password
# PBKDF to use when encrypting the device if such property makes sense (eg. LUKS2)
#
# @return [PbkdFunction, nil] nil to use the default derivation function
attr_accessor :encryption_pbkdf
# LUKS label to use for the device if labels are supported (eg. LUKS2)
#
# @return [String, nil] nil or empty string to not set any label
attr_accessor :encryption_label
# Cipher to use when encrypting a LUKS device
#
# @return [String, nil] nil or empty string to use the default cipher
attr_accessor :encryption_cipher
# Key size (in bits) to use when encrypting a LUKS device
#
# Any positive value must be a multiple of 8.
#
# Note this uses bits since that's the standard unit for the key size in LUKS and is
# also the unit used by cryptsetup for all its inputs and outputs.
#
# Under the hood, this is translated to bytes because that's what libstorage-ng uses.
#
# @return [Integer, nil] nil or zero to use the default size
attr_accessor :encryption_key_size
# Initializations of the mixin, to be called from the class constructor.
def initialize_can_be_encrypted; end
# Checks whether the resulting device must be encrypted
#
# @return [Boolean]
def encrypt?
!!(encryption_method || encryption_password)
end
# Determines whether the device can be ciphered using the given encryption method
#
# @param method [EncryptionMethod] Encryption method
# @return [Boolean]
def supported_encryption_method?(method)
!method.only_for_swap? || swap?
end
# Returns the (possibly encrypted) device to be used for the planned
# device.
#
# If encryption is requested by the planned device, the method will
# encrypt the plain device and will return the corresponding encrypted
# one. Otherwise, it will simply return the plain device.
#
# FIXME: temporary API. It should be improved.
#
# @param plain_device [BlkDevice]
# @return [BlkDevice]
def final_device!(plain_device)
result = super
if create_encryption?
method = encryption_method || EncryptionMethod.find(:luks1)
result = plain_device.encrypt(method: method, password: encryption_password)
assign_enc_attr(result, :pbkdf)
assign_enc_attr(result, :label)
assign_enc_attr(result, :cipher)
assign_enc_attr(result, :key_size) { |value| value / 8 }
log.info "Device encrypted. Returning the new device #{result.inspect}"
else
log.info "No need to encrypt. Returning the existing device #{result.inspect}"
end
result
end
def self.included(base)
base.extend(ClassMethods)
end
protected
def create_encryption?
return false unless encrypt?
return true unless reuse?
return reformat? if respond_to?(:reformat?)
false
end
# Assigns the corresponding attribute to the encryption object if it makes sense
#
# @see #final_device!
#
# A block can be passed to transform the value of the attribute
#
# @param encryption [Encryption]
# @param attr [Symbol, String]
def assign_enc_attr(encryption, attr)
value = send(:"encryption_#{attr}")
return if value.nil?
return unless encryption.send(:"supports_#{attr}?")
value = yield(value) if block_given?
encryption.send(:"#{attr}=", value)
end
# Class methods for the mixin
module ClassMethods
# Space that will be used by the encryption data structures in a device.
# I.e. how much smaller will be an encrypted device compared to the plain
# one.
#
# @return [DiskSize]
def encryption_overhead
ENCRYPTION_OVERHEAD
end
end
end
end
end