< Summary

Class:Microsoft.Azure.KeyVault.Cryptography.Algorithms.AesKw
Assembly:Microsoft.Azure.KeyVault.Cryptography
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Microsoft.Azure.KeyVault.Cryptography\src\Algorithms\AesKw.cs
Covered lines:108
Uncovered lines:29
Coverable lines:137
Total lines:430
Line coverage:78.8% (108 of 137)
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%
.ctor(...)-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\Microsoft.Azure.KeyVault.Cryptography\src\Algorithms\AesKw.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License. See License.txt in the project root for
 3// license information.
 4
 5using System;
 6using System.Security.Cryptography;
 7
 8namespace Microsoft.Azure.KeyVault.Cryptography.Algorithms
 9{
 10    /// <summary>
 11    /// Abstract AES Key Wrap algoritm.
 12    /// </summary>
 13    public abstract class AesKw : KeyWrapAlgorithm
 14    {
 15        const int BlockSizeInBits  = 64;
 16        const int BlockSizeInBytes = BlockSizeInBits >> 3;
 17
 218        static readonly byte[] _defaultIv = new byte[] { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
 19
 220        protected static RandomNumberGenerator Rng = RandomNumberGenerator.Create();
 21
 22        internal static Aes Create( byte[] key )
 23        {
 4824            var aes = Aes.Create();
 25
 4826            aes.Mode    = CipherMode.ECB;
 4827            aes.Padding = PaddingMode.None;
 4828            aes.KeySize = key.Length * 8;
 4829            aes.Key    = key;
 30
 4831            return aes;
 32        }
 33
 1834        protected AesKw( string name ) : base( name )
 35        {
 36
 1837        }
 38
 39        public ICryptoTransform CreateEncryptor( byte[] key )
 40        {
 1241            return CreateEncryptor( key, null );
 42        }
 43
 44        public override ICryptoTransform CreateEncryptor( byte[] key, byte[] iv )
 45        {
 2446            if ( key == null )
 047                throw new ArgumentNullException( "key" );
 48
 2449            if ( key.Length != 128 >> 3 && key.Length != 192 >> 3 && key.Length != 256 >> 3 )
 050                throw new ArgumentException( "key length must be 128, 192 or 256 bits" );
 51
 2452            if ( iv != null && iv.Length != 8 )
 053                throw new ArgumentException( "iv length must be 64 bits" );
 54
 2455            return new AesKwEncryptor( key, iv ?? DefaultIv );
 56        }
 57
 58        public ICryptoTransform CreateDecryptor( byte[] key )
 59        {
 1260            return CreateDecryptor( key, null );
 61        }
 62
 63        public override ICryptoTransform CreateDecryptor( byte[] key, byte[] iv)
 64        {
 2465            if ( key == null )
 066                throw new ArgumentNullException( "key" );
 67
 2468            if ( key.Length != 128 >> 3 && key.Length != 192 >> 3 && key.Length != 256 >> 3 )
 069                throw new ArgumentException( "key length must be 128, 192 or 256 bits" );
 70
 2471            if ( iv != null && iv.Length != 8 )
 072                throw new ArgumentException( "iv length must be 64 bits" );
 73
 2474            return new AesKwDecryptor( key, iv ?? DefaultIv );
 75        }
 76
 77        private static byte[] DefaultIv
 78        {
 4879            get { return (byte[])_defaultIv.Clone(); }
 80        }
 81
 82        static byte[] GetBytes( UInt64 i )
 83        {
 57684            byte[] temp = BitConverter.GetBytes( i );
 85
 57686            if ( BitConverter.IsLittleEndian )
 87            {
 57688                Array.Reverse( temp );
 89            }
 90
 57691            return temp;
 92        }
 93
 94        class AesKwEncryptor : ICryptoTransform
 95        {
 96            private Aes    _aes;
 97            private byte[] _iv;
 98
 2499            internal AesKwEncryptor( byte[] keyBytes, byte[] iv )
 100            {
 101                // Create the AES provider
 24102                _aes = AesKw.Create( keyBytes );
 103
 104                // Set the AES IV to Zeroes
 24105                var aesIv = new byte[_aes.BlockSize >> 3];
 106
 24107                aesIv.Zero();
 108
 24109                _aes.IV = aesIv;
 110
 111                // Remember the real IV
 24112                _iv = iv.Clone() as byte[];
 24113            }
 114
 115            public bool CanReuseTransform
 116            {
 0117                get { throw new NotImplementedException(); }
 118            }
 119
 120            public bool CanTransformMultipleBlocks
 121            {
 0122                get { throw new NotImplementedException(); }
 123            }
 124
 125            public int InputBlockSize
 126            {
 0127                get { throw new NotImplementedException(); }
 128            }
 129
 130            public int OutputBlockSize
 131            {
 0132                get { throw new NotImplementedException(); }
 133            }
 134
 135            public int TransformBlock( byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int out
 136            {
 137                // No support for block-by-block transformation
 0138                throw new NotImplementedException();
 139            }
 140
 141            public byte[] TransformFinalBlock( byte[] inputBuffer, int inputOffset, int inputCount )
 142            {
 24143                if ( inputBuffer == null )
 0144                    throw new ArgumentNullException( "inputBuffer" );
 145
 24146                if ( inputBuffer.Length == 0 )
 0147                    throw new ArgumentNullException( "inputBuffer", "The length of the inputBuffer parameter cannot be z
 148
 24149                if ( inputCount <= 0 )
 0150                    throw new ArgumentOutOfRangeException( "inputCount", "The inputCount parameter must not be zero or n
 151
 24152                if ( inputCount % 8 != 0 )
 0153                    throw new ArgumentOutOfRangeException( "inputCount", "The inputCount parameter must be a multiple of
 154
 24155                if ( inputOffset < 0 )
 0156                    throw new ArgumentOutOfRangeException( "inputOffset", "The inputOffset parameter must not be negativ
 157
 24158                if ( inputOffset + inputCount > inputBuffer.Length )
 0159                    throw new ArgumentOutOfRangeException( "inputCount", "The sum of inputCount and inputOffset paramete
 160
 161
 162                /*
 163                   1) Initialize variables.
 164
 165                       Set A = IV, an initial value (see 2.2.3)
 166                       For i = 1 to n
 167                           R[i] = P[i]
 168
 169                   2) Calculate intermediate values.
 170
 171                       For j = 0 to 5
 172                           For i=1 to n
 173                               B = AES(K, A | R[i])
 174                               A = MSB(64, B) ^ t where t = (n*j)+i
 175                               R[i] = LSB(64, B)
 176
 177                   3) Output the results.
 178
 179                       Set C[0] = A
 180                       For i = 1 to n
 181                           C[i] = R[i]
 182                */
 183
 184                // The default initialization vector from RFC3394
 24185                byte[]   a  = _iv;
 186
 187                // The number of input blocks
 24188                var      n  = inputCount >> 3;
 189
 190                // The set of input blocks
 24191                byte[]  r  = new byte[n << 3];
 192
 24193                Array.Copy( inputBuffer, inputOffset, r, 0, inputCount );
 194
 24195                var    encryptor = _aes.CreateEncryptor();
 24196                byte[] block     = new byte[16];
 197
 198                // Calculate intermediate values
 336199                for ( var j = 0; j < 6; j++ )
 200                {
 864201                    for ( var i = 0; i < n; i++ )
 202                    {
 203                        // T = ( n * j ) + i
 288204                        var t = (ulong)( ( n * j ) + i + 1 );
 205
 206                        // B = AES( K, A | R[i] )
 207
 208                        // First, block = A | R[i]
 288209                        Array.Copy( a, block, a.Length );
 288210                        Array.Copy( r, i << 3, block, 64 >> 3, 64 >> 3 );
 211
 212                        // Second, AES( K, block )
 288213                        var b = encryptor.TransformFinalBlock( block, 0, 16 );
 214
 215                        // A = MSB( 64, B )
 288216                        Array.Copy( b, a, 64 >> 3 );
 217
 218                        // A = A ^ t
 288219                        a.Xor( GetBytes( t ), true );
 220
 221                        // R[i] = LSB( 64, B )
 288222                        Array.Copy( b, 64 >> 3, r, i << 3, 64 >> 3 );
 223                    }
 224                }
 225
 24226                var c = new byte[( n + 1 ) << 3];
 227
 24228                Array.Copy( a, c, a.Length );
 229
 144230                for ( var i = 0; i < n; i++ )
 231                {
 48232                    Array.Copy( r, i << 3, c, ( i + 1 ) << 3, 8 );
 233                }
 234
 24235                return c;
 236            }
 237
 238            public void Dispose()
 239            {
 24240                Dispose( true );
 24241                GC.SuppressFinalize( this );
 24242            }
 243
 244            protected virtual void Dispose( bool disposing )
 245            {
 24246                if ( disposing )
 247                {
 24248                    if ( _aes != null )
 249                    {
 24250                        _aes.Dispose();
 24251                        _aes = null;
 252                    }
 253                }
 24254            }
 255        }
 256
 257        class AesKwDecryptor : ICryptoTransform
 258        {
 259            private Aes    _aes;
 260            private byte[] _iv;
 261
 24262            internal AesKwDecryptor( byte[] keyBytes, byte[] iv )
 263            {
 264                // Create the AES provider
 24265                _aes = AesKw.Create( keyBytes );
 266
 267                // Set the AES IV to Zeroes
 24268                var aesIv = new byte[_aes.BlockSize >> 3];
 269
 24270                aesIv.Zero();
 271
 24272                _aes.IV = aesIv;
 273
 274                // Remember the real IV
 24275                _iv = iv.Clone() as byte[];
 24276            }
 277
 278            public bool CanReuseTransform
 279            {
 0280                get { throw new NotImplementedException(); }
 281            }
 282
 283            public bool CanTransformMultipleBlocks
 284            {
 0285                get { throw new NotImplementedException(); }
 286            }
 287
 288            public int InputBlockSize
 289            {
 0290                get { throw new NotImplementedException(); }
 291            }
 292
 293            public int OutputBlockSize
 294            {
 0295                get { throw new NotImplementedException(); }
 296            }
 297
 298            public int TransformBlock( byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int out
 299            {
 300                // No support for block-by-block transformation
 0301                throw new NotImplementedException();
 302            }
 303
 304            public byte[] TransformFinalBlock( byte[] inputBuffer, int inputOffset, int inputCount )
 305            {
 24306                if ( inputBuffer == null )
 0307                    throw new ArgumentNullException( "inputBuffer" );
 308
 24309                if ( inputBuffer.Length == 0 )
 0310                    throw new ArgumentNullException( "inputBuffer", "The length of the inputBuffer parameter cannot be z
 311
 24312                if ( inputCount <= 0 )
 0313                    throw new ArgumentOutOfRangeException( "inputCount", "The inputCount parameter must not be zero or n
 314
 24315                if ( inputCount % 8 != 0 )
 0316                    throw new ArgumentOutOfRangeException( "inputCount", "The inputCount parameter must be a multiple of
 317
 24318                if ( inputOffset < 0 )
 0319                    throw new ArgumentOutOfRangeException( "inputOffset", "The inputOffset parameter must not be negativ
 320
 24321                if ( inputOffset + inputCount > inputBuffer.Length )
 0322                    throw new ArgumentOutOfRangeException( "inputCount", "The sum of inputCount and inputOffset paramete
 323
 324
 325                /*
 326                    1) Initialize variables.
 327
 328                        Set A = C[0]
 329                        For i = 1 to n
 330                            R[i] = C[i]
 331
 332                    2) Compute intermediate values.
 333
 334                        For j = 5 to 0
 335                            For i = n to 1
 336                                B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
 337                                A = MSB(64, B)
 338                                R[i] = LSB(64, B)
 339
 340                    3) Output results.
 341
 342                    If A is an appropriate initial value (see 2.2.3),
 343                    Then
 344                        For i = 1 to n
 345                            P[i] = R[i]
 346                    Else
 347                        Return an error
 348                */
 349
 350                // A = C[0]
 24351                byte[]   a  = new byte[BlockSizeInBytes];
 352
 24353                Array.Copy( inputBuffer, inputOffset, a, 0, BlockSizeInBytes );
 354
 355                // The number of input blocks
 24356                var      n  = ( inputCount - BlockSizeInBytes ) >> 3;
 357
 358                // The set of input blocks
 24359                byte[]   r  = new byte[n << 3];
 360
 24361                Array.Copy( inputBuffer, inputOffset + BlockSizeInBytes, r, 0, inputCount - BlockSizeInBytes );
 362
 24363                var    encryptor = _aes.CreateDecryptor();
 24364                byte[] block     = new byte[16];
 365
 366                // Calculate intermediate values
 336367                for ( var j = 5; j >= 0; j-- )
 368                {
 864369                    for ( var i = n; i > 0; i-- )
 370                    {
 371                        // T = ( n * j ) + i
 288372                        var t = (ulong)( ( n * j ) + i );
 373
 374                        // B = AES-1(K, (A ^ t) | R[i] )
 375
 376                        // First, A = ( A ^ t )
 288377                        a.Xor( GetBytes( t ), true );
 378
 379                        // Second, block = ( A | R[i] )
 288380                        Array.Copy( a, block, BlockSizeInBytes );
 288381                        Array.Copy( r, ( i - 1 ) << 3, block, BlockSizeInBytes, BlockSizeInBytes );
 382
 383                        // Third, b = AES-1( block )
 288384                        var b = encryptor.TransformFinalBlock( block, 0, 16 );
 385
 386                        // A = MSB(64, B)
 288387                        Array.Copy( b, a, BlockSizeInBytes );
 388
 389                        // R[i] = LSB(64, B)
 288390                        Array.Copy( b, BlockSizeInBytes, r, ( i - 1 ) << 3, BlockSizeInBytes );
 391                    }
 392                }
 393
 24394                if ( a.SequenceEqualConstantTime( _iv ) )
 395                {
 24396                    var c = new byte[n << 3];
 397
 144398                    for ( var i = 0; i < n; i++ )
 399                    {
 48400                        Array.Copy( r, i << 3, c, i << 3, 8 );
 401                    }
 402
 24403                    return c;
 404                }
 405                else
 406                {
 0407                    throw new CryptographicException( "Data is not authentic" );
 408                }
 409            }
 410
 411            public void Dispose()
 412            {
 24413                Dispose( true );
 24414                GC.SuppressFinalize( this );
 24415            }
 416
 417            protected virtual void Dispose( bool disposing )
 418            {
 24419                if ( disposing )
 420                {
 24421                    if ( _aes != null )
 422                    {
 24423                        _aes.Dispose();
 24424                        _aes = null;
 425                    }
 426                }
 24427            }
 428        }
 429    }
 430}