Commit c543af83 authored by Michal Rozegnal's avatar Michal Rozegnal Committed by Jim Harris
Browse files

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: default avatarMichal Rozegnal <michal.rozegnal@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16058

 (master)

(cherry picked from commit 34083991)
Change-Id: I92edc71f5f4dfeb0d08a34b73424675321e4740e
Signed-off-by: default avatarKrzysztof Karas <krzysztof.karas@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16483


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent e2409055
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -33,6 +33,26 @@ message VolumeCryptoParameters {
  }
  // Cipher to use
  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] = {1’b0, ~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
+4 −4
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ class CryptoEngine:
        """Initialize crypto engine"""
        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"""
        raise NotImplementedError()

@@ -34,7 +34,7 @@ class CryptoEngine:
        """
        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
        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):
        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')

    def cleanup(self, volume_id):
        pass

    def verify(self, volume_id, key, cipher, key2=None):
    def verify(self, volume_id, key, cipher, key2=None, tweak_mode=None):
        pass

    def get_crypto_bdev(self, volume_id):
+9 −2
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ class CryptoEngineBdev(crypto.CryptoEngine):
        # _driver can be None
        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:
            with self._client() as client:
                cipher = self._ciphers.get(cipher)
@@ -41,6 +41,10 @@ class CryptoEngineBdev(crypto.CryptoEngine):
                    params['crypto_pmd'] = self._driver
                if key2 is not None:
                    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(
                            params['name'], volume_id))
                client.call('bdev_crypto_create', params)
@@ -62,7 +66,7 @@ class CryptoEngineBdev(crypto.CryptoEngine):
            raise crypto.CryptoException(grpc.StatusCode.INTERNAL,
                                         '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)
        # 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)):
@@ -91,6 +95,9 @@ class CryptoEngineBdev(crypto.CryptoEngine):
        if crypto_key['name'].lower() != params['key_name'].lower():
            raise crypto.CryptoException(grpc.StatusCode.INVALID_ARGUMENT,
                                         '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):
        try:
+8 −6
Original line number Diff line number Diff line
@@ -163,23 +163,25 @@ class VolumeManager:
                                  'Failed to stop discovery')

    def _get_crypto_params(self, params):
        key, cipher, key2 = None, None, None
        key, cipher, key2, tweak_mode = None, None, None, None
        try:
            if params.HasField('crypto'):
                key, cipher = params.crypto.key.decode('ascii'), params.crypto.cipher
                if len(params.crypto.key2) > 0:
                    key2 = params.crypto.key2.decode('ascii')
                if params.crypto.tweak_mode is not None:
                    tweak_mode = params.crypto.tweak_mode
        except UnicodeDecodeError:
            raise VolumeException(grpc.StatusCode.INVALID_ARGUMENT,
                                  'Corrupted crypto key')
        return key, cipher, key2
        return key, cipher, key2, tweak_mode

    def _setup_crypto(self, volume_id, params):
        try:
            if not params.HasField('crypto'):
                return
            key, cipher, key2 = self._get_crypto_params(params)
            crypto.get_crypto_engine().setup(volume_id, key, cipher, key2)
            key, cipher, key2, tweak_mode = self._get_crypto_params(params)
            crypto.get_crypto_engine().setup(volume_id, key, cipher, key2, tweak_mode)
        except crypto.CryptoException as ex:
            raise VolumeException(ex.code, ex.message)

@@ -191,8 +193,8 @@ class VolumeManager:

    def _verify_crypto(self, volume_id, params):
        try:
            key, cipher, key2 = self._get_crypto_params(params)
            crypto.get_crypto_engine().verify(volume_id, key, cipher, key2)
            key, cipher, key2, tweak_mode = self._get_crypto_params(params)
            crypto.get_crypto_engine().verify(volume_id, key, cipher, key2, tweak_mode)
        except crypto.CryptoException as ex:
            raise VolumeException(ex.code, ex.message)