Skip to content

Instantly share code, notes, and snippets.

@0xfeeddeadbeef
Last active July 3, 2018 15:31
Show Gist options
  • Save 0xfeeddeadbeef/5a965519da969b8492015121596e7710 to your computer and use it in GitHub Desktop.
Save 0xfeeddeadbeef/5a965519da969b8492015121596e7710 to your computer and use it in GitHub Desktop.
/*
* 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