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 //
6 // This file is one of a group of files (AesCng.cs, TripleDESCng.cs) that are almost identical except
7 // for the algorithm name. If you make a change to this file, there's a good chance you'll have to make
8 // the same change to the other files so please check. This is a pain but given that the contracts demand
9 // that each of these derive from a different class, it can't be helped.
10 //
11 
12 using Internal.Cryptography;
13 using Internal.NativeCrypto;
14 
15 namespace System.Security.Cryptography
16 {
17     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350")] // We are providing the implementation for 3DES not consuming it
18     public sealed class TripleDESCng : TripleDES, ICngSymmetricAlgorithm
19     {
TripleDESCng()20         public TripleDESCng()
21         {
22             _core = new CngSymmetricAlgorithmCore(this);
23         }
24 
TripleDESCng(string keyName)25         public TripleDESCng(string keyName)
26             : this(keyName, CngProvider.MicrosoftSoftwareKeyStorageProvider)
27         {
28         }
29 
TripleDESCng(string keyName, CngProvider provider)30         public TripleDESCng(string keyName, CngProvider provider)
31             : this(keyName, provider, CngKeyOpenOptions.None)
32         {
33         }
34 
TripleDESCng(string keyName, CngProvider provider, CngKeyOpenOptions openOptions)35         public TripleDESCng(string keyName, CngProvider provider, CngKeyOpenOptions openOptions)
36         {
37             _core = new CngSymmetricAlgorithmCore(this, keyName, provider, openOptions);
38         }
39 
40         public override byte[] Key
41         {
42             get
43             {
44                 return _core.GetKeyIfExportable();
45             }
46             set
47             {
48                 _core.SetKey(value);
49             }
50         }
51 
52         public override int KeySize
53         {
54             get
55             {
56                 return base.KeySize;
57             }
58 
59             set
60             {
61                 _core.SetKeySize(value, this);
62             }
63         }
64 
CreateDecryptor()65         public override ICryptoTransform CreateDecryptor()
66         {
67             // Do not change to CreateDecryptor(this.Key, this.IV). this.Key throws if a non-exportable hardware key is being used.
68             return _core.CreateDecryptor();
69         }
70 
CreateDecryptor(byte[] rgbKey, byte[] rgbIV)71         public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
72         {
73             return _core.CreateDecryptor(rgbKey, rgbIV);
74         }
75 
CreateEncryptor()76         public override ICryptoTransform CreateEncryptor()
77         {
78             // Do not change to CreateEncryptor(this.Key, this.IV). this.Key throws if a non-exportable hardware key is being used.
79             return _core.CreateEncryptor();
80         }
81 
CreateEncryptor(byte[] rgbKey, byte[] rgbIV)82         public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
83         {
84             return _core.CreateEncryptor(rgbKey, rgbIV);
85         }
86 
GenerateKey()87         public override void GenerateKey()
88         {
89             _core.GenerateKey();
90         }
91 
GenerateIV()92         public override void GenerateIV()
93         {
94             _core.GenerateIV();
95         }
96 
Dispose(bool disposing)97         protected override void Dispose(bool disposing)
98         {
99             base.Dispose(disposing);
100         }
101 
102         byte[] ICngSymmetricAlgorithm.BaseKey { get { return base.Key; } set { base.Key = value; } }
103         int ICngSymmetricAlgorithm.BaseKeySize { get { return base.KeySize; } set { base.KeySize = value; } }
104 
ICngSymmetricAlgorithm.IsWeakKey(byte[] key)105         bool ICngSymmetricAlgorithm.IsWeakKey(byte[] key)
106         {
107             return TripleDES.IsWeakKey(key);
108         }
109 
ICngSymmetricAlgorithm.GetEphemeralModeHandle()110         SafeAlgorithmHandle ICngSymmetricAlgorithm.GetEphemeralModeHandle()
111         {
112             return TripleDesBCryptModes.GetSharedHandle(Mode);
113         }
114 
ICngSymmetricAlgorithm.GetNCryptAlgorithmIdentifier()115         string ICngSymmetricAlgorithm.GetNCryptAlgorithmIdentifier()
116         {
117             return Interop.NCrypt.NCRYPT_3DES_ALGORITHM;
118         }
119 
ICngSymmetricAlgorithm.PreprocessKey(byte[] key)120         byte[] ICngSymmetricAlgorithm.PreprocessKey(byte[] key)
121         {
122             if (key.Length == 16)
123             {
124                 // Cng does not support Two-Key Triple DES, so manually support it here for consistency with System.Security.Cryptography.Algorithms.
125                 // Two-Key Triple DES contains two 8-byte keys {K1}{K2} with {K1} appended to make {K1}{K2}{K1}.
126                 byte[] newkey = new byte[24];
127                 Array.Copy(key, 0, newkey, 0, 16);
128                 Array.Copy(key, 0, newkey, 16, 8);
129                 return newkey;
130             }
131 
132             return key;
133         }
134 
135         private CngSymmetricAlgorithmCore _core;
136     }
137 }
138