其实文件的加密解密我们可以理解成在复制文件时对文件中的每一个字节做一些操作,比如最简单的就是加上一个常数或一个随机数,还有取模等,只要把它变成不是原本的模样就OK了。
以下给出生成随机数的方式加密:MyKey是一个生成128个0~128之间的随机数,然后我把这些随机数存到一个文件里,这个文件叫密钥文件。加密与解密需要的密钥就到这个文件中读取。
//生成密钥文件
public class MyKey {
public static void main(String[] args){
try{
File f=new File("c:/work/key.key");//保存生成密钥的路径
FileOutputStream fos=new FileOutputStream(f);
for(int i=0;i<128;i++)
//写入生成的随机数
fos.write((int)(Math.random()*128));
}catch (Exception e){}
}
}
//加密
public class MyEncrypt{
public static void main(String[] args) {
try {
// 读密钥文件
int[] key = new int[128];
File keyFile = new File("c:/work/key.key");
FileInputStream keyFis = new FileInputStream(keyFile);
for (int i = 0; i < 128; i++) {
key[i] = keyFis.read();
}
// 加密
File inFile = new File("c:/work/test.txt");
File outFile = new File("c:/work/test1.txt");
FileInputStream fis = new FileInputStream(inFile);
FileOutputStream fos = new FileOutputStream(outFile);
int length = fis.available();
for (int i = 0; i < length; i++)
fos.write(fis.read() + key[i % 128]);
} catch (Exception e) {
}
}
}
//解密
public class MyDecrypt{
public static void main(String[] args){
try{
//读密钥文件
int [] key=new int[128];
File keyFile=new File("c:/work/key.key");
FileInputStream keyFis=new FileInputStream(keyFile);
for(int i=0;i<128;i++){
key[i]=keyFis.read();
}
//解密
File f=new File("c:/work/test1.txt");
FileInputStream fis=new FileInputStream(f);
int length=fis.available();
for(int i=0;i
这样文件的加密规律行太强了,所以安全性自然也不高。
下面介绍一种加密算法:RSA加密算法,是一种非对称加密算法。(过程如图,来自百度)
RSA公开密钥密码体制是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。(虽然解密密钥是由公开的加密密钥决定的,但由于大数的因子分解问题:【当p和q是一个大素数的时候,从它们的积pq去分解因子p和q,这是一个公认的数学难题。】还未得到解决,所以还不能根据加密密钥计算出解密密钥。)
密钥生成的步骤如下:
1.随机选择两个不相等的质数p和q;(p与q越大越安全)
2.计算n=p*q(将n转换为二进制后,二进制的长度就是密钥的长度,实际应用中一般选择1024位、2048位);
3.计算n的欧拉函数φ(n):其实就是φ(n)=(p-1)(q-1),同时对p, q严加保密,不让任何人知道。
4.随机选择一个整数e,其中φ(n)>e>1,且e与φ(n)互质;
5.计算d,使得de≡1 mod φ(n):
≡是同余符号。公式中,≡符号的左边必须和符号右边同余,也就是两边模运算结果相同。显而易见,不管φ(n)取什么值,符号右边1 modφ(n)的结果都等于1;符号的左边d与e的乘积做模运算后的结果也必须等于1。这就需要计算出d的值,让这个同余等式能够成立。
6.将n和e封装成公钥,n和d封装成私钥:公钥KU=(e,n),私钥KR=(d,n)。
7.加密:假设发送方向接收方发送信息m,m称为明文。发送方从接收方获得的公钥为(n,e),加密公式为
me=c(mod n)
m,e,n已知,从上面的公式中计算出c,c就是加密后的信息,称为密文。发送方将密文发送给接收方。
8.解密:加密的逆过程 由cd=m(mod n) 算出m,就是发送方发过来的明文。
下面是一个Demo:
/**
*
* @Description Demo说明:
* 1、按照加密解密和签名验签的逻辑,编写简单的demo,不涉及java中继承的RSA相关类和Sigesture签名类
* 2、只能对数字和字母进行加密, 不涉及编码和解码问题 。 3、不做数字签名和验证了,涉及到提取信息摘要。
*/
public class EnAndDe {
private long p = 0;
private long q = 0;
private long n = 0;
private long t = 0; // 欧拉函数
private long e = 0; // 公匙
private long d = 0; // 密匙
private String mc; // 明文
private long c = 0; // 密文
private long word = 0; // 解密后明文
// 判断是一个数 x 否为素数素数就是判断在 (2,√x)范围内有没有除1外的因数,如果没有则x数素数
public boolean isPrime(long t) {
long k = 0;
k = (long) Math.sqrt((double) t);
for (int i = 2; i <= k; i++) {
if ((t % i) == 0) {
return false;
}
}
return true;
}
// 随机产生大素数(1e6数量级,注意,太大了要超出范围)
public void bigprimeRandom() {
do {
p = (long) (Math.random() * 1000000);
} while (!this.isPrime(p));
do {
q = (long) (Math.random() * 1000000);
} while (p == q || !this.isPrime(q));
}
// 输入PQ
public void inputPQ() throws Exception {
this.bigprimeRandom();
System.out.println("自动生成两个大素数p,q分别为:" + this.p + " " + this.q);
this.n = (long) p * q;
this.t = (long) (p - 1) * (q - 1);
System.out.println("这两个素数的乘积为p*q:" + this.n);
System.out.println("所得的t=(p-1)(q-1):" + this.t);
}
// 求最大公约数
public long gcd(long a, long b) {
long gcd;
if (b == 0)
gcd = a;
else
gcd = gcd(b, a % b);
return gcd;
}
// 生成公匙
public void getPublic_key() throws Exception {
do {
this.e = (long) (Math.random() * 100000);
// e满足 e∈(1, ψ(n))且e与ψ(n)最大公约数为1,即 e与t互质
} while ((this.e >= this.t) || (this.gcd(this.t, this.e) != 1));
System.out.println("生成的公钥为:" + "(" + this.n + "," + this.e + ")");
}
// 生成私钥 e*d=1(mod ψ(n))==> d = (k ψ(n)+1) / e
public void getPrivate_key() {
long value = 1; // value 是e和d的乘积
outer: for (long k = 1;; k++) {
value = k * this.t + 1;
if ((value % this.e == 0)) {
this.d = value / this.e;
break outer;
}
}
System.out.println("产生的一个私钥为:" + "(" + this.n + "," + this.d + ")");
}
// 输入明文
public void getText() throws Exception {
System.out.println("请输入明文:");
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
mc = stdin.readLine();
}
// 解密密文
public void pascolum() throws Exception {
this.getText();
System.out.println("输入明文为: " + this.mc);
// 加密
ArrayList cestr = new ArrayList();
for (int i = 0; i < mc.length(); i++) {
this.c = this.colum((long) mc.charAt(i), this.n, this.e);
cestr.add(c);
}
System.out.println("加密后所得的密文为:" + cestr);
// 解密
StringBuffer destr = new StringBuffer();
for (int j = 0; j < cestr.size(); j++) {
this.word = this.colum(Long.parseLong(cestr.get(j).toString()), this.n, this.d);
destr.append((char) word);
}
System.out.println("解密后所得的明文为:" + destr);
}
// 加密、解密计算
public long colum(long mc, long n, long key) {
BigInteger bigy = new BigInteger(String.valueOf(mc));
BigInteger bign = new BigInteger(String.valueOf(n));
BigInteger bigkey = new BigInteger(String.valueOf(key));
return Long.parseLong(bigy.modPow(bigkey, bign).toString());
}
public static void main(String[] args) {
try {
EnAndDe t = new EnAndDe();
t.inputPQ();
t.getPublic_key();
t.getPrivate_key();
t.pascolum();
} catch (Exception e) {
e.printStackTrace();
}
}
}
其实RSA加密应用还是比较广泛,比如qq登录的密码和银行卡密码等,其实我们输入的密码并不是被原文保存,也是被加密后而保存在某一个文件中的。验证过程也是输入后进行加密去匹配加密后的内容,而不是直接匹配输入的原文。
我们经常浏览网页,那么怎么才能保证我们现在访问的这个网页就是我的CSDN网页,我们逛的淘宝是真的www.taobao.com呢? RSA也应用在https认证上。https认证原理是这样的:
除此之外,还有MD5等很多加密算法,MD5原理是通过Hash算法产生散列值的。