1 生成RSA密钥
生成非对称加密的公钥和私钥-生成RSA密钥
非对称加密将加密的密钥和解密的密钥分开。A事先生成一对密钥,一个用于加密,称为公钥(公钥),一个用于解密,称为私钥。由于产生这一对密钥的一些数学特性,公钥加密的信息只能用私钥解密。这样,A只要将公钥对外公开,不论谁就可以使用这个公钥给A发送秘密信息了。A接收到加密信息后可以用私钥打开。由于只需要传递公钥,而公钥只能加密不能解密,因此即使攻击者知道了公钥也无济于事。
本文介绍的是RSA非对称加密算法。
GenerateRSAKey.java
package sign;
import java.io.*;
import java.security.*;
public class GenerateRSAKey {
public static void main(String args[]) throws Exception{
KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp=kpg.genKeyPair();
PublicKey pbkey=kp.getPublic();
PrivateKey prkey=kp.getPrivate();
// 保存公钥
FileOutputStream f1=new FileOutputStream("RSA_pub.dat");
ObjectOutputStream b1=new ObjectOutputStream(f1);
b1.writeObject(pbkey);
// 保存私钥
FileOutputStream f2=new FileOutputStream("RSA_priv.dat");
ObjectOutputStream b2=new ObjectOutputStream(f2);
b2.writeObject(prkey);
}
}
2 对称密钥的生成和保存-生成DES密钥
对称密钥的生成及以对象序列化方式保存
import java.io.*;
import javax.crypto.*;
public class GetDesKey{
public static void main(String args[]) throws Exception{
KeyGenerator kg=KeyGenerator.getInstance("DESede");
kg.init(168);
SecretKey k=kg.generateKey( );
FileOutputStream f=new FileOutputStream("DesKey.dat");
ObjectOutputStream b=new ObjectOutputStream(f);
b.writeObject(k);//要写入对象数据只能使用对象数据流
byte[] c=k.getEncoded();//生成编码的字节表示展示一下,使用时可以删除
for(int i=0;i<c.length;i++){
System.out.print(c[i]);
}}}
以字节保存对称密钥
import java.io.*;
import java.security.*;
public class Skey_kb{
public static void main(String args[]) throws Exception{
FileInputStream f=new FileInputStream("key1.dat");
ObjectInputStream b=new ObjectInputStream(f);
Key k=(Key)b.readObject( );
byte[ ] kb=k.getEncoded( );
FileOutputStream f2=new FileOutputStream("keykb1.dat");
f2.write(kb);
// 打印密钥编码中的内容
for(int i=0;i<kb.length;i++<span style="font-family: Verdana, Arial, Helvetica, sans-serif;"> ){</span>
System.out.print(kb[i]+",");
}
}
}
3 使用CBC方式进行加密
对明文分组的不同处理方式形成了不同的加密方式,本章前面各节的程序中没有指定加密方式,默认的加密方式是ECB(Electronic Code Book),它对每个明文分组独立进行处理。所以明文若8个字节一组相同的话(如本节开头的“Hello123Hello123Hello123Hello123”),加密出的结果也是8个字节一组相同的。
另一种加密方式称为CBC(Cipher Block Chaining),它先加密第一个分组,然后使用得到的密文加密第二个分组,加密第二个分组得到的密文再加密第三个分组,……。这样,即使两个分组相同,得到的密文也不同。剩下的问题是如果两个密文的开头8个字节相同,按照这种加密方式,只要使用的密钥相同,则每条密文的开头8个字节也将相同。为此,CBC使用一个8个字节的随机数(称为初始向量,IV)来加密第一个分组,其作用类似于基于口令加密中的盐。
因此,使用CBC方式首先要生成初始向量,然后在获取密码器对象时通过getInstance( )方法的参数设定加密方式,在密码器初始化时传入初始向量。
//必须拥有DES加密密钥文件 DesKey.dat 和需要加密的文件1.txt
import java.io.*;
import java.util.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class CBC{
public static void main(String args[]) throws Exception{
FileInputStream fi=new FileInputStream("1.txt");
int l=fi.available();
byte[] c=new byte[l];
fi.read(c);
FileInputStream f1=new FileInputStream("DesKey.dat");
ObjectInputStream b=new ObjectInputStream(f1);
Key k=(Key)b.readObject( );
byte[] rand=new byte[8];
Random r=new Random( );
r.nextBytes(rand);
IvParameterSpec iv=new IvParameterSpec(rand);
Cipher cp=Cipher.getInstance("DESede/CBC/PKCS5Padding");
cp.init(Cipher.ENCRYPT_MODE, k, iv);
byte ptext[]=c;
byte ctext[]=cp.doFinal(ptext);
for(int i=0;i< div="">
System.out.print(ctext[i] +",");
}
FileOutputStream f2=new FileOutputStream("SEncCBC.dat");
f2.write(rand);
f2.write(ctext);
Cipher cp1=Cipher.getInstance("DESede/CBC/PKCS5Padding");
cp1.init(Cipher.DECRYPT_MODE, k, iv);
byte[] jm=cp1.doFinal(ctext);
FileOutputStream fo=new FileOutputStream("2.txt");
fo.write(jm);
fo.close();
}
}
4 基于口令的加密解密
基于口令的加密和解密
import java.io.*;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class PBE{
public static void main(String args[]) throws Exception{
FileInputStream fi=new FileInputStream("1.rar");
int l=fi.available();
byte[] b=new byte[l];
fi.read(b);
//生成密钥
char[] passwd="123".toCharArray();
PBEKeySpec pbks=new PBEKeySpec(passwd);
SecretKeyFactory kf=
SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey k=kf.generateSecret(pbks);
//生成盐
byte[] salt=new byte[8];
Random r=new Random( );
r.nextBytes(salt);
//创建并初始化密码器
Cipher cp=Cipher.getInstance("PBEWithMD5AndDES");
PBEParameterSpec ps=new PBEParameterSpec(salt,1000);
cp.init(Cipher.ENCRYPT_MODE, k,ps);
//获取明文并加密
byte ctext[]=cp.doFinal(b);
//生成输出文件
//准备解密
Cipher cp1=Cipher.getInstance("PBEWithMD5AndDES");
cp1.init(Cipher.DECRYPT_MODE, k,ps);
byte ptext1[]=cp1.doFinal(ctext);
FileOutputStream f=new FileOutputStream("2.rar");
f.write(ptext1);
f.close();
}
}
5 针对流的加密和解密
针对流的加密和解密
针对输入流的加密和解密
//必须拥有的文件:key1.dat(DES密钥文件),需要加密的文件1.rar
import java.io.*;
import java.security.*;
import java.util.Scanner;
import javax.crypto.*;
public class StreamInCipher{
public static void main(String args[]) throws Exception{
Scanner reader=new Scanner(System.in);
System.out.println("please choose the type of opration:1.加密 2.解密");
int choose=reader.nextInt();
String fi="1.zip";
String fc="code.txt";
String fo="2.zip";
String f1=null;
String f2=null;
if(choose==1){
f1=fi;
f2=fc;
}
if(choose==2){
f1=fc;
f2=fo;
}
FileInputStream f=new FileInputStream("key1.dat");
ObjectInputStream ob=new ObjectInputStream(f);
Key k=(Key)ob.readObject( );
Cipher cp=Cipher.getInstance("DESede");
if(choose==1)
cp.init(Cipher.ENCRYPT_MODE, k);
else
cp.init(Cipher.DECRYPT_MODE, k);
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
CipherInputStream cin=new CipherInputStream(in, cp);
int b=0;
while( (b=cin.read())!=-1){
out.write(b);
System.out.println("ok!");
System.out.println(b);
}
cin.close();
out.close();
in.close();
}
}
针对输出流的加密和解密
import java.io.*;
import java.security.*;
import java.util.Scanner;
import javax.crypto.*;
public class StreamOutCipher{
public static void main(String args[]) throws Exception{
Scanner reader=new Scanner(System.in);
System.out.println("please choose the type of opration:1.加密 2.解密");
int choose=reader.nextInt();
String fi="1.zip";
String fc="code.txt";
String fo="2.zip";
String f1=null;
String f2=null;
if(choose==1){
f1=fi;
f2=fc;
}
if(choose==2){
f1=fc;
f2=fo;
}
FileInputStream f=new FileInputStream("key1.dat");
ObjectInputStream ob=new ObjectInputStream(f);
Key k=(Key)ob.readObject( );
Cipher cp=Cipher.getInstance("DESede");
if(choose==1)
cp.init(Cipher.ENCRYPT_MODE, k);
else
cp.init(Cipher.DECRYPT_MODE, k);
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
CipherOutputStream cout=new CipherOutputStream(out, cp);
int b=0;
while( (b=in.read())!=-1){
cout.write(b);
//System.out.println(b);
}
cout.close();
out.close();
in.close();
}
}
6 数字签名与数字签名验证
(对字符串或文件进行签名以及相应数字签名验证)
Sign.java
//对字符串或文件进行签名
package sign;
import java.io.*;
import java.security.*;
import java.security.interfaces.*;
public class Sign{
public static void main(String args[ ]) throws Exception{
//获取要签名的数据,放在data数组
FileInputStream f=new FileInputStream("1.txt");
int num=f.available();
byte[ ] data=new byte[num];
f.read(data);
//获取私钥
FileInputStream f2=new FileInputStream("RSA_priv.dat");
ObjectInputStream b=new ObjectInputStream(f2);
RSAPrivateKey prk=(RSAPrivateKey)b.readObject( );
//获取Signature对象
Signature s=Signature.getInstance("MD5WithRSA");
//初始化
s.initSign(prk);
//传入要签名的数据
s.update(data);
System.out.println("");
//签名
byte[ ] signeddata=s.sign( );
//保存签名
FileOutputStream f3=new FileOutputStream("Sign.dat");
f3.write(signeddata);
}
}
CheckSign.java
package sign;
import java.io.*;
import java.security.*;
import java.security.interfaces.*;
public class CheckSign{
// 从签名者那儿得到msg.dat和sign.dat和公钥RSA_pub.dat
// 修改msg.dat则数据无法通过验证,因此不怕网络传递过程中被修改,或signer不承认,因为只有signer才能针对msg.dat得到sign.dat,
// 如果checker将内容改为$300,则signer可要求其用签名验证,
// 1.验证完整性 checker担心是否网络传递时将内容修改过了,或者是否确实是signer发来的,不是别人乱传的,经检查签名,正确,于是放心,
// 2. 不可否认性。 signer不承认这个文件是自己发的,或说checker改过内容了,checker展示其签名sign.dat,只有signer有私钥,能根据msg.dat生成这样的内容,别人都不能。
public static void main(String args[ ]) throws Exception{
//获取数据,放在data数组
FileInputStream f=new FileInputStream("1.txt");
int num=f.available();
byte[ ] data=new byte[num];
f.read(data);
//读签名
FileInputStream f2=new FileInputStream("Sign.dat");
int num2=f2.available();
byte[ ] signeddata=new byte[num2];
f2.read(signeddata);
//读公钥
FileInputStream f3=new FileInputStream("RSA_pub.dat");
ObjectInputStream b=new ObjectInputStream(f3);
RSAPublicKey pbk=(RSAPublicKey)b.readObject( );
//获取对象
Signature s=Signature.getInstance("MD5WithRSA");
//初始化
s.initVerify(pbk);
//传入原始数据
s.update(data);
boolean ok=false;
try{
//用签名验证原始数据
ok= s.verify(signeddata);
System.out.println(ok);
}
catch(SignatureException e){ System.out.println(e);}
System.out.println("Check Over");
}
}