c#(实现rsa非对称加密算法)-mile米乐体育
c#,实现rsa非对称加密算法
目录
- 公钥与私钥
- c#实现
公钥与私钥
公钥与私钥是成对的,一般的,我们认为的是公钥加密、私钥解密、私钥签名、公钥验证,有人说成私钥加密,公钥解密时不对的。
公钥与私钥的生成有多种方式,可以通过程序生成(下文具体实现),可以通过openssl工具:
# 生成一个私钥,推荐使用1024位的秘钥,秘钥以pem格式保存到-out参数指定的文件中,采用pkcs1格式 openssl genrsa -out rsa.pem 1024 # 生成与私钥对应的公钥,生成的是subject public key,一般配合pkcs8格式私钥使用 openssl rsa -in rsa.pem -pubout -out rsa.pub
rsa生成公钥与私钥一般有两种格式:pkcs1和pkcs8,上面的命令生成的秘钥是pkcs1格式的,而公钥是subject public key,一般配合pkcs8格式私钥使用,所以就可能会涉及到pkcs1和pkcs8之间的转换:
# pkcs1格式私钥转换为pkcs8格式私钥,私钥直接输出到-out参数指定的文件中 openssl pkcs8 -topk8 -inform pem -in rsa.pem -outform pem -nocrypt -out rsa_pkcs8.pem # pkcs8格式私钥转换为pkcs1格式私钥,私钥直接输出到-out参数指定的文件中 openssl rsa -in rsa_pkcs8.pem -out rsa_pkcs1.pem # pkcs1格式公钥转换为pkcs8格式公钥,转换后的内容直接输出 openssl rsa -pubin -in rsa.pub -rsapublickey_out # pkcs8格式公钥转换为pkcs1格式公钥,转换后的内容直接输出 openssl rsa -rsapublickey_in -pubout -in rsa.pub
现实中,我们往往从pem、crt、pfx文件获取公私和私钥,crt、pfx的制作可以参考:简单的制作ssl证书,并在nginx和iis中使用,或者使用现成的:https://www.zzm8.com/d/file/p/2021062118042516953/2021062118042516954 (提取码:c6tj),密码都是:123456
c#实现
为了方便读取pem、crt、pfx文件中的公私和私钥,这里我使用了第三方的包:portable.bouncycastle,可以使用nuget安装:install-package portable.bouncycastle
接着,这里我封装了一个rsahelper辅助类来实现各种rsa加密的过程:
using org.bouncycastle.utilities.io.pem; using system; using system.collections.generic; using system.io; using system.security.cryptography; using system.security.cryptography.x509certificates; using system.text; namespace consoleapp1 { public class rsahelper { #region key ////// 将秘钥保存到pem文件 /// /// /// /// ///public static void writetopem(byte[] buffer, bool isprivatekey, string pemfilename) { pemobject pemobject = new pemobject(isprivatekey ? "rsa private key" : "rsa public key", buffer); if (file.exists(pemfilename)) { file.delete(pemfilename); } using (var filestream = new filestream(pemfilename, filemode.openorcreate, fileaccess.write)) { using (var sw = new streamwriter(filestream)) { var writer = new pemwriter(sw); writer.writeobject(pemobject); sw.flush(); } } } /// /// 从pem文件中读取秘钥 /// /// ///public static byte[] readfrompem(string pemfilename) { using (var filestream = new filestream(pemfilename, filemode.open, fileaccess.read)) { using (var sw = new streamreader(filestream)) { var writer = new pemreader(sw); return writer.readpemobject().content; } } } /// /// 从xml中读取秘钥 /// /// /// /// ///public static byte[] readfromxml(string xml, bool isprivatekey, bool usepkcs8) { using (var rsa = new rsacryptoserviceprovider()) { rsa.fromxmlstring(xml); if (isprivatekey) { return usepkcs8 ? rsa.exportpkcs8privatekey() : rsa.exportrsaprivatekey(); } return usepkcs8 ? rsa.exportsubjectpublickeyinfo() : rsa.exportrsapublickey(); } } /// /// 将秘钥保存到xml中 /// /// /// /// ///public static string writetoxml(byte[] buffer, bool isprivatekey, bool usepkcs8) { using (var rsa = creatersacryptoserviceprovider(buffer, isprivatekey, usepkcs8)) { return rsa.toxmlstring(isprivatekey); } } /// /// 获取rsa非对称加密的key /// /// /// public static void generatersakey(bool usepkcs8, out byte[] publickey, out byte[] privatekey) { using (rsacryptoserviceprovider rsa = new rsacryptoserviceprovider()) { rsa.keysize = 1024;//1024位 if (usepkcs8) { //使用pkcs8填充方式导出 publickey = rsa.exportsubjectpublickeyinfo();//公钥 privatekey = rsa.exportpkcs8privatekey();//私钥 } else { //使用pkcs1填充方式导出 publickey = rsa.exportrsapublickey();//公钥 privatekey = rsa.exportrsaprivatekey();//私钥 } } } ////// 从pfx文件获取rsa非对称加密的key /// /// /// /// public static void readfrompfx(string pfxfilename, string password, out byte[] publickey, out byte[] privatekey) { x509certificate2 x509certificate2 = new x509certificate2(pfxfilename, password, x509keystorageflags.exportable); publickey = x509certificate2.getrsapublickey().exportrsapublickey(); privatekey = x509certificate2.getrsaprivatekey().exportrsaprivatekey(); } ////// 从crt文件中读取公钥 /// /// /// ///public static byte[] readpublickeyfromcrt(string crtfilename, string password) { x509certificate2 x509certificate2 = new x509certificate2(crtfilename, password, x509keystorageflags.exportable); var publickey = x509certificate2.getrsapublickey().exportrsapublickey(); return publickey; } #endregion #region pkcs1 and pkcs8 /// /// pkcs1转pkcs8 /// /// /// ///public static byte[] pkcs1topkcs8(bool isprivatekey, byte[] buffer) { using (var rsa = new rsacryptoserviceprovider()) { if (isprivatekey) { rsa.importrsaprivatekey(buffer, out _); return rsa.exportpkcs8privatekey(); } else { rsa.importrsapublickey(buffer, out _); return rsa.exportsubjectpublickeyinfo(); } } } /// /// pkcs8转pkcs1 /// /// /// ///public static byte[] pkcs8topkcs1(bool isprivatekey, byte[] buffer) { using (var rsa = new rsacryptoserviceprovider()) { if (isprivatekey) { rsa.importpkcs8privatekey(buffer, out _); return rsa.exportrsaprivatekey(); } else { rsa.importsubjectpublickeyinfo(buffer, out _); return rsa.exportrsapublickey(); } } } #endregion #region rsa /// /// 获取一个rsacryptoserviceprovider /// /// /// /// ///public static rsacryptoserviceprovider creatersacryptoserviceprovider(byte[] buffer, bool isprivatekey, bool usepkcs8 = false) { rsacryptoserviceprovider rsa = new rsacryptoserviceprovider(); if (isprivatekey) { if (usepkcs8) rsa.importpkcs8privatekey(buffer, out _); else rsa.importrsaprivatekey(buffer, out _); } else { if (usepkcs8) rsa.importsubjectpublickeyinfo(buffer, out _); else rsa.importrsapublickey(buffer, out _); } return rsa; } /// /// rsa公钥加密 /// /// 待加密的明文 /// 公钥 /// 是否使用pkcs8填充 ///public static string rsaencrypt(string value, byte[] publickey, bool usepkcs8 = false) { if (string.isnullorempty(value)) return value; using (rsacryptoserviceprovider rsa = creatersacryptoserviceprovider(publickey, false, usepkcs8)) { var buffer = encoding.utf8.getbytes(value); buffer = rsa.encrypt(buffer, false); //使用hex格式输出数据 stringbuilder result = new stringbuilder(); foreach (byte b in buffer) { result.appendformat("{0:x2}", b); } return result.tostring(); //或者使用下面的输出 //return bitconverter.tostring(buffer).replace("-", "").tolower(); } } /// /// rsa私钥解密 /// /// 密文 /// 私钥 /// 是否使用pkcs8填充 ///public static string rsadecrypt(string value, byte[] privatekey, bool usepkcs8 = false) { if (string.isnullorempty(value)) return value; using (rsacryptoserviceprovider rsa = creatersacryptoserviceprovider(privatekey, true, usepkcs8)) { //转换hex格式数据为byte数组 var buffer = new byte[value.length / 2]; for (var i = 0; i < buffer.length; i ) { buffer[i] = (byte)convert.toint32(value.substring(i * 2, 2), 16); } buffer = rsa.decrypt(buffer, false); return encoding.utf8.getstring(buffer); } } /// /// rsa私钥生成签名 /// /// 原始值 /// 公钥 /// 签名hash算法:sha,sha1,md5,sha256,sha384,sha512 /// 是否使用pkcs8填充 ///public static string sign(string value, byte[] privatekey, string halg = "md5", bool usepkcs8 = false) { if (string.isnullorempty(value)) return value; using (rsacryptoserviceprovider rsa = creatersacryptoserviceprovider(privatekey, true, usepkcs8)) { byte[] buffer = encoding.utf8.getbytes(value); buffer = rsa.signdata(buffer, hashalgorithm.create(halg)); //使用hex格式输出数据 stringbuilder result = new stringbuilder(); foreach (byte b in buffer) { result.appendformat("{0:x2}", b); } return result.tostring(); //或者使用下面的输出 //return bitconverter.tostring(buffer).replace("-", "").tolower(); } } /// /// rsa公钥验证签名 /// /// 原始值 /// 公钥 /// 签名 /// 签名hash算法:sha,sha1,md5,sha256,sha384,sha512 /// 是否使用pkcs8填充 ///public static bool verify(string value, byte[] publickey, string signature, string halg = "md5", bool usepkcs8 = false) { if (string.isnullorempty(value)) return false; using (rsacryptoserviceprovider rsa = creatersacryptoserviceprovider(publickey, false, usepkcs8)) { //转换hex格式数据为byte数组 var buffer = new byte[signature.length / 2]; for (var i = 0; i < buffer.length; i ) { buffer[i] = (byte)convert.toint32(signature.substring(i * 2, 2), 16); } return rsa.verifydata(encoding.utf8.getbytes(value), hashalgorithm.create(halg), buffer); } } #endregion } }
可以使用生成rsa的公私秘钥:
//通过程序生成 rsahelper.generatersakey(usepkcs8, out publickey, out privatekey);
生成秘钥后,需要保存,一般保存到pem文件中:
//保存到pem文件,filepath是文件目录 rsahelper.writetopem(publickey, false, path.combine(filepath, "rsa.pub")); rsahelper.writetopem(privatekey, true, path.combine(filepath, "rsa.pem"));
还以将公钥和私钥输出为xml格式:
//保存到xml中 string publickeyxml = rsahelper.writetoxml(publickey, false, usepkcs8); string privatekeyxml = rsahelper.writetoxml(privatekey, true, usepkcs8);
保存到pem文件和xml中后,也可以从中读取:
//从pem文件获取,filepath是文件目录 publickey = rsahelper.readfrompem(path.combine(filepath, "rsa.pub")); privatekey = rsahelper.readfrompem(path.combine(filepath, "rsa.pem")); //从xml中读取 publickey = rsahelper.readfromxml(publickeyxml, false, usepkcs8); privatekey = rsahelper.readfromxml(privatekeyxml, true, usepkcs8);
还可以从crt证书中读取公钥,而crt文件不包含私钥,因此需要单独获取私钥:
//从crt文件读取,filepath是文件目录 publickey = rsahelper.readpublickeyfromcrt(path.combine(filepath, "demo.crt"), ""); privatekey = rsahelper.readfrompem(path.combine(filepath, "demo.key"));
pfx文件中包含了公钥和私钥,可以很方便就读取到:
//从demo.pfx文件读取(demo.pfx采用的是pkcs1),filepath是文件目录 rsahelper.readfrompfx(path.combine(filepath, "demo.pfx"), "123456", out publickey, out privatekey);
有时候我们还可能需要进行秘钥的转换:
// pkcs8格式公钥转换为pkcs1格式公钥 publickey = rsahelper.pkcs8topkcs1(false, publickey); // pkcs8格式私钥转换为pkcs1格式私钥 privatekey = rsahelper.pkcs8topkcs1(true, privatekey); // pkcs1格式公钥转换为pkcs8格式公钥 publickey = rsahelper.pkcs1topkcs8(false, publickey); // pkcs1格式私钥转换为pkcs8格式私钥 privatekey = rsahelper.pkcs1topkcs8(true, privatekey);
有了公钥和私钥,接下就就能实现加密、解密、签名、验证签名等操作了:
string encrypttext = rsahelper.rsaencrypt(text, publickey, usepkcs8); console.writeline($"【{text}】经过【rsa】加密后:{encrypttext}"); string decrypttext = rsahelper.rsadecrypt(encrypttext, privatekey, usepkcs8); console.writeline($"【{encrypttext}】经过【rsa】解密后:{decrypttext}"); string signature = rsahelper.sign(text, privatekey, "md5", usepkcs8); console.writeline($"【{text}】经过【rsa】签名后:{signature}"); bool result = rsahelper.verify(text, publickey, signature, "md5", usepkcs8); console.writeline($"【{text}】的签名【{signature}】经过【rsa】验证后结果是:{result}");
完整的demo代码:
using system; using system.io; namespace consoleapp1 { class program { static void main(string[] args) { string text = "上山打老虎"; bool usepkcs8 = true;// usepkcs8=true表示是否成pkcs8格式的公私秘钥,否则乘车pkcs1格式的公私秘钥 string filepath = directory.getcurrentdirectory(); console.writeline($"文件路径:{filepath}");// 存放pem,crt,pfx等文件的目录 byte[] publickey, privatekey;// 公钥和私钥 //通过程序生成 rsahelper.generatersakey(usepkcs8, out publickey, out privatekey); //从pem文件获取,filepath是文件目录 //publickey = rsahelper.readfrompem(path.combine(filepath, "rsa.pub")); //privatekey = rsahelper.readfrompem(path.combine(filepath, "rsa.pem")); //从demo.pfx文件读取(demo.pfx采用的是pkcs1),filepath是文件目录 //rsahelper.readfrompfx(path.combine(filepath, "demo.pfx"), "123456", out publickey, out privatekey); //从crt文件读取,filepath是文件目录 //publickey = rsahelper.readpublickeyfromcrt(path.combine(filepath, "demo.crt"), ""); //privatekey = rsahelper.readfrompem(path.combine(filepath, "demo.key")); //保存到pem文件,filepath是文件目录 rsahelper.writetopem(publickey, false, path.combine(filepath, "rsa.pub")); rsahelper.writetopem(privatekey, true, path.combine(filepath, "rsa.pem")); //保存到xml中 string publickeyxml = rsahelper.writetoxml(publickey, false, usepkcs8); string privatekeyxml = rsahelper.writetoxml(privatekey, true, usepkcs8); //从xml中读取 publickey = rsahelper.readfromxml(publickeyxml, false, usepkcs8); privatekey = rsahelper.readfromxml(privatekeyxml, true, usepkcs8); // pkcs8格式公钥转换为pkcs1格式公钥 publickey = rsahelper.pkcs8topkcs1(false, publickey); // pkcs8格式私钥转换为pkcs1格式私钥 privatekey = rsahelper.pkcs8topkcs1(true, privatekey); // pkcs1格式公钥转换为pkcs8格式公钥 publickey = rsahelper.pkcs1topkcs8(false, publickey); // pkcs1格式私钥转换为pkcs8格式私钥 privatekey = rsahelper.pkcs1topkcs8(true, privatekey); string encrypttext = rsahelper.rsaencrypt(text, publickey, usepkcs8); console.writeline($"【{text}】经过【rsa】加密后:{encrypttext}"); string decrypttext = rsahelper.rsadecrypt(encrypttext, privatekey, usepkcs8); console.writeline($"【{encrypttext}】经过【rsa】解密后:{decrypttext}"); string signature = rsahelper.sign(text, privatekey, "md5", usepkcs8); console.writeline($"【{text}】经过【rsa】签名后:{signature}"); bool result = rsahelper.verify(text, publickey, signature, "md5", usepkcs8); console.writeline($"【{text}】的签名【{signature}】经过【rsa】验证后结果是:{result}"); } } }
以上就是c# 实现rsa非对称加密算法的详细内容,更多关于c# rsa非对称加密算法的资料请关注趣讯吧其它相关文章!