openssl使用以及C#加密和数字签名
如何使用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 { /// <summary> /// This helper function parses an RSA private key using the ASN.1 format /// </summary> /// <param name="privateKeyBytes">Byte array containing PEM string of private key.</param> /// <returns>An instance of <see cref="RSACryptoServiceProvider"/> rapresenting the requested private key. /// Null if method fails on retriving the key.</returns> 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; }