java加密解密算法MD5SHA1,DSA
通常,使⽤的加密算法⽐较简便⾼效,密钥简短,加解密速度快,破译极其困难。本⽂介绍了
MD5/SHA1,DSA,DESede/DES,Diffie-Hellman的使⽤。
第1章基础知识
1.1. 单钥密码体制
单钥密码体制是⼀种传统的加密,是指信息的发送⽅和接收⽅共同使⽤同⼀把密钥进⾏加解密。
通常,使⽤的加密算法⽐较简便⾼效,密钥简短,加解密速度快,破译极其困难。但是加密的安全性依靠密钥保管的安全性,在公开的上安全地传送和保管密钥是⼀个严峻的问题,并且如果在多⽤户的情况下密钥的保管安全性也是⼀个问题。
单钥密码体制的代表是美国的DES
1.2. 消息摘要
⼀个消息摘要就是⼀个数据块的数字指纹。即对⼀个任意长度的⼀个数据块进⾏计算,产⽣⼀个唯⼀指
印(对于SHA1是产⽣⼀个20字节的⼆进制数组)。
消息摘要有两个基本属性:
两个不同的报⽂难以⽣成相同的摘要
难以对指定的摘要⽣成⼀个报⽂,⽽由该报⽂反推算出该指定的摘要
代表:美国国家标准技术研究所的SHA1和⿇省理⼯学院Ronald Rivest提出的MD5
1.3. Diffie-Hellman密钥⼀致协议
密钥⼀致协议是由公开密钥密码体制的奠基⼈Diffie和Hellman所提出的⼀种思想。
先决条件,允许两名⽤户在公开媒体上交换信息以⽣成"⼀致"的,可以共享的密钥
代表:指数密钥⼀致协议(Exponential Key Agreement Protocol)
1.4. ⾮对称算法与公钥体系
1976 年,Dittie和Hellman为解决密钥管理问题,在他们的奠基性的⼯作"密码学的新⽅向"⼀⽂中,提
出⼀种密钥交换协议,允许在不安全的媒体上通过通讯双⽅交换信息,安全地传送秘密密钥。在此新思想的基础上,很快出现了⾮对称密钥密码体制,即公钥密码体制。在公钥体制中,加密密钥不同于解密密钥,加密密钥公之于众,谁都可以使⽤;解密密钥只有解密⼈⾃⼰知道。它们分别称为公开密钥(Public key)和秘密密钥(Private key)。
迄今为⽌的所有公钥密码体系中,RSA系统是最著名、最多使⽤的⼀种。RSA公开密钥密码系统是由R.Rivest、A.Shamir和L.Adleman俊教授于1977年提出的。RSA的取名就是来⾃于这三位发明者的姓的第⼀个字母
1.5. 数字签名java源代码加密
所谓数字签名就是信息发送者⽤其私钥对从所传报⽂中提取出的特征数据(或称数字指纹)进⾏RSA算法操作,以保证发信⼈⽆法抵赖曾发过该信息(即不可抵赖性),同时也确保信息报⽂在经签名后末被篡改(即完整性)。当信息接收者收到报⽂后,就可以⽤发送者的公钥对数字签名进⾏验证。
在数字签名中有重要作⽤的数字指纹是通过⼀类特殊的散列函数(HASH函数)⽣成的,对这些HASH函数的特殊要求是:
1. 接受的输⼊报⽂数据没有长度限制;
2. 对任何输⼊报⽂数据⽣成固定长度的摘要(数字指纹)输出
3. 从报⽂能⽅便地算出摘要;
4. 难以对指定的摘要⽣成⼀个报⽂,⽽由该报⽂反推算出该指定的摘要;
5. 两个不同的报⽂难以⽣成相同的摘要
代表:DSA
第2章在JAVA中的实现
2.1. 相关
Diffie-Hellman密钥⼀致协议和DES程序需要JCE⼯具库的⽀持,可以到下载JCE,并进⾏安装。简易安装把 jce1.2.1\lib 下的所有内容复制到%java_home%\lib\ext下,如果没有ext⽬录⾃⾏建⽴,再把jce1_2_1.jar和sunjce_provider.jar添加到CLASSPATH内,更详细说明请看相应⽤户⼿册
2.2. 消息摘要MD5和SHA的使⽤
使⽤⽅法:
⾸先⽤⽣成⼀个MessageDigest类,确定计算⽅法
.security.MessageDigest alga=java.Instance("SHA-1");
添加要进⾏计算摘要的信息
alga.Bytes());
计算出摘要
byte[] digesta=alga.digest();
发送给其他⼈你的信息和摘要
其他⼈⽤相同的⽅法初始化,添加信息,最后进⾏⽐较摘要是否相同
algb.isEqual(digesta,algb.digest())
相关AIP
java.security.MessageDigest 类
static getInstance(String algorithm)
返回⼀个MessageDigest对象,它实现指定的算法
参数:算法名,如 SHA-1 或MD5
void update (byte input)
void update (byte[] input)
void update(byte[] input, int offset, int len)
添加要进⾏计算摘要的信息
byte[] digest()
完成计算,返回计算得到的摘要(对于MD5是16位,SHA是20位)
void reset()
复位
static boolean isEqual(byte[] digesta, byte[] digestb)
⽐效两个摘要是否相同
代码:
import java.security.*;
public class myDigest {
public static void main(String[] args) {
myDigest my=new myDigest();
}
public void testDigest()
{
try {
String myinfo="我的测试信息";
//java.security.MessageDigest alg=java.Instance("MD5");
java.security.MessageDigest alga=java.Instance("SHA-1");
alga.Bytes());
byte[] digesta=alga.digest();
System.out.println("本信息摘要是:"+byte2hex(digesta));
//通过某中⽅式传给其他⼈你的信息(myinfo)和摘要(digesta) 对⽅可以判断是否更改或传输正常
java.security.MessageDigest algb=java.Instance("SHA-1");
algb.Bytes());
if (algb.isEqual(digesta,algb.digest())) {
System.out.println("信息检查正常");
}
else
{
System.out.println("摘要不相同");
}
}
catch (java.security.NoSuchAlgorithmException ex) {
System.out.println("⾮法摘要算法");
}
}
public String byte2hex(byte[] b) //⼆⾏制转字符串
{
String hs="";
String stmp="";
for (int n=0;n<b.length;n++)
{
stmp=(java.HexString(b[n] & 0XFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
if (n<b.length-1) hs=hs+":";
}
UpperCase();
}
}
2.3. 数字签名DSA
1. 对于⼀个⽤户来讲⾸先要⽣成他的密钥对,并且分别保存
⽣成⼀个KeyPairGenerator实例
java.security.KeyPairGenerator keygen=java.Instance("DSA");
如果设定随机产⽣器就⽤如相代码初始化
SecureRandom secrand=new SecureRandom();
secrand.setSeed("tttt".getBytes()); //初始化随机产⽣器
keygen.initialize(512,secrand); //初始化密钥⽣成器
否则
keygen.initialize(512);
⽣成密钥公钥pubkey和私钥prikey
KeyPair ateKeyPair(); //⽣成密钥组
PublicKey Public();
PrivateKey Private();
分别保存在myprikey.dat和mypubkey.dat中,以便下次不在⽣成
(⽣成密钥对的时间⽐较长
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));
out.writeObject(prikey);
out.close();
out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
out.writeObject(pubkey);
out.close();
2. ⽤他私⼈密钥(prikey)对他所确认的信息(info)进⾏数字签名产⽣⼀个签名数组
从⽂件中读⼊私⼈密钥(prikey)
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
PrivateKey myprikey=(adObject();
in.close();
初始⼀个Signature对象,并⽤私钥对信息签名
java.security.Signature signet=java.Instance("DSA");
signet.initSign(myprikey);
signet.Bytes());
byte[] signed=signet.sign();
把信息和签名保存在⼀个⽂件中(myinfo.dat)
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));
out.writeObject(myinfo);
out.writeObject(signed);
out.close();
把他的公钥的信息及签名发给其它⽤户
3. 其他⽤户⽤他的公共密钥(pubkey)和签名(signed)和信息(info)进⾏验证是否由他签名的信息
读⼊公钥
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
PublicKey pubkey=(adObject();
in.close();
读⼊签名和信息
in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
String info=(adObject();
byte[] signed=(byte[])in.readObject();
in.close();
初始⼀个Signature对象,并⽤公钥和签名进⾏验证
java.security.Signature signetcheck=java.Instance("DSA");
signetcheck.initVerify(pubkey);
signetcheck.Bytes());
if (signetcheck.verify(signed)) { System.out.println("签名正常");}
对于密钥的保存本⽂是⽤对象流的⽅式保存和传送的,也可可以⽤编码的⽅式保存.注意要
import java.security.spec.*
import java.security.*
具休说明如下
public key是⽤X.509编码的,例码如下:
byte[] Encoded(); //⽣成编码
//传送⼆进制编码
//以下代码转换编码为相应key对象
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
KeyFactory keyFactory = Instance("DSA");
PublicKey bobPubKey = atePublic(bobPubKeySpec);
对于Private key是⽤PKCS#8编码,例码如下:
byte[] Encoded();
//传送⼆进制编码
//以下代码转换编码为相应key对象
PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS);
KeyFactory Instance("DSA");
PrivateKey atePrivate(priPKCS8);
4. 常⽤API
java.security.KeyPairGenerator 密钥⽣成器类
public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException 以指定的算法返回⼀个KeyPairGenerator 对象
参数: algorithm 算法名.如:"DSA","RSA"
public void initialize(int keysize)
以指定的长度初始化KeyPairGenerator对象,如果没有初始化系统以1024长度默认设置
参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数
public void initialize(int keysize, SecureRandom random)
以指定的长度初始化和随机发⽣器初始化KeyPairGenerator对象
参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数
random ⼀个随机位的来源(对于initialize(int keysize)使⽤了默认随机器
public abstract KeyPair generateKeyPair()
产⽣新密钥对
java.security.KeyPair 密钥对类
public PrivateKey getPrivate()
返回私钥
public PublicKey getPublic()
返回公钥
java.security.Signature 签名类
public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
返回⼀个指定算法的Signature对象
参数 algorithm 如:"DSA"
public final void initSign(PrivateKey privateKey)
throws InvalidKeyException
⽤指定的私钥初始化
参数:privateKey 所进⾏签名时⽤的私钥
public final void update(byte data)
throws SignatureException
public final void update(byte[] data)
throws SignatureException
public final void update(byte[] data, int off, int len)
throws SignatureException
添加要签名的信息
public final byte[] sign()
throws SignatureException
返回签名的数组,前提是initSign和update
public final void initVerify(PublicKey publicKey)
throws InvalidKeyException
⽤指定的公钥初始化
参数:publicKey 验证时⽤的公钥
public final boolean verify(byte[] signature)
throws SignatureException
验证签名是否有效,前提是已经initVerify初始化
参数: signature 签名数组
*/
import java.security.*;
import java.security.spec.*;
public class testdsa {
public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception {
testdsa my=new testdsa();
my.run();
}
public void run()
{
//数字签名⽣成密钥
//第⼀步⽣成密钥对,如果已经⽣成过,本过程就可以跳过,对⽤户来讲myprikey.dat要保存在本地
//⽽mypubkey.dat给发布给其它⽤户
if ((new java.io.File("myprikey.dat")).exists()==false) {
if (generatekey()==false) {
System.out.println("⽣成密钥对败");
return;
};
}
//第⼆步,此⽤户
//从⽂件中读⼊私钥,对⼀个字符串进⾏签名后保存在⼀个⽂件(myinfo.dat)中
//并且再把myinfo.dat发送出去
//为了⽅便数字签名也放进了myifno.dat⽂件中,当然也可分别发送
try {
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
PrivateKey myprikey=(adObject();
in.close();
// java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509); //java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec
String myinfo="这是我的信息"; //要签名的信息
//⽤私钥对信息⽣成数字签名
java.security.Signature signet=java.Instance("DSA");
signet.initSign(myprikey);
signet.Bytes());
byte[] signed=signet.sign(); //对信息的数字签名
System.out.println("signed(签名内容)="+byte2hex(signed));
//把信息和数字签名保存在⼀个⽂件中
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat")); out.writeObject(myinfo);
out.writeObject(signed);
out.close();
System.out.println("签名并⽣成⽂件成功");
}
catch (java.lang.Exception e) {
e.printStackTrace();
System.out.println("签名并⽣成⽂件失败");
};
//第三步
//其他⼈通过公共⽅式得到此户的公钥和⽂件
//其他⼈⽤此户的公钥,对⽂件进⾏检查,如果成功说明是此⽤户发布的信息.
//
try {
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat")); PublicKey pubkey=(adObject();
in.close();
System.out.Format());
in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
String info=(adObject();
byte[] signed=(byte[])in.readObject();
in.close();
java.security.Signature signetcheck=java.Instance("DSA");
signetcheck.initVerify(pubkey);
signetcheck.Bytes());
if (signetcheck.verify(signed)) {
System.out.println("info="+info);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论