sma: added tweak mode in sma crypto

AES-XTS requires providing tweak. By definition tweak (128bits)
represents logical position of the data being encrypted or decrypted,
typically for nvme it is LBA.
Various implementations of AES-XTS can treat that requirment
in different way, because AES-XTS specification doesn't define
how exactly tweak look like and how exactly LBA is transformed
into tweak  For example:
 - Tweak[127:0] = {1’b0, ~LBA[62:0], LBA[63:0]}
 - Tweak[127:0] = {LBA[127:0] + 1}
 - Tweak[127:0] = {LBA[63:0] + 1, 64'b0}

So there's a need of specifying mode of tweak

Signed-off-by: Michal Rozegnal <michal.rozegnal@intel.com>
Change-Id: I92edc71f5f4dfeb0d08a34b73424675321e4740e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16058
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Jacek Kalwas <jacek.kalwas@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Michal Rozegnal 2022-12-22 12:05:24 +01:00 committed by Tomasz Zawadzki
parent b82f1987b9
commit 3408399172
4 changed files with 41 additions and 12 deletions

View File

@ -33,6 +33,26 @@ message VolumeCryptoParameters {
} }
// Cipher to use // Cipher to use
Cipher cipher = 3; Cipher cipher = 3;
// Tweak mode - determine how nvme LBA is converted into tweak
enum TweakMode {
// default for SPDK bdev_crypto
// Tweak[127:0] = {64'b0, LBA[63:0]}
TWEAK_MODE_SIMPLE_LBA = 0;
// Tweak[127:0] = {1b0, ~LBA[62:0], LBA[63:0]}
TWEAK_MODE_NOT_AND_LBA = 1;
// tweak is derived from nvme LBA that is internally incremented by 1 for every 512 bytes processed
// so initial lba = (BLOCK_SIZE_IN_BYTES / 512) * LBA
// Tweak[127:0] = {lba[127:0]}
TWEAK_MODE_FORCE_512_FULL = 2;
// tweak is derived from nvme LBA that is internally incremented by 1 for every 512 bytes processed
// so initial lba = (BLOCK_SIZE_IN_BYTES / 512) * LBA
// Tweak[127:0] = {lba[63:0], 64'b0}
TWEAK_MODE_FORCE_512_UPPER = 3;
}
TweakMode tweak_mode = 4;
} }
// Parameters describing a volume // Parameters describing a volume

View File

@ -23,7 +23,7 @@ class CryptoEngine:
"""Initialize crypto engine""" """Initialize crypto engine"""
self._client = client self._client = client
def setup(self, volume_id, key, cipher, key2=None): def setup(self, volume_id, key, cipher, key2=None, tweak_mode=None):
"""Set up crypto on a given volume""" """Set up crypto on a given volume"""
raise NotImplementedError() raise NotImplementedError()
@ -34,7 +34,7 @@ class CryptoEngine:
""" """
raise NotImplementedError() raise NotImplementedError()
def verify(self, volume_id, key, cipher, key2=None): def verify(self, volume_id, key, cipher, key2=None, tweak_mode=None):
""" """
Verify that specified crypto parameters match those that are currently deployed on a given Verify that specified crypto parameters match those that are currently deployed on a given
volume. If key is None, this mehtod ensures that the volume doesn't use crypto. If volume. If key is None, this mehtod ensures that the volume doesn't use crypto. If
@ -56,13 +56,13 @@ class CryptoEngineNop(CryptoEngine):
def __init__(self): def __init__(self):
super().__init__('nop') super().__init__('nop')
def setup(self, volume_id, key, cipher, key2=None): def setup(self, volume_id, key, cipher, key2=None, tweak_mode=None):
raise CryptoException(grpc.StatusCode.INVALID_ARGUMENT, 'Crypto is disabled') raise CryptoException(grpc.StatusCode.INVALID_ARGUMENT, 'Crypto is disabled')
def cleanup(self, volume_id): def cleanup(self, volume_id):
pass pass
def verify(self, volume_id, key, cipher, key2=None): def verify(self, volume_id, key, cipher, key2=None, tweak_mode=None):
pass pass
def get_crypto_bdev(self, volume_id): def get_crypto_bdev(self, volume_id):

View File

@ -26,7 +26,7 @@ class CryptoEngineBdev(crypto.CryptoEngine):
# _driver can be None # _driver can be None
self._driver = params.get('driver') self._driver = params.get('driver')
def setup(self, volume_id, key, cipher, key2=None): def setup(self, volume_id, key, cipher, key2=None, tweak_mode=None):
try: try:
with self._client() as client: with self._client() as client:
cipher = self._ciphers.get(cipher) cipher = self._ciphers.get(cipher)
@ -41,6 +41,10 @@ class CryptoEngineBdev(crypto.CryptoEngine):
params['crypto_pmd'] = self._driver params['crypto_pmd'] = self._driver
if key2 is not None: if key2 is not None:
params['key2'] = key2 params['key2'] = key2
if tweak_mode is not None and tweak_mode != sma_pb2.VolumeCryptoParameters.TWEAK_MODE_SIMPLE_LBA:
raise crypto.CryptoException(grpc.StatusCode.INVALID_ARGUMENT,
'Invalid volume crypto configuration: bad tweak_mode')
log.info('Creating crypto bdev: {} on volume: {}'.format( log.info('Creating crypto bdev: {} on volume: {}'.format(
params['name'], volume_id)) params['name'], volume_id))
client.call('bdev_crypto_create', params) client.call('bdev_crypto_create', params)
@ -62,7 +66,7 @@ class CryptoEngineBdev(crypto.CryptoEngine):
raise crypto.CryptoException(grpc.StatusCode.INTERNAL, raise crypto.CryptoException(grpc.StatusCode.INTERNAL,
'Failed to delete crypto bdev') 'Failed to delete crypto bdev')
def verify(self, volume_id, key, cipher, key2=None): def verify(self, volume_id, key, cipher, key2=None, tweak_mode=None):
crypto_bdev = self._get_crypto_bdev(volume_id) crypto_bdev = self._get_crypto_bdev(volume_id)
# Key being None/non-None defines whether we expect a bdev_crypto on top of a given volume # Key being None/non-None defines whether we expect a bdev_crypto on top of a given volume
if ((key is None and crypto_bdev is not None) or (key is not None and crypto_bdev is None)): if ((key is None and crypto_bdev is not None) or (key is not None and crypto_bdev is None)):
@ -91,6 +95,9 @@ class CryptoEngineBdev(crypto.CryptoEngine):
if crypto_key['name'].lower() != params['key_name'].lower(): if crypto_key['name'].lower() != params['key_name'].lower():
raise crypto.CryptoException(grpc.StatusCode.INVALID_ARGUMENT, raise crypto.CryptoException(grpc.StatusCode.INVALID_ARGUMENT,
'Invalid volume crypto configuration: key name does not match') 'Invalid volume crypto configuration: key name does not match')
if tweak_mode is not None and tweak_mode != sma_pb2.VolumeCryptoParameters.TWEAK_MODE_SIMPLE_LBA:
raise crypto.CryptoException(grpc.StatusCode.INVALID_ARGUMENT,
'Invalid volume crypto configuration: bad tweak_mode')
def _get_crypto_bdev(self, volume_id): def _get_crypto_bdev(self, volume_id):
try: try:

View File

@ -163,23 +163,25 @@ class VolumeManager:
'Failed to stop discovery') 'Failed to stop discovery')
def _get_crypto_params(self, params): def _get_crypto_params(self, params):
key, cipher, key2 = None, None, None key, cipher, key2, tweak_mode = None, None, None, None
try: try:
if params.HasField('crypto'): if params.HasField('crypto'):
key, cipher = params.crypto.key.decode('ascii'), params.crypto.cipher key, cipher = params.crypto.key.decode('ascii'), params.crypto.cipher
if len(params.crypto.key2) > 0: if len(params.crypto.key2) > 0:
key2 = params.crypto.key2.decode('ascii') key2 = params.crypto.key2.decode('ascii')
if params.crypto.tweak_mode is not None:
tweak_mode = params.crypto.tweak_mode
except UnicodeDecodeError: except UnicodeDecodeError:
raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT, raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT,
'Corrupted crypto key') 'Corrupted crypto key')
return key, cipher, key2 return key, cipher, key2, tweak_mode
def _setup_crypto(self, volume_id, params): def _setup_crypto(self, volume_id, params):
try: try:
if not params.HasField('crypto'): if not params.HasField('crypto'):
return return
key, cipher, key2 = self._get_crypto_params(params) key, cipher, key2, tweak_mode = self._get_crypto_params(params)
crypto.get_crypto_engine().setup(volume_id, key, cipher, key2) crypto.get_crypto_engine().setup(volume_id, key, cipher, key2, tweak_mode)
except crypto.CryptoException as ex: except crypto.CryptoException as ex:
raise VolumeException(ex.code, ex.message) raise VolumeException(ex.code, ex.message)
@ -191,8 +193,8 @@ class VolumeManager:
def _verify_crypto(self, volume_id, params): def _verify_crypto(self, volume_id, params):
try: try:
key, cipher, key2 = self._get_crypto_params(params) key, cipher, key2, tweak_mode = self._get_crypto_params(params)
crypto.get_crypto_engine().verify(volume_id, key, cipher, key2) crypto.get_crypto_engine().verify(volume_id, key, cipher, key2, tweak_mode)
except crypto.CryptoException as ex: except crypto.CryptoException as ex:
raise VolumeException(ex.code, ex.message) raise VolumeException(ex.code, ex.message)