用Portable.BouncyCastle来进行加解密的代码demo
前言
这里对之前对接的公司中的代码demo做一个总结,原本为清一色的java,哈哈。这里都转成C#。用到的库是Portable.BouncyCastle。官网。之前也是准备用.net core 内置的类,方法,但实际在用的时候比如因为desKey并不是特定长度的,导致抛了一些异常,于是就改用了这个库。
这个库中有如下这么一段的介绍:
The lightweight API works with everything from the J2ME to the JDK 1.7 and there is also an API in C# providing equivalent functionality for most of the above.
实际用下来也确实如此,方法基本上是“相同”名字的。
正文
Des
这是一种对称密钥加密算法,也就是说加密解密的秘钥是一样的。
- 加密
public static string DesEncrypt(string dataXml, string desKey)
{
var keyParam = ParameterUtilities.CreateKeyParameter("DES", Convert.FromBase64String(desKey));
var cipher = (BufferedBlockCipher) CipherUtilities.GetCipher("DES/NONE/PKCS5Padding");
cipher.Init(true, keyParam);
var bs = Encoding.UTF8.GetBytes(dataXml);
var rst = cipher.DoFinal(bs);
// var asciiBs = Encoding.ASCII.GetBytes(Encoding.UTF8.GetString(rst));
return Convert.ToBase64String(rst);
}
看方法签名,需要两个参数,1.要加密的内容,2.加密的秘钥。先用desKey作为参数创建一个keyParam。然后用DES/NONE/PKCS5Padding
作为参数获取一个cipher,这个参数用来详细描述des加密时候的相关细节,具体是根据对方给的代码里面来的。然后对这个cipher做一个初始化,第一个参数true
表示这个cipher是用来加密的,并且传入之前的keyParam。然后获取加密内容的字节数组,编码是utf-8,一般都是这个编码。然后调用cipher的DoFinal方法就能获取加密之后的内容了。最后一行转成了一个base64字符串。
通过这个方法就能对数据进行des加密了。中间也涉及了字符编码格式,base64转换的内容,这些是根据给的demo写的。
- 解密
public static string DesDecrypt(string text, string desKey)
{
var keyParam = ParameterUtilities.CreateKeyParameter("DES", Convert.FromBase64String(desKey));
var cipher = (BufferedBlockCipher) CipherUtilities.GetCipher("DES/NONE/PKCS5Padding");
cipher.Init(false, keyParam);
var bs = Convert.FromBase64String(text);
var rst = cipher.DoFinal(bs);
return Encoding.UTF8.GetString(rst);
}
下面是解密方法。两个参数,1.需要解密的内容。 2.解密的key。这个key是和加密的时候一样的。首先也是通过desKey获取一个keyParam,然后用DES/NONE/PKCS5Padding
参数获取一个cipher。然后用false
参数初始化这个cipher为解密用的。获取base64编码过的字节数组,调用DoFinal
方法解密字节数组。解密出来的字节数组再用utf-8编码获取实际的字符串,这个是和前面的加密方法对应的。
MD5
这个用的是core框架自带的方法。
- 加密
因为要区别BouncyCastle中的MD5类,所以对引用取一下别名。
using SystemX = System.Security.Cryptography;
public static string Md5(string data)
{
var text = data;
using (var md5 = SystemX.MD5.Create())
{
var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(text));
return BitConverter.ToString(bs).Replace("-", "").ToLower();
}
}
方法就一个参数,需要做md5的数据。首先是创建一个md5的实例。然后取加密内容的字节数组,再调用ComputeHash方法对数组做hash值计算,然后转成16进制的字符串,去掉-
字符,最后转小写。
- 没有解密,你懂的。
SHA-1
SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。copy自维基百科。
public static string ComputeSha1(string text)
{
Sha1Digest sha1Digest = new Sha1Digest();
var retValue = new byte[sha1Digest.GetDigestSize()];
var bs = Encoding.UTF8.GetBytes(text);
sha1Digest.BlockUpdate(bs, 0, bs.Length);
sha1Digest.DoFinal(retValue, 0);
return BitConverter.ToString(retValue).Replace("-", "");
}
这个方法和SHA-256很像,在SHA-256解释。
SHA-256
public static string ComputeSha256(string text)
{
Sha256Digest sha256Digest = new Sha256Digest();
var retValue = new byte[sha256Digest.GetDigestSize()];
var bs = Encoding.UTF8.GetBytes(text);
sha256Digest.BlockUpdate(bs, 0, bs.Length);
sha256Digest.DoFinal(retValue, 0);
return BitConverter.ToString(retValue).Replace("-", "");
}
下面是当时的java-demo
SHA256Digest digester = new SHA256Digest();
byte[] retValue = new byte[digester.getDigestSize()];
digester.update(key.getBytes(), 0, key.length());
digester.doFinal(retValue, 0);
return retValue;
对比一下两份代码,基本是一样的。首先是实例化一个Sha256Digest,然后获取原文的字节数组,然后用这个Sha256Digest去更新内容,最后输出到retValue数组中。
SHA家族很庞大,224,256,384,512等等等。用法都一样。
SignEnvelop
这个方法有点复杂,取这个名字是因为demo就是这么写的。
private static byte[] EncryptEnvelop(X509Certificate certificate, byte[] bsOrgData)
{
var gen = new CmsEnvelopedDataGenerator();
var data = new CmsProcessableByteArray(bsOrgData);
gen.AddKeyTransRecipient(certificate);
var enveloped = gen.Generate(data, CmsEnvelopedDataGenerator.DesEde3Cbc);
var a = enveloped.ContentInfo.ToAsn1Object();
return a.GetEncoded();
}
/// <summary>
/// pfx文件密码
/// </summary>
private const string pfxPwd = "sss";
/// <summary>
/// pfx证书,主要是拿私钥
/// </summary>
public static string PfxPath => Path.Combine(AppContext.BaseDirectory, "rsa", "sss.pfx");
/// <summary>
/// cer证书,拿公钥
/// </summary>
public static string CertPath => Path.Combine(AppContext.BaseDirectory, "rsa", "sss.cer");
public static string SignEnvelop(string orgData)
{
Pkcs12StoreBuilder pkcs12StoreBuilder = new Pkcs12StoreBuilder();
var pkcs12Store = pkcs12StoreBuilder.Build();
pkcs12Store.Load(File.OpenRead(PfxPath), pfxPwd.ToCharArray());
IEnumerable aliases = pkcs12Store.Aliases;
var enumerator = aliases.GetEnumerator();
enumerator.MoveNext();
var alias = enumerator.Current.ToString();
//从pfx文件中获取CmsSignedData需要的key。
var privKey = pkcs12Store.GetKey(alias);
var x509Cert = pkcs12Store.GetCertificate(alias).Certificate;
var bs = Encoding.UTF8.GetBytes(orgData);
CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
gen.AddSignerInfoGenerator(
new SignerInfoGeneratorBuilder().Build(new Asn1SignatureFactory("SHA1withRSA", privKey.Key), x509Cert));
IList certList = new ArrayList();
certList.Add(x509Cert);
gen.AddCertificates(X509StoreFactory.Create("Certificate/Collection",
new X509CollectionStoreParameters(certList)));
var msg = new CmsProcessableByteArray(bs);
var sigData = gen.Generate(msg, true);
var signData = sigData.GetEncoded();
var certificate = DotNetUtilities.FromX509Certificate(new SystemX509.X509Certificate(CertPath));
var rst = Convert.ToBase64String(EncryptEnvelop(certificate, signData));
return rst;
}
这里有两个方法,拆分一下,主要有以下几个demo功能。
- 使用
Pkcs12StoreBuilder
从pfx文件中获取CmsSignedData需要的key。 - 使用
DotNetUtilities
从cer文件中获取X509Certificate对象。
RSA
读取pem文件中的公钥做加密,这里用到了一个分段加密的逻辑。
文件参数
private static string publicKeyFile = Path.Combine(AppContext.BaseDirectory, "rsa", "rsa_public_key.pem");
private static string privateKeyFile = Path.Combine(AppContext.BaseDirectory, "rsa", "rsa_private_key.pem");
- 用公钥对数据进行分段加密
public static string GetNonce(string randomStr)
{
var maxBlock = 245;
int offset = 0;
int i = 0;
var outBytes = new List<byte>();
var pubKey = new PemReader(new StreamReader(publicKeyFile)).ReadObject() as AsymmetricKeyParameter;
IBufferedCipher c = CipherUtilities.GetCipher("RSA/NONE/PKCS1PADDING");// 参数与JAVA中解密的参数一致
c.Init(true, pubKey);
var data = Encoding.UTF8.GetBytes(randomStr);
var inputLength = data.Length;
while (inputLength - offset > 0)
{
if (inputLength - offset > maxBlock)
{
outBytes.AddRange(c.DoFinal(data, offset, maxBlock));
}
else
{
outBytes.AddRange(c.DoFinal(data, offset, inputLength - offset));
}
i++;
offset = i * maxBlock;
}
return Convert.ToBase64String(outBytes.ToArray());
}
主要是用PemReader
对象对pem文件进行读写操作。因为是RSA加密的,所以对象转换成AsymmetricKeyParameter
。其他的就和之前的DES之类的类似。
- 用私钥以及
MD5withRSA
对数据算签名
public static string GetSignature(string text)
{
var bsToEncrypt = Encoding.UTF8.GetBytes(text);
PemReader pemReader = new PemReader(new StreamReader(privateKeyFile));
var pem = (AsymmetricCipherKeyPair)pemReader.ReadObject();
ISigner sig = SignerUtilities.GetSigner("MD5withRSA");
sig.Init(true, pem.Private);
sig.BlockUpdate(bsToEncrypt, 0, bsToEncrypt.Length);
byte[] signature = sig.GenerateSignature();
/* Base 64 encode the sig so its 8-bit clean */
var signedString = Convert.ToBase64String(signature);
return signedString;
}
主要还是PemReader
对象的使用以及使用ISigner
构造一个签名工具。
- 解密
private static byte[] Decrypt(byte[] input, string privateKeyPath)
{
PemReader r = new PemReader(new StreamReader(privateKeyPath)); //载入私钥
var readObject = r.ReadObject();
AsymmetricCipherKeyPair priKey = (AsymmetricCipherKeyPair)readObject;
string mode = "RSA/NONE/PKCS1Padding";
IBufferedCipher c = CipherUtilities.GetCipher(mode);
c.Init(false, priKey.Private);
byte[] outBytes = c.DoFinal(input);
return outBytes;
}
public static string RSADecryptByPrivateKey(string text)
{
if (string.IsNullOrEmpty(text))
{
return string.Empty;
}
var bs = Convert.FromBase64String(text);
var rst = new List<byte>();
#region 分段解密 解决加密密文过长问题
int len = 256;
int m = bs.Length / len;
if (m * len != bs.Length)
{
m = m + 1;
}
for (int i = 0; i < m; i++)
{
byte[] temp = new byte[256];
if (i < m - 1)
{
temp = bs.Skip(i * len).Take(len).ToArray();
}
else
{
temp = new byte[bs.Length % len == 0 ? 1 * len : bs.Length % len];
bs.Skip(i * len).Take(bs.Length % len == 0 ? len : bs.Length % len).ToArray().CopyTo(temp, 0);
}
rst.AddRange(Decrypt(temp, privateKeyFile));
}
#endregion
return Encoding.UTF8.GetString(rst.ToArray());
}
因为加密是分段的,所以解密也需要分段,套路和之前一样。
完。
用Portable.BouncyCastle来进行加解密的代码demo的更多相关文章
- 彻底告别加解密模块代码拷贝-JCE核心Cpiher详解
前提 javax.crypto.Cipher,翻译为密码,其实叫做密码器更加合适.Cipher是JCA(Java Cryptographic Extension,Java加密扩展)的核心,提供基于多种 ...
- android md5加密与rsa加解密实现代码
import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security. ...
- openssl - rsa加解密例程
原文链接: http://www.cnblogs.com/cswuyg/p/3187462.html openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加 ...
- T-SQL问题解决集锦——数据加解密
原文:T-SQL问题解决集锦--数据加解密 以下代码已经在SQLServer2008上的示例数据库测试通过 问题一:如何为数据进行加密与解密,避免使用者窃取机密数据? 对于一些敏感数据,如密码.卡号, ...
- 6. Java 加解密技术系列之 3DES
Java 加解密技术系列之 3DES 序 背景 概念 原理 代码实现 结束语 序 上一篇文章讲的是对称加密算法 — — DES,这篇文章打算在 DES 的基础上,继续多讲一点,也就是 3 重 DES ...
- python实现RSA加密和签名以及分段加解密的方案
1.前言 很多朋友在工作中,会遇到一些接口使用RSA加密和签名来处理的请求参数,那么遇到这个问题的时候,第一时间当然是找开发要加解密的方法,但是开发给加解密代码,大多数情况都是java,c++,js等 ...
- 惊呆了!不改一行 Java 代码竟然就能轻松解决敏感信息加解密|原创
前言 出于安全考虑,现需要将数据库的中敏感信息加密存储到数据库中,但是正常业务交互还是需要使用明文数据,所以查询返回我们还需要经过相应的解密才能返回给调用方. ps:日常开发中,我们要有一定的安全意识 ...
- .NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书
简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...
- 使用bouncycastle进行DESede/DESeee/AES128/AES192/AES256的加解密
前言 默认的jdk不支持DESeee的算法,本地化的JDK中配置有拦截规则,可以通过使用bouncycastle的jar包中的DESEngine类来进行DESeee算法的运算. DES的8字节加解密 ...
随机推荐
- linux使用windows磁盘,挂载共享目录
实例说明:客户两台服务器,一台web服务器(linux)只有50G,课程资源太多太大导致磁盘不够用:客户的文档服务器(windows)磁盘很大超过1T,所以产生了,将web资源使用文档服务器磁盘的想法 ...
- __BEGIN_DECLS 和 __END_DECLS
扩充C语言在编译的时候按照C++编译器进行统一处理,使得C++代码能够调用C编译生成的中间代码. 由于C语言的头文件可能被不同类型的编译器读取,因此写C语言的头文件必须慎重. 我们编写代码,经常需要c ...
- hessian在ssh项目中的配置
一. 在服务端发布一个web项目 1.创建一个动态的web项目,并导入hessian的jar包 2. 在服务端的crm项目中创建接口 package cn.rodge.crm.service;impo ...
- 安装Twisted
Python看到网络编程,讲到Twisted这个强大的网络框架,很有兴趣,配合 官方文档,打算研究一哈,但是一开始就碰壁了. 安装的时候 pip install Twisted报错了: 提示没有装什么 ...
- Jmeter4.0分布式测试时启动Jmeter.server时报错
最近又开始研究Jmeter,将新版本4.0下载下来体验,准备远程分布式测试,又出现一些问题,废话不多说,直入主题把! Windows 系统启动Jmeter 4.0的JmeterServer.ba ...
- maven入门 (二)_私服安装与上传下载
本篇文章主要介绍maven的私服安装和 jar包的上传与下载.毕竟大家还是在公司需要上传jar包到自己公司私服的. 1.安装私服 下载链接: https://pan.baidu.com/s/17dbQ ...
- 剑指Offer常见问题整理
1 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数.(来自牛客网,剑指offer) ...
- 微信H5中静默登录及非静默登录的正确使用姿势
在微信中打开网页且需要调用微信登录接口时,微信官方给我们提供了两种登录调用方式:静默登录和非静默登录:但是官方文档中却没有说明在何种情况下使用静默登录,何种情况下使用非静默登录,所以在这里,我想将之前 ...
- bootstrap table的样式
<style> table{ border: 1px solid #ddd; background-color: transparent; border-spacing:; border- ...
- 35.app后端搜索入门
现在人们的网络生活已经离不开搜索了,遇到不懂的问题,想知道的事情,搜索一下,就知道答案. 在app中,最常见的搜索情景就是搜索用户.只有几百,几千的用户量时,可以直接用用like这样的模糊查询,但是, ...