#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.IO;
namespace CSharpTest.Net.Crypto
{
///
/// Provides a wrapper around encrypting/decrypting with public/private key pairs from Certificats or CSP
///
public class RSAPrivateKey : RSAPublicKey
{
/// The default key size in bits to use when constructing a new keypair
public const int DefaultKeySize = 1024;
/// The minimum allowed value for an RSA key
public const int MinKeySize = 384;
/// The maximum allowed value for an RSA key
public const int MaxKeySize = 16384;
/// Creates the key from the information provided
public new static RSAPrivateKey FromParameters(RSAParameters parameters)
{ return (RSAPrivateKey)RSAPublicKey.FromParameters(parameters); }
/// Creates the key from the information provided
public new static RSAPrivateKey FromBytes(byte[] bytes)
{ return (RSAPrivateKey)RSAPublicKey.FromBytes(bytes); }
/// Creates the key from the information provided
public new static RSAPrivateKey FromXml(string xml)
{ return RSAPrivateKey.FromXml(new XmlTextReader(new StringReader(xml))); }
/// Creates the key from the information provided
public new static RSAPrivateKey FromStore(string name)
{ return (RSAPrivateKey)RSAPublicKey.FromStore(name); }
/// Creates the key from the information provided
public new static RSAPrivateKey FromStore(CspParameters parameters)
{ return (RSAPrivateKey)RSAPublicKey.FromStore(parameters); }
/// Create RSAPrivateKey with a new keypair of (DefaultKeySize) bit length
public RSAPrivateKey()
: this(DefaultKeySize) { }
// Create RSAPrivateKey with a new keypair of (keySize) bit length
/// the bit-size of the key to generate, 384 - 16384 in increments of 8
public RSAPrivateKey(int keySize)
: this(new RSACryptoServiceProvider(Check.InRange(keySize & 0x0FFF8, MinKeySize, MaxKeySize)))
{ }
/// Create RSAPrivateKey with the provided key
public RSAPrivateKey(X509Certificate2 certificate)
: this(CertToPrivateKey(certificate)) { }
/// Create RSAPrivateKey with the provided key
public RSAPrivateKey(RSAParameters keyInfo)
: this(new RSACryptoServiceProvider())
{
Check.NotNull(keyInfo);
Check.NotNull(keyInfo.D);
Check.NotNull(keyInfo.DP);
Check.NotNull(keyInfo.DQ);
Check.NotNull(keyInfo.Exponent);
Check.NotNull(keyInfo.InverseQ);
Check.NotNull(keyInfo.Modulus);
Check.NotNull(keyInfo.P);
Check.NotNull(keyInfo.Q);
RSAKey.ImportParameters(keyInfo);
}
/// Create RSAPrivateKey with the provided key
public RSAPrivateKey(RSACryptoServiceProvider keyInfo)
: base(keyInfo)
{ }
/// Extract private key from certificate
private static RSACryptoServiceProvider CertToPrivateKey(X509Certificate2 cert)
{
Check.IsEqual(true, cert.HasPrivateKey);
return Check.IsAssignable(cert.PrivateKey);
}
/// Creates the key from the information provided
public new static RSAPrivateKey FromXml(XmlReader xrdr)
{
RSAParameters param = new RSAParameters();
while (xrdr.Read())
{
if (xrdr.NodeType == XmlNodeType.Element)
{
if (xrdr.LocalName == "Modulus") param.Modulus = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "Exponent") param.Exponent = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "P") param.P = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "Q") param.Q = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "DP") param.DP = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "DQ") param.DQ = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "InverseQ") param.InverseQ = Convert.FromBase64String(xrdr.ReadElementString());
if (xrdr.LocalName == "D") param.D = Convert.FromBase64String(xrdr.ReadElementString());
}
}
Check.Assert(param.Modulus != null && param.Exponent != null
&& param.P != null && param.Q != null && param.DP != null
&& param.DQ!= null && param.InverseQ != null && param.D != null);
return FromParameters(param);
}
/// Returns the key information
public override void ToXml(XmlWriter xml)
{
RSAParameters param = ExportParameters();
xml.WriteStartElement("RSAKeyValue");
xml.WriteElementString("Modulus", Convert.ToBase64String(param.Modulus));
xml.WriteElementString("Exponent", Convert.ToBase64String(param.Exponent));
xml.WriteElementString("P", Convert.ToBase64String(param.P));
xml.WriteElementString("Q", Convert.ToBase64String(param.Q));
xml.WriteElementString("DP", Convert.ToBase64String(param.DP));
xml.WriteElementString("DQ", Convert.ToBase64String(param.DQ));
xml.WriteElementString("InverseQ", Convert.ToBase64String(param.InverseQ));
xml.WriteElementString("D", Convert.ToBase64String(param.D));
xml.WriteEndElement();
}
///
/// Returns only the public key of this public/private key pair
///
public RSAPublicKey PublicKey
{
get { return new RSAPublicKey(RSAKey.ExportParameters(false)); }
}
///
/// Signs the provided Hash code with the private key and returns the hash signature
///
public byte[] SignHash(Hash hashBytes)
{
return RSAKey.SignHash(hashBytes.ToArray(), hashBytes.AlgorithmOID);
}
}
}