< Summary

Class:Azure.Security.KeyVault.Keys.Cryptography.AesKw
Assembly:Azure.Security.KeyVault.Keys
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\Cryptography\AesKw.cs
Covered lines:106
Uncovered lines:29
Coverable lines:135
Total lines:422
Line coverage:78.5% (106 of 135)
Covered branches:55
Total branches:76
Branch coverage:72.3% (55 of 76)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
Create(...)-100%100%
CreateEncryptor(...)-100%100%
CreateEncryptor(...)-57.14%71.43%
CreateDecryptor(...)-100%100%
CreateDecryptor(...)-57.14%71.43%
get_DefaultIv()-100%100%
GetBytes(...)-100%100%
.ctor(...)-100%100%
get_CanReuseTransform()-0%100%
get_CanTransformMultipleBlocks()-0%100%
get_InputBlockSize()-0%100%
get_OutputBlockSize()-0%100%
TransformBlock(...)-0%100%
TransformFinalBlock(...)-81.25%66.67%
Dispose()-100%100%
Dispose(...)-100%100%
.ctor(...)-100%100%
get_CanReuseTransform()-0%100%
get_CanTransformMultipleBlocks()-0%100%
get_InputBlockSize()-0%100%
get_OutputBlockSize()-0%100%
TransformBlock(...)-0%100%
TransformFinalBlock(...)-79.41%65%
Dispose()-100%100%
Dispose(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\Cryptography\AesKw.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Security.Cryptography;
 6
 7namespace Azure.Security.KeyVault.Keys.Cryptography
 8{
 9    /// <summary>
 10    /// AES Key Wrap algoritm as defined in https://tools.ietf.org/html/rfc3394
 11    /// </summary>
 12    internal abstract class AesKw
 13    {
 14        private const int BlockSizeInBits = 64;
 15        private const int BlockSizeInBytes = BlockSizeInBits >> 3;
 16
 217        private static readonly byte[] _defaultIv = new byte[] { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
 18
 219        protected static RandomNumberGenerator Rng = RandomNumberGenerator.Create();
 20
 21        internal static Aes Create(byte[] key)
 22        {
 2023            var aes = Aes.Create();
 24
 2025            aes.Mode = CipherMode.ECB;
 2026            aes.Padding = PaddingMode.None;
 2027            aes.KeySize = key.Length * 8;
 2028            aes.Key = key;
 29
 2030            return aes;
 31        }
 32
 33        public static ICryptoTransform CreateEncryptor(byte[] key)
 34        {
 1035            return CreateEncryptor(key, null);
 36        }
 37
 38        public static ICryptoTransform CreateEncryptor(byte[] key, byte[] iv)
 39        {
 1040            if (key == null)
 041                throw new ArgumentNullException(nameof(key));
 42
 1043            if (key.Length != 128 >> 3 && key.Length != 192 >> 3 && key.Length != 256 >> 3)
 044                throw new ArgumentException("key length must be 128, 192 or 256 bits");
 45
 1046            if (iv != null && iv.Length != 8)
 047                throw new ArgumentException("iv length must be 64 bits");
 48
 1049            return new AesKwEncryptor(key, iv ?? DefaultIv);
 50        }
 51
 52        public static ICryptoTransform CreateDecryptor(byte[] key)
 53        {
 1054            return CreateDecryptor(key, null);
 55        }
 56
 57        public static ICryptoTransform CreateDecryptor(byte[] key, byte[] iv)
 58        {
 1059            if (key == null)
 060                throw new ArgumentNullException(nameof(key));
 61
 1062            if (key.Length != 128 >> 3 && key.Length != 192 >> 3 && key.Length != 256 >> 3)
 063                throw new ArgumentException("key length must be 128, 192 or 256 bits");
 64
 1065            if (iv != null && iv.Length != 8)
 066                throw new ArgumentException("iv length must be 64 bits");
 67
 1068            return new AesKwDecryptor(key, iv ?? DefaultIv);
 69        }
 70
 71        private static byte[] DefaultIv
 72        {
 2073            get { return (byte[])_defaultIv.Clone(); }
 74        }
 75
 76        private static byte[] GetBytes(UInt64 i)
 77        {
 33678            byte[] temp = BitConverter.GetBytes(i);
 79
 33680            if (BitConverter.IsLittleEndian)
 81            {
 33682                Array.Reverse(temp);
 83            }
 84
 33685            return temp;
 86        }
 87
 88        private class AesKwEncryptor : ICryptoTransform
 89        {
 90            private Aes _aes;
 91            private byte[] _iv;
 92
 1093            internal AesKwEncryptor(byte[] keyBytes, byte[] iv)
 94            {
 95                // Create the AES provider
 1096                _aes = AesKw.Create(keyBytes);
 97
 98                // Set the AES IV to Zeroes
 1099                var aesIv = new byte[_aes.BlockSize >> 3];
 100
 10101                aesIv.Zero();
 102
 10103                _aes.IV = aesIv;
 104
 105                // Remember the real IV
 10106                _iv = iv.Clone() as byte[];
 10107            }
 108
 109            public bool CanReuseTransform
 110            {
 0111                get { throw new NotImplementedException(); }
 112            }
 113
 114            public bool CanTransformMultipleBlocks
 115            {
 0116                get { throw new NotImplementedException(); }
 117            }
 118
 119            public int InputBlockSize
 120            {
 0121                get { throw new NotImplementedException(); }
 122            }
 123
 124            public int OutputBlockSize
 125            {
 0126                get { throw new NotImplementedException(); }
 127            }
 128
 129            public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outp
 130            {
 131                // No support for block-by-block transformation
 0132                throw new NotImplementedException();
 133            }
 134
 135            public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 136            {
 10137                if (inputBuffer == null)
 0138                    throw new ArgumentNullException(nameof(inputBuffer));
 139
 10140                if (inputBuffer.Length == 0)
 0141                    throw new ArgumentNullException(nameof(inputBuffer), "The length of the inputBuffer parameter cannot
 142
 10143                if (inputCount <= 0)
 0144                    throw new ArgumentOutOfRangeException(nameof(inputCount), "The inputCount parameter must not be zero
 145
 10146                if (inputCount % 8 != 0)
 0147                    throw new ArgumentOutOfRangeException(nameof(inputCount), "The inputCount parameter must be a multip
 148
 10149                if (inputOffset < 0)
 0150                    throw new ArgumentOutOfRangeException(nameof(inputOffset), "The inputOffset parameter must not be ne
 151
 10152                if (inputOffset + inputCount > inputBuffer.Length)
 0153                    throw new ArgumentOutOfRangeException(nameof(inputCount), "The sum of inputCount and inputOffset par
 154
 155                /*
 156                   1) Initialize variables.
 157
 158                       Set A = IV, an initial value (see 2.2.3)
 159                       For i = 1 to n
 160                           R[i] = P[i]
 161
 162                   2) Calculate intermediate values.
 163
 164                       For j = 0 to 5
 165                           For i=1 to n
 166                               B = AES(K, A | R[i])
 167                               A = MSB(64, B) ^ t where t = (n*j)+i
 168                               R[i] = LSB(64, B)
 169
 170                   3) Output the results.
 171
 172                       Set C[0] = A
 173                       For i = 1 to n
 174                           C[i] = R[i]
 175                */
 176
 177                // The default initialization vector from RFC3394
 10178                byte[] a = _iv;
 179
 180                // The number of input blocks
 10181                var n = inputCount >> 3;
 182
 183                // The set of input blocks
 10184                byte[] r = new byte[n << 3];
 185
 10186                Array.Copy(inputBuffer, inputOffset, r, 0, inputCount);
 187
 10188                var encryptor = _aes.CreateEncryptor();
 10189                byte[] block = new byte[16];
 190
 191                // Calculate intermediate values
 140192                for (var j = 0; j < 6; j++)
 193                {
 456194                    for (var i = 0; i < n; i++)
 195                    {
 196                        // T = ( n * j ) + i
 168197                        var t = (ulong)((n * j) + i + 1);
 198
 199                        // B = AES( K, A | R[i] )
 200
 201                        // First, block = A | R[i]
 168202                        Array.Copy(a, block, a.Length);
 168203                        Array.Copy(r, i << 3, block, 64 >> 3, 64 >> 3);
 204
 205                        // Second, AES( K, block )
 168206                        var b = encryptor.TransformFinalBlock(block, 0, 16);
 207
 208                        // A = MSB( 64, B )
 168209                        Array.Copy(b, a, 64 >> 3);
 210
 211                        // A = A ^ t
 168212                        a.Xor(GetBytes(t), true);
 213
 214                        // R[i] = LSB( 64, B )
 168215                        Array.Copy(b, 64 >> 3, r, i << 3, 64 >> 3);
 216                    }
 217                }
 218
 10219                var c = new byte[(n + 1) << 3];
 220
 10221                Array.Copy(a, c, a.Length);
 222
 76223                for (var i = 0; i < n; i++)
 224                {
 28225                    Array.Copy(r, i << 3, c, (i + 1) << 3, 8);
 226                }
 227
 10228                return c;
 229            }
 230
 231            public void Dispose()
 232            {
 10233                Dispose(true);
 10234                GC.SuppressFinalize(this);
 10235            }
 236
 237            protected virtual void Dispose(bool disposing)
 238            {
 10239                if (disposing)
 240                {
 10241                    if (_aes != null)
 242                    {
 10243                        _aes.Dispose();
 10244                        _aes = null;
 245                    }
 246                }
 10247            }
 248        }
 249
 250        private class AesKwDecryptor : ICryptoTransform
 251        {
 252            private Aes _aes;
 253            private byte[] _iv;
 254
 10255            internal AesKwDecryptor(byte[] keyBytes, byte[] iv)
 256            {
 257                // Create the AES provider
 10258                _aes = AesKw.Create(keyBytes);
 259
 260                // Set the AES IV to Zeroes
 10261                var aesIv = new byte[_aes.BlockSize >> 3];
 262
 10263                aesIv.Zero();
 264
 10265                _aes.IV = aesIv;
 266
 267                // Remember the real IV
 10268                _iv = iv.Clone() as byte[];
 10269            }
 270
 271            public bool CanReuseTransform
 272            {
 0273                get { throw new NotImplementedException(); }
 274            }
 275
 276            public bool CanTransformMultipleBlocks
 277            {
 0278                get { throw new NotImplementedException(); }
 279            }
 280
 281            public int InputBlockSize
 282            {
 0283                get { throw new NotImplementedException(); }
 284            }
 285
 286            public int OutputBlockSize
 287            {
 0288                get { throw new NotImplementedException(); }
 289            }
 290
 291            public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outp
 292            {
 293                // No support for block-by-block transformation
 0294                throw new NotImplementedException();
 295            }
 296
 297            public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
 298            {
 10299                if (inputBuffer == null)
 0300                    throw new ArgumentNullException(nameof(inputBuffer));
 301
 10302                if (inputBuffer.Length == 0)
 0303                    throw new ArgumentNullException(nameof(inputBuffer), "The length of the inputBuffer parameter cannot
 304
 10305                if (inputCount <= 0)
 0306                    throw new ArgumentOutOfRangeException(nameof(inputCount), "The inputCount parameter must not be zero
 307
 10308                if (inputCount % 8 != 0)
 0309                    throw new ArgumentOutOfRangeException(nameof(inputCount), "The inputCount parameter must be a multip
 310
 10311                if (inputOffset < 0)
 0312                    throw new ArgumentOutOfRangeException(nameof(inputOffset), "The inputOffset parameter must not be ne
 313
 10314                if (inputOffset + inputCount > inputBuffer.Length)
 0315                    throw new ArgumentOutOfRangeException(nameof(inputCount), "The sum of inputCount and inputOffset par
 316
 317                /*
 318                    1) Initialize variables.
 319
 320                        Set A = C[0]
 321                        For i = 1 to n
 322                            R[i] = C[i]
 323
 324                    2) Compute intermediate values.
 325
 326                        For j = 5 to 0
 327                            For i = n to 1
 328                                B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
 329                                A = MSB(64, B)
 330                                R[i] = LSB(64, B)
 331
 332                    3) Output results.
 333
 334                    If A is an appropriate initial value (see 2.2.3),
 335                    Then
 336                        For i = 1 to n
 337                            P[i] = R[i]
 338                    Else
 339                        Return an error
 340                */
 341
 342                // A = C[0]
 10343                byte[] a = new byte[BlockSizeInBytes];
 344
 10345                Array.Copy(inputBuffer, inputOffset, a, 0, BlockSizeInBytes);
 346
 347                // The number of input blocks
 10348                var n = (inputCount - BlockSizeInBytes) >> 3;
 349
 350                // The set of input blocks
 10351                byte[] r = new byte[n << 3];
 352
 10353                Array.Copy(inputBuffer, inputOffset + BlockSizeInBytes, r, 0, inputCount - BlockSizeInBytes);
 354
 10355                var encryptor = _aes.CreateDecryptor();
 10356                byte[] block = new byte[16];
 357
 358                // Calculate intermediate values
 140359                for (var j = 5; j >= 0; j--)
 360                {
 456361                    for (var i = n; i > 0; i--)
 362                    {
 363                        // T = ( n * j ) + i
 168364                        var t = (ulong)((n * j) + i);
 365
 366                        // B = AES-1(K, (A ^ t) | R[i] )
 367
 368                        // First, A = ( A ^ t )
 168369                        a.Xor(GetBytes(t), true);
 370
 371                        // Second, block = ( A | R[i] )
 168372                        Array.Copy(a, block, BlockSizeInBytes);
 168373                        Array.Copy(r, (i - 1) << 3, block, BlockSizeInBytes, BlockSizeInBytes);
 374
 375                        // Third, b = AES-1( block )
 168376                        var b = encryptor.TransformFinalBlock(block, 0, 16);
 377
 378                        // A = MSB(64, B)
 168379                        Array.Copy(b, a, BlockSizeInBytes);
 380
 381                        // R[i] = LSB(64, B)
 168382                        Array.Copy(b, BlockSizeInBytes, r, (i - 1) << 3, BlockSizeInBytes);
 383                    }
 384                }
 385
 10386                if (a.SequenceEqualConstantTime(_iv))
 387                {
 10388                    var c = new byte[n << 3];
 389
 76390                    for (var i = 0; i < n; i++)
 391                    {
 28392                        Array.Copy(r, i << 3, c, i << 3, 8);
 393                    }
 394
 10395                    return c;
 396                }
 397                else
 398                {
 0399                    throw new CryptographicException("Data is not authentic");
 400                }
 401            }
 402
 403            public void Dispose()
 404            {
 10405                Dispose(true);
 10406                GC.SuppressFinalize(this);
 10407            }
 408
 409            protected virtual void Dispose(bool disposing)
 410            {
 10411                if (disposing)
 412                {
 10413                    if (_aes != null)
 414                    {
 10415                        _aes.Dispose();
 10416                        _aes = null;
 417                    }
 418                }
 10419            }
 420        }
 421    }
 422}