openssl使用以及C#加密和数字签名
阅读原文时间:2023年07月10日阅读:1

如何使用openssl生成RSA公钥和私钥对

http://blog.csdn.net/scape1989/article/details/18959657

https://www.openssl.org/docs/manmaster/apps/rsautl.html

C# RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密

http://www.2cto.com/kf/201007/52626.html

RSA Key Converter(XML to PEM,PEM to XML)

https://superdry.apphb.com/tools/online-rsa-key-converter

openssl
it defaulte generate RSA format , sometimes need convert to pkcs8 format

generate a private key pair with pkcs8 format
openssl>pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM –nocrypt

generate a private key pair with pem format
openssl>genrsa -out rsa_private_key.pem 1024

output the public key

openssl>rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

use public key to encrypt data
openssl>rsautl -encrypt -in orig.txt -inkey rsa_public_key.pem -pubin -out orig.en

use private key to decrypt data
openssl>rsautl -decrypt -in orig.en -inkey rsa_private_key.pem -out orig.de

use private key to signature data
rsautl -sign -in orig.txt -inkey rsa_private_key.pem -out sig

output the data with private key from signed data
rsautl -verify -in sig -inkey rsa_private_key.pem

!!!Error:output the data with public key from signed data
rsautl -verify -in sig -inkey rsa_public_key.pem

Examine the reaw signed data
rsautl -verify -in sig -inkey rsa_private_key.pem -raw -hexdump

SSOBLL
sso = newSSOBLL();

string
signature = sso.SignData(string.Empty,SSOBLL.KeyType.PrivatePEM,
sigData);

string
signature2 = sso.SignData(string.Empty,SSOBLL.KeyType.PrivateXML,
sigData);

bool
valid = sso.VerifySignData(string.Empty,SSOBLL.KeyType.PublicXML,sigData,Convert.FromBase64String(signature));

public class SSOBLL
{
public enum KeyType
{
PrivatePEM,
PublicPEM,
PrivateXML,
PublicXML
}

    public string SignData(string privateKeyStr, KeyType keyType, string dataStr)  
    {  
        byte\[\] data = Encoding.UTF8.GetBytes(dataStr);  
        string base64 = string.Empty;  
        if (keyType == KeyType.PrivatePEM)  
        {

            string keyStr = GetKey(privateKeyStr, KeyType.PrivatePEM);  
            byte\[\] privateKey = Helpers.GetBytesFromPEM(keyStr, PemStringType.RsaPrivateKey);  
            RSACryptoServiceProvider rsa = Crypto.DecodeRsaPrivateKey(privateKey);  
            byte\[\] hash = rsa.SignData(data, SHA1.Create());  
            base64 = Convert.ToBase64String(hash);  
        }  
        if (keyType == KeyType.PrivateXML)  
        {  
            string privatekey = GetKey(privateKeyStr, keyType);  
            RSACryptoServiceProvider oRSA3 = new RSACryptoServiceProvider();  
            oRSA3.FromXmlString(privatekey);  
            byte\[\] BOutput = oRSA3.SignData(data, "SHA1");  
            base64 = Convert.ToBase64String(BOutput);  
        }  
        return base64;  
    }

    public bool VerifySignData(RSACryptoServiceProvider rsa, KeyType keyType, string dataStr, byte\[\] dataHash)  
    {  
        byte\[\] data = Encoding.UTF8.GetBytes(dataStr);  
        bool valid = false;  
        if (keyType == KeyType.PublicPEM)  
        {  
            RSAParameters key = rsa.ExportParameters(false); // false:公钥  true:私钥  
            RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();  
            RSAalg.ImportParameters(key);  
            valid = RSAalg.VerifyData(data, new SHA1CryptoServiceProvider(), dataHash);  
        }  
        else if (keyType == KeyType.PublicXML)  
        {  
            string publickey = rsa.ToXmlString(false);//false:公钥  true:私钥  
            valid = VerifySignData(publickey, keyType, dataStr, dataHash);  
        }  
        return valid;  
    }

    public bool VerifySignData(string keyStr, KeyType keyType, string dataStr, byte\[\] dataHash)  
    {  
        byte\[\] data = Encoding.UTF8.GetBytes(dataStr);  
        bool valid = false;  
        if (keyType == KeyType.PublicXML)  
        {  
            RSACryptoServiceProvider oRSA4 = new RSACryptoServiceProvider();  
            string publickey = GetKey(keyStr, KeyType.PublicXML);  
            oRSA4.FromXmlString(publickey);  
            valid = oRSA4.VerifyData(data, "SHA1", dataHash);  
        }  
        return valid;  
    }

    private string GetKey(string keyStr, KeyType keyType)  
    {  
        string key = keyStr;  
        if (string.IsNullOrWhiteSpace(keyStr))  
        {  
            string KeyFile = AppDomain.CurrentDomain.BaseDirectory;  
            switch (keyType)  
            {  
                case KeyType.PrivatePEM:  
                    KeyFile += @"Keys\\private.pem";  
                    break;  
                case KeyType.PublicPEM:  
                    KeyFile += @"Keys\\public.pem";  
                    break;  
                case KeyType.PrivateXML:  
                    KeyFile += @"Keys\\private.xml";  
                    break;  
                case KeyType.PublicXML:  
                    KeyFile += @"Keys\\public.xml";  
                    break;  
                default:  
                    KeyFile += @"Keys\\private.pem";  
                    break;  
            }  
            key = File.ReadAllText(KeyFile);  
        }  
        return key;  
    }

}

public class Crypto
{
///

/// This helper function parses an RSA private key using the ASN.1 format ///
/// Byte array containing PEM string of private key.
/// An instance of rapresenting the requested private key. /// Null if method fails on retriving the key.
public static RSACryptoServiceProvider DecodeRsaPrivateKey(byte[] privateKeyBytes)
{
MemoryStream ms = new MemoryStream(privateKeyBytes);
BinaryReader rd = new BinaryReader(ms);

        try  
        {  
            byte byteValue;  
            ushort shortValue;

            shortValue = rd.ReadUInt16();

            switch (shortValue)  
            {  
                case 0x8130:  
                    // If true, data is little endian since the proper logical seq is 0x30 0x81  
                    rd.ReadByte(); //advance 1 byte  
                    break;  
                case 0x8230:  
                    rd.ReadInt16();  //advance 2 bytes  
                    break;  
                default:  
                    Debug.Assert(false);     // Improper ASN.1 format  
                    return null;  
            }

            shortValue = rd.ReadUInt16();  
            if (shortValue != 0x0102) // (version number)  
            {  
                Debug.Assert(false);     // Improper ASN.1 format, unexpected version number  
                return null;  
            }

            byteValue = rd.ReadByte();  
            if (byteValue != 0x00)  
            {  
                Debug.Assert(false);     // Improper ASN.1 format  
                return null;  
            }

            // The data following the version will be the ASN.1 data itself, which in our case  
            // are a sequence of integers.

            // In order to solve a problem with instancing RSACryptoServiceProvider  
            // via default constructor on .net 4.0 this is a hack  
            CspParameters parms = new CspParameters();  
            parms.Flags = CspProviderFlags.NoFlags;  
            parms.KeyContainerName = Guid.NewGuid().ToString().ToUpperInvariant();  
            parms.ProviderType = ((Environment.OSVersion.Version.Major > 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor >= 1))) ? 0x18 : 1;

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(parms);  
            RSAParameters rsAparams = new RSAParameters();

            rsAparams.Modulus = rd.ReadBytes(Helpers.DecodeIntegerSize(rd));

            // Argh, this is a pain.  From emperical testing it appears to be that RSAParameters doesn't like byte buffers that  
            // have their leading zeros removed.  The RFC doesn't address this area that I can see, so it's hard to say that this  
            // is a bug, but it sure would be helpful if it allowed that. So, there's some extra code here that knows what the  
            // sizes of the various components are supposed to be.  Using these sizes we can ensure the buffer sizes are exactly  
            // what the RSAParameters expect.  Thanks, Microsoft.  
            RSAParameterTraits traits = new RSAParameterTraits(rsAparams.Modulus.Length \* 8);

            rsAparams.Modulus = Helpers.AlignBytes(rsAparams.Modulus, traits.size\_Mod);  
            rsAparams.Exponent = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_Exp);  
            rsAparams.D = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_D);  
            rsAparams.P = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_P);  
            rsAparams.Q = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_Q);  
            rsAparams.DP = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_DP);  
            rsAparams.DQ = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_DQ);  
            rsAparams.InverseQ = Helpers.AlignBytes(rd.ReadBytes(Helpers.DecodeIntegerSize(rd)), traits.size\_InvQ);

            rsa.ImportParameters(rsAparams);  
            return rsa;  
        }  
        catch (Exception)  
        {  
            Debug.Assert(false);  
            return null;  
        }  
        finally  
        {  
            rd.Close();  
        }  
    }  
}

public enum PemStringType
{
Certificate,
RsaPrivateKey,
RsaPublicKey
}

public class Helpers  
{  
    /// <summary>  
    /// This helper function parses an integer size from the reader using the ASN.1 format  
    /// </summary>  
    /// <param name="rd"></param>  
    /// <returns></returns>  
    public static int DecodeIntegerSize(System.IO.BinaryReader rd)  
    {  
        byte byteValue;  
        int count;

        byteValue = rd.ReadByte();  
        if (byteValue != 0x02)        // indicates an ASN.1 integer value follows  
            return 0;

        byteValue = rd.ReadByte();  
        if (byteValue == 0x81)  
        {  
            count = rd.ReadByte();    // data size is the following byte  
        }  
        else if (byteValue == 0x82)  
        {  
            byte hi = rd.ReadByte();  // data size in next 2 bytes  
            byte lo = rd.ReadByte();  
            count = BitConverter.ToUInt16(new\[\] { lo, hi }, 0);  
        }  
        else  
        {  
            count = byteValue;        // we already have the data size  
        }

        //remove high order zeros in data  
        while (rd.ReadByte() == 0x00)  
        {  
            count -= 1;  
        }  
        rd.BaseStream.Seek(-1, System.IO.SeekOrigin.Current);

        return count;  
    }

    /// <summary>  
    ///  
    /// </summary>  
    /// <param name="pemString"></param>  
    /// <param name="type"></param>  
    /// <returns></returns>  
    public static byte\[\] GetBytesFromPEM(string pemString, PemStringType type)  
    {  
        string header; string footer;

        switch (type)  
        {  
            case PemStringType.Certificate:  
                header = "-----BEGIN CERTIFICATE-----";  
                footer = "-----END CERTIFICATE-----";  
                break;  
            case PemStringType.RsaPrivateKey:  
                header = "-----BEGIN RSA PRIVATE KEY-----";  
                footer = "-----END RSA PRIVATE KEY-----";  
                break;  
            case PemStringType.RsaPublicKey:  
                header = "-----BEGIN PUBLIC KEY-----";  
                footer = "-----END PUBLIC KEY-----";  
                break;  
            default:  
                return null;  
        }

        int start = pemString.IndexOf(header) + header.Length;  
        int end = pemString.IndexOf(footer, start) - start;  
        return Convert.FromBase64String(pemString.Substring(start, end));  
    }

    /// <summary>  
    ///  
    /// </summary>  
    /// <param name="inputBytes"></param>  
    /// <param name="alignSize"></param>  
    /// <returns></returns>  
    public static byte\[\] AlignBytes(byte\[\] inputBytes, int alignSize)  
    {  
        int    inputBytesSize = inputBytes.Length;

        if ((alignSize != -1) && (inputBytesSize < alignSize))  
        {  
            byte\[\] buf = new byte\[alignSize\];  
            for (int i = 0; i < inputBytesSize; ++i)  
            {  
                buf\[i + (alignSize - inputBytesSize)\] = inputBytes\[i\];  
            }  
            return buf;  
        }  
        else  
        {  
            return inputBytes;      // Already aligned, or doesn't need alignment  
        }  
    }

internal class RSAParameterTraits
{
public RSAParameterTraits(int modulusLengthInBits)
{
// The modulus length is supposed to be one of the common lengths, which is the commonly referred to strength of the key,
// like 1024 bit, 2048 bit, etc. It might be a few bits off though, since if the modulus has leading zeros it could show
// up as 1016 bits or something like that.
int assumedLength = -1;
double logbase = Math.Log(modulusLengthInBits, 2);
if (logbase == (int)logbase)
{
// It's already an even power of 2
assumedLength = modulusLengthInBits;
}
else
{
// It's not an even power of 2, so round it up to the nearest power of 2.
assumedLength = (int)(logbase + 1.0);
assumedLength = (int)(Math.Pow(2, assumedLength));
System.Diagnostics.Debug.Assert(false); // Can this really happen in the field? I've never seen it, so if it happens
// you should verify that this really does the 'right' thing!
}

        switch (assumedLength)  
        {  
            case 1024:  
                this.size\_Mod = 0x80;  
                this.size\_Exp = -1;  
                this.size\_D = 0x80;  
                this.size\_P = 0x40;  
                this.size\_Q = 0x40;  
                this.size\_DP = 0x40;  
                this.size\_DQ = 0x40;  
                this.size\_InvQ = 0x40;  
                break;  
            case 2048:  
                this.size\_Mod = 0x100;  
                this.size\_Exp = -1;  
                this.size\_D = 0x100;  
                this.size\_P = 0x80;  
                this.size\_Q = 0x80;  
                this.size\_DP = 0x80;  
                this.size\_DQ = 0x80;  
                this.size\_InvQ = 0x80;  
                break;  
            case 4096:  
                this.size\_Mod = 0x200;  
                this.size\_Exp = -1;  
                this.size\_D = 0x200;  
                this.size\_P = 0x100;  
                this.size\_Q = 0x100;  
                this.size\_DP = 0x100;  
                this.size\_DQ = 0x100;  
                this.size\_InvQ = 0x100;  
                break;  
            default:  
                System.Diagnostics.Debug.Assert(false); // Unknown key size?  
                break;  
        }  
    }

    public int size\_Mod  = -1;  
    public int size\_Exp  = -1;  
    public int size\_D    = -1;  
    public int size\_P    = -1;  
    public int size\_Q    = -1;  
    public int size\_DP   = -1;  
    public int size\_DQ   = -1;  
    public int size\_InvQ = -1;  
}