1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Diagnostics;
7 using System.Security.Cryptography;
8 
9 using Internal.Cryptography;
10 
11 namespace System.Security.Cryptography
12 {
13     //
14     // If you change anything in this class, you must make the same change in the other HMAC* classes. This is a pain but given that the
15     // preexisting contract from the desktop locks all of these into deriving directly from HMAC, it can't be helped.
16     //
17 
18     public class HMACSHA512 : HMAC
19     {
HMACSHA512()20         public HMACSHA512()
21             : this(Helpers.GenerateRandom(BlockSize))
22         {
23         }
24 
HMACSHA512(byte[] key)25         public HMACSHA512(byte[] key)
26         {
27             this.HashName = HashAlgorithmNames.SHA512;
28             _hMacCommon = new HMACCommon(HashAlgorithmNames.SHA512, key, BlockSize);
29             base.Key = _hMacCommon.ActualKey;
30             // change the default value of BlockSizeValue to 128 instead of 64
31             BlockSizeValue = BlockSize;
32             HashSizeValue = _hMacCommon.HashSizeInBits;
33         }
34 
35         public bool ProduceLegacyHmacValues
36         {
37             get
38             {
39                 return false;
40             }
41             set
42             {
43                 if (value)
44                 {
45                     throw new PlatformNotSupportedException(); // This relates to a quirk in the Desktop managed implementation; ours is native.
46                 }
47             }
48         }
49 
50         public override byte[] Key
51         {
52             get
53             {
54                 return base.Key;
55             }
56             set
57             {
58                 _hMacCommon.ChangeKey(value);
59                 base.Key = _hMacCommon.ActualKey;
60             }
61         }
62 
HashCore(byte[] rgb, int ib, int cb)63         protected override void HashCore(byte[] rgb, int ib, int cb) =>
64             _hMacCommon.AppendHashData(rgb, ib, cb);
65 
66         protected override void HashCore(ReadOnlySpan<byte> source) =>
67             _hMacCommon.AppendHashData(source);
68 
HashFinal()69         protected override byte[] HashFinal() =>
70             _hMacCommon.FinalizeHashAndReset();
71 
TryHashFinal(Span<byte> destination, out int bytesWritten)72         protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
73             _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
74 
Initialize()75         public override void Initialize()
76         {
77             // Nothing to do here. We expect HashAlgorithm to invoke HashFinal() and Initialize() as a pair. This reflects the
78             // reality that our native crypto providers (e.g. CNG) expose hash finalization and object reinitialization as an atomic operation.
79         }
80 
Dispose(bool disposing)81         protected override void Dispose(bool disposing)
82         {
83             if (disposing)
84             {
85                 HMACCommon hMacCommon = _hMacCommon;
86                 if (hMacCommon != null)
87                 {
88                     _hMacCommon = null;
89                     hMacCommon.Dispose(disposing);
90                 }
91             }
92             base.Dispose(disposing);
93         }
94 
95         private HMACCommon _hMacCommon;
96         private const int BlockSize = 128;
97     }
98 }
99