| File: System\Security\Cryptography\CngAlgorithmCore.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using Microsoft.Win32.SafeHandles; using static Interop.NCrypt; namespace System.Security.Cryptography { // // Common infrastructure for crypto algorithms that accept CngKeys. // internal struct CngAlgorithmCore { private readonly Type _disposedType; #pragma warning disable CS0649 public CngAlgorithm? DefaultKeyType; #pragma warning restore CS0649 private CngKey? _lazyKey; private bool _disposed; public CngAlgorithmCore(Type disposedType) : this() { _disposedType = disposedType; } public static CngKey Duplicate(CngKey key) { return CngKey.Open(key.HandleNoDuplicate, key.IsEphemeral ? CngKeyHandleOpenOptions.EphemeralKey : CngKeyHandleOpenOptions.None); } public bool IsKeyGeneratedNamedCurve() { ThrowIfDisposed(); return (_lazyKey != null && _lazyKey.IsECNamedCurve()); } public void DisposeKey() { if (_lazyKey != null) { _lazyKey.Dispose(); _lazyKey = null; } } public unsafe CngKey GetOrGenerateKey(int keySize, CngAlgorithm algorithm) { ThrowIfDisposed(); // If our key size was changed, we need to generate a new key. if (_lazyKey != null) { if (_lazyKey.KeySize != keySize) DisposeKey(); } // If we don't have a key yet, we need to generate one now. if (_lazyKey == null) { CngKeyCreationParameters creationParameters = new CngKeyCreationParameters() { ExportPolicy = CngExportPolicies.AllowPlaintextExport, }; Span<byte> keySizeBuffer = stackalloc byte[sizeof(int)]; bool success = BitConverter.TryWriteBytes(keySizeBuffer, keySize); Debug.Assert(success); CngProperty keySizeProperty = new CngProperty(KeyPropertyName.Length, keySizeBuffer, CngPropertyOptions.None); creationParameters.Parameters.Add(keySizeProperty); _lazyKey = CngKey.Create(algorithm, null, creationParameters); } return _lazyKey; } public CngKey GetOrGenerateKey(ECCurve? curve) { ThrowIfDisposed(); if (_lazyKey != null) { return _lazyKey; } // We don't have a key yet so generate Debug.Assert(curve.HasValue); CngKeyCreationParameters creationParameters = new CngKeyCreationParameters() { ExportPolicy = CngExportPolicies.AllowPlaintextExport, }; if (curve.Value.IsNamed) { creationParameters.Parameters.Add(CngKey.GetPropertyFromNamedCurve(curve.Value)); } else if (curve.Value.IsPrime) { ECCurve eccurve = curve.Value; byte[] parametersBlob = ECCng.GetPrimeCurveParameterBlob(ref eccurve); CngProperty prop = new CngProperty( Interop.BCrypt.BCryptPropertyStrings.BCRYPT_ECC_PARAMETERS, parametersBlob, CngPropertyOptions.None); creationParameters.Parameters.Add(prop); } else { throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CurveNotSupported, curve.Value.CurveType.ToString())); } try { _lazyKey = CngKey.Create(DefaultKeyType ?? CngAlgorithm.ECDsa, null, creationParameters); } catch (CryptographicException e) { // Map to PlatformNotSupportedException if appropriate ErrorCode errorCode = (ErrorCode)e.HResult; if (curve.Value.IsNamed && errorCode == ErrorCode.NTE_INVALID_PARAMETER || errorCode == ErrorCode.NTE_NOT_SUPPORTED) { throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CurveNotSupported, curve.Value.Oid.FriendlyName), e); } throw; } return _lazyKey; } public void SetKey(CngKey key) { Debug.Assert(key != null); ThrowIfDisposed(); // If we already have a key, clear it out. DisposeKey(); _lazyKey = key; } public void Dispose() { DisposeKey(); _disposed = true; } internal void ThrowIfDisposed() { ObjectDisposedException.ThrowIf(_disposed, _disposedType); } } }