Last active
July 3, 2018 15:31
-
-
Save 0xfeeddeadbeef/5a965519da969b8492015121596e7710 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* FipsSHA256SignatureDescription.cs | |
* | |
* Copyright (c) 2013-2018, Sustainsys and contributors. All rights reserved. | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this library; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
* MA 02110-1301 USA | |
*/ | |
// This is a slightly modified variant of the following file: | |
// https://github.com/Sustainsys/Saml2/blob/master/Sustainsys.Saml2/ManagedSha256SignatureDescription.cs | |
namespace YOUR_PROJECT_NAMESPACE | |
{ | |
using System; | |
using System.Security.Cryptography; | |
/// <summary> | |
/// Crypto description for a managed FIPS-compliant implementation of SHA256 signatures. | |
/// </summary> | |
public class FipsSHA256SignatureDescription : SignatureDescription | |
{ | |
private readonly string sha256ImplementationName; | |
public FipsSHA256SignatureDescription() | |
{ | |
// Create FIPS-compliant SHA256 algorithm when FIPS is enforced: | |
this.sha256ImplementationName = CryptoConfig.AllowOnlyFipsAlgorithms | |
? typeof(SHA256Cng).FullName | |
: typeof(SHA256Managed).FullName; | |
KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName; | |
DigestAlgorithm = sha256ImplementationName; | |
} | |
public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) | |
{ | |
if (key == null) | |
{ | |
throw new ArgumentNullException(nameof(key)); | |
} | |
var df = new RSAPKCS1SignatureDeformatter(key); | |
df.SetHashAlgorithm(this.sha256ImplementationName); | |
return df; | |
} | |
public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) | |
{ | |
if (key == null) | |
{ | |
throw new ArgumentNullException(nameof(key)); | |
} | |
var provider = GetSha256EnabledRSACryptoServiceProvider((RSACryptoServiceProvider)key); | |
var formatter = new RSAPKCS1SignatureFormatter(provider); | |
formatter.SetHashAlgorithm(this.sha256ImplementationName); | |
return formatter; | |
} | |
// | |
// Taken from here: | |
// https://github.com/Sustainsys/Saml2/blob/master/Sustainsys.Saml2/Internal/CryptographyExtensions.cs#L63 | |
// | |
private static RSACryptoServiceProvider GetSha256EnabledRSACryptoServiceProvider( | |
RSACryptoServiceProvider original) | |
{ | |
// The provider is probably using the default ProviderType. That's | |
// a problem, because it doesn't support SHA256. Let's do some | |
// black magic and create a new provider of a type that supports | |
// SHA256 without the user ever knowing we fix this. This is what | |
// is done in X509AsymmetricKey.GetSignatureFormatter if | |
// http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 isn't | |
// a known algorithm, so users kind of expect this to be handled | |
// for them magically. | |
var cspParams = new CspParameters(); | |
cspParams.ProviderType = 24; //PROV_RSA_AES | |
cspParams.KeyContainerName = original.CspKeyContainerInfo.KeyContainerName; | |
cspParams.KeyNumber = (int)original.CspKeyContainerInfo.KeyNumber; | |
SetMachineKeyFlag(original, cspParams); | |
cspParams.Flags |= CspProviderFlags.UseExistingKey; | |
return new RSACryptoServiceProvider(cspParams); | |
} | |
private static void SetMachineKeyFlag(RSACryptoServiceProvider provider, CspParameters cspParams) | |
{ | |
if (provider.CspKeyContainerInfo.MachineKeyStore) | |
{ | |
cspParams.Flags = CspProviderFlags.UseMachineKeyStore; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment