Java加密解密和数字签名完整代码示例
常见的加密算法
基本的单向加密算法:
base64严格地说,属于编码格式,而非加密算法
md5(messagedigestalgorithm5,信息摘要算法)
sha(securehashalgorithm,安全散列算法)
hmac(hashmessageauthenticationcode,散列消息鉴别码)
复杂的对称加密(des、pbe)、非对称加密算法:
des(dataencryptionstandard,数据加密算法)
pbe(password-basedencryption,基于密码验证)
rsa(算法的名字以发明者的名字命名:ronrivest,adishamir和leonardadleman)
dh(diffie-hellman算法,密钥一致协议)
dsa(digitalsignaturealgorithm,数字签名)
ecc(ellipticcurvescryptography,椭圆曲线密码编码学)
数字签名
算法简述
数字签名算法可以看做是一种带有密钥的消息摘要算法,并且这种密钥包含了公钥和私钥。也就是说,数字签名算法是非对称加密算法和消息摘要算法的结合体。
特点
数字签名算法要求能够验证数据完整性、认证数据来源,并起到抗否认的作用。
原理
数字签名算法包含签名和验证两项操作,遵循私钥签名,公钥验证的方式。
签名时要使用私钥和待签名数据,验证时则需要公钥、签名值和待签名数据,其核心算法主要是消息摘要算法。
1. 消息摘要
string beforedegist = "asdf"; system.out.println("摘要前:"+beforedegist); //初始信息要转换成字节流的形式 byte[] plaintext = beforedegist.getbytes("utf8"); //使用getinstance("算法")来获得消息摘要,这里使用sha-1的160位算法或者md5算法 gedigest messagedigest = messagedigest.getinstance("sha-1"); messagedigest messagedigest = messagedigest.getinstance("md5"); system.out.println("/n" + messagedigest.getprovider().getinfo()); //开始使用算法 messagedigest.update(plaintext); //输出算法运算结果 string afterdegist = new string(messagedigest.digest(),"utf8"); system.out.println("摘要后:"+afterdegist);
2. 私钥加密
/** * 此例子是对一个字符串信息,用一个私钥(key)加密,然后在用该私钥解密,验证是否一致 * 私钥加密,是对称加密 * 使用对称算法。比如:a用一个密钥对一个文件加密,而b读取这个文件的话,则需要和a一样的密钥,双方共享一 * 个私钥(而在web环境下,私钥在传递时容易被侦听) * * 附:主要对称算法有:des(实际密钥只用到56 位) * aes(支持三种密钥长度:128、192、256位),通常首先128位,其他的还有desede等 */ <span style="white-space: pre; "> </span>string before = "asdf"; byte[] plaintext = before.getbytes("utf8"); // step 1.
system.out.println("start generate aes key."); //得到一个使用aes算法的keygenerator的实例 keygenerator keygen = keygenerator.getinstance("aes"); //定义密钥长度128位 keygen.init(128); //通过keygenerator产生一个key(密钥算法刚才已定义,为aes) key key = keygen.generatekey(); system.out.println("finish generating aes key="+key);
//step 2.
//获得一个私钥加密类cipher,定义cipher的基本信息:ecb是加密方式,pkcs5padding是填充方法 cipher cipher = cipher.getinstance("aes/ecb/pkcs5padding"); //system.out.println("/n" + cipher.getprovider().getinfo());
//step 3.
// 使用私钥加密 system.out.println("/n用私钥加密..."); // 把刚才生成的key当作参数,初始化使用刚才获得的私钥加密类,cipher.encrypt_mode意思是加密 cipher.init(cipher.encrypt_mode, key); //私钥加密类cipher进行加密,加密后返回一个字节流byte[] byte[] ciphertext = cipher.dofinal(plaintext); //以utf8格式把字节流转化为string string after1 = new string(ciphertext, "utf8"); system.out.println("用私钥加密完成:"+after1);
// step 4.
[java] view plain copy //使用私钥对刚才加密的信息进行解密,看看是否一致,cipher.decrypt_mode意思是解密钥 system.out.println("/n用私钥解密..."); cipher.init(cipher.decrypt_mode, key); //对刚才私钥加密的字节流进行解密,解密后返回一个字节流byte[] byte[] newplaintext = cipher.dofinal(ciphertext); string after2 = new string(newplaintext, "utf8"); system.out.println("用私钥解密完成:"+after2);
3. 公钥加密
string before = "asdf"; byte[] plaintext = before.getbytes("utf8"); //产生一个rsa密钥生成器keypairgenerator(顾名思义:一对钥匙生成器) keypairgenerator keygen = keypairgenerator.getinstance("rsa"); //定义密钥长度1024位 keygen.initialize(1024); //通过keypairgenerator产生密钥,注意:这里的key是一对钥匙!! keypair key = keygen.generatekeypair(); //获得一个rsa的cipher类,使用公钥加密 cipher cipher = cipher.getinstance("rsa/ecb/pkcs1padding"); //system.out.println("/n" + cipher.getprovider().getinfo()); system.out.println("/n用公钥加密..."); //cipher.encrypt_mode意思是加密,从一对钥匙中得到公钥 key.getpublic() cipher.init(cipher.encrypt_mode, key.getpublic()); //用公钥进行加密,返回一个字节流 byte[] ciphertext = cipher.dofinal(plaintext); //以utf8格式把字节流转化为string string after1 = new string(ciphertext, "utf8"); system.out.println("用公钥加密完成:"+after1); //使用私钥解密 system.out.println("/n用私钥解密..."); //cipher.decrypt_mode意思是解密模式,从一对钥匙中得到私钥 key.getprivate() cipher.init(cipher.decrypt_mode, key.getprivate()); //用私钥进行解密,返回一个字节流 byte[] newplaintext = cipher.dofinal(ciphertext); string after2 = new string(newplaintext, "utf8"); system.out.println("用私钥解密完成:"+after2);
4. 数字签名
/** * 此例子是数字签名的例子,使用rsa私钥对消息摘要(这里指的是原始数据)进行签名,然后使用公钥验证签名 * * a通过使用b的公钥加密数据后发给b,b利用b的私钥解密就得到了需要的数据(进过b公钥加密的数据只有b的私钥能够 * 解开,c没有b的私钥,所以c解不开,但c可以使用b的公钥加密一份数据发给b,这样一来,问题来了,b收到的数据到 * 底是a发过来的还是c发过来的呢) * 由于私钥是唯一的,那么a就可以利用a自己的私钥进行加密,然后b再利用a的公钥来解密,就可以确定:一定是a的消 * 息,数字签名的原理就基于此 * * 总结:a想将目标数据传给b,此时a需要准备1和2两部分 * 1:a使用b的公钥将原始信息加密,以起到保密作用(只有b的私钥能解开,其他人使用其他钥匙都解不开,当然就保密咯) * 2:a使用a的私钥将原始信息的摘要进行签名,以起到接收方b确定是a发过来的作用(a用a的私钥对目标数据的摘要进行签 * 名,然后传给b,同时,c用c的私钥对任意信息进行签名也传给b,b想接受的是a的数据(比如说一个转帐请求),于是b * 就通过a的公钥对接受到的两个信息进行解密,解开的就是a(a的公钥能且只能解开a的私钥加密的数据)) */ string before = "asdf"; byte[] plaintext = before.getbytes("utf8"); //形成rsa公钥对 keypairgenerator keygen = keypairgenerator.getinstance("rsa"); keygen.initialize(1024); keypair key = keygen.generatekeypair(); //使用私钥签名********************************************************** signature sig = signature.getinstance("sha1withrsa"); sig.initsign(key.getprivate()); //sig对象得到私钥 //签名对象得到原始数据 sig.update(plaintext); //sig对象得到原始数据(现实中用的是原始数据的摘要,摘要的是单向的,即摘要算法后无法解密) byte[] signature = sig.sign(); //sig对象用私钥对原始数据进行签名,签名后得到签名signature em.out.println(sig.getprovider().getinfo()); string after1 = new string(signature, "utf8"); system.out.println("/n用私钥签名后:"+after1); //使用公钥验证 sig.initverify(key.getpublic()); //sig对象得到公钥 //签名对象得到原始信息 sig.update(plaintext); //sig对象得到原始数据(现实中是摘要) try { if (sig.verify(signature)) { //sig对象用公钥解密签名signature得到原始数据(即摘要),一致则true system.out.println("签名验证正确!!"+new string(plaintext, "utf8")); } else { system.out.println("签名验证失败!!"); } } catch (signatureexception e) { system.out.println("签名验证失败!!"); }
5. 数字证书
/** * 此例是对“数字证书”文件的操作 * java平台(在机器上安装jdk)为你提供了密钥库(证书库),cmd下提供了keytool命令就可以创建证书库 * * 在运行此例前: * 在c盘目录下创建一个证书,指定证书库为bocsoftkeylib,创建别名为testcertification的一条证书,它指定用 * rsa 算法生成,且指定密钥长度为1024,证书有效期为1年 * 导出证书文件为tc.cer已存于本地磁盘c:/ * 密码是qazzaq */ try { //前提:将证书库中的一条证书导出到证书文件(我写的例子里证书文件叫tc.cer) //从证书文件tc.cer里读取证书信息 certificatefactory cf = certificatefactory.getinstance("x.509"); fileinputstream in = new fileinputstream("c:/tc.cer"); //将文件以文件流的形式读入证书类certificate中 certificate c = cf.generatecertificate(in); system.err.println("转换成string后的证书信息:"+c.tostring()); */ //或者不用上面代码的方法,直接从证书库中读取证书信息,和上面的结果一摸一样 string pass="qazzaq"; fileinputstream in2=new fileinputstream("c:/bocsoftkeylib"); keystore ks=keystore.getinstance("jks"); ks.load(in2,pass.tochararray()); string alias = "testcertification"; //alias为条目的别名 certificate c=ks.getcertificate(alias); system.err.println("转换成string后的证书信息:"+c.tostring()); //获取获取x509certificate类型的对象,这是证书类获取certificate的子类,实现了更多方法 x509certificate t=(x509certificate)c; //从信息中提取需要信息 system.out.println("版本号:"+t.getversion()); system.out.println("序列号:"+t.getserialnumber().tostring(16)); system.out.println("主体名:"+t.getsubjectdn()); system.out.println("签发者:"+t.getissuerdn()); system.out.println("有效期:"+t.getnotbefore()); system.out.println("签名算法:"+t.getsigalgname()); byte [] sig=t.getsignature(); //签名值 publickey pk = t.getpublickey(); byte [] pkenc=pk.getencoded(); system.out.println("公钥:"); for (int i=0;i<pkenc.length;i++){ system.out.print(pkenc[i]+","); } system.err.println(); //证书的日期有效性检查,颁发的证书都有一个有效性的日期区间 date timenow=new date(); t.checkvalidity(timenow); system.out.println("证书的日期有效性检查:有效的证书日期!"); //验证证书签名的有效性,通过数字证书认证中心(ca)机构颁布给客户的ca证书,比如:caroot.crt文件 //我手里没有ca颁给我的证书,所以下面代码执行不了 /*fileinputstream in3=new fileinputstream("caroot.crt"); //获取ca证书 certificate cac = cf.generatecertificate(in3); //获取ca的公钥 publickey pbk=cac.getpublickey(); //c为本地证书,也就是待检验的证书,用ca的公钥校验数字证书c的有效性 c.verify(pbk); } catch(certificateexpiredexception e){//证书的日期有效性检查:过期 system.out.println("证书的日期有效性检查:过期"); } catch(certificatenotyetvalidexception e){ //证书的日期有效性检查:尚未生效 system.out.println("证书的日期有效性检查:尚未生效"); } catch (certificateexception ce) { ce.printstacktrace(); } catch (filenotfoundexception fe) { fe.printstacktrace(); } /*catch (ioexception ioe){ } catch (keystoreexception kse){ }*/ catch (exception e){ e.printstacktrace(); } }
总结
以上就是本文关于java加密解密和数字签名完整代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
上一篇: 用sql语句实现分离和附加数据库的方法