因为加密算法用的比较多,这里就常用的加密算法(如AES、DES、MD5、SHA1、SHA256、SHA512、RSA等加密算法)基于基本用法结合实际应用做一个总结笔记。因为加密算法的具体方法与类都在jdk中有封装好,关于里面的详细逻辑会在后面的章节里写出来,这里仅以应用为主。
一、对称加密
双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密。
优点:速度快,对称性加密通常在消息发送方需要加密大量数据时使用,算法公开、计算量小、加密速度快、加密效率高。
缺点:在数据传送前,发送方和接收方必须商定好秘钥,然后 使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。
1.1、对称加密之AES
1.1.1、AES加密
//AES加密
public static byte[] encrypt(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES"); //(对称)密钥生成器
kgen.init(128, new SecureRandom(password.getBytes())); //显式地初始化 KeyGenerator(通过调用 init 方法)
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (Exception e) {
}
return null;
}
1.1.2、AES解密
//AES解密
public static byte[] decrypt(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(content);
return result; // 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
1.1.3、测试结果
1.1.4、应用
该AES适合加密字符串,当然也可以加密文件如音视频媒体文件、可执行文件等,但这种加密对于大的文件比较耗时,下面贴出自己平常使用中的AES加密算法,这个是另外一种AES加密,但这种对于加密字符串有缺点,
密钥必须是16位的
待加密内容的长度必须是16的倍数,如果不是16的倍数,就会出异常这里是代码:
//手机常用路径记录/sdcard/DCIM/Camera/VID_20140217_144346.mp4
// 原文件
private static final String filePath = "F:/惊鸿一面mv.mp4";
// 加密后的文件
private static final String outPath = "F:/惊鸿一面mvAES加密.mp4";
// 加密再解密后的文件
private static final String inPath = "F:/惊鸿一面mvAES解密.mp4";
//AES加密文件算法
private void encrypt() throws Exception{
FileInputStream fis = new FileInputStream(filePath);
FileOutputStream fos = new FileOutputStream(outPath);
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),// Length is 16 byte
"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sks);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
}
//AES解密文件算法
private void decrypt() throws Exception,{
FileInputStream fis = new FileInputStream(outPath);
FileOutputStream fos = new FileOutputStream(inPath);
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),
"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
1.2、对称加密之DES
1.2.1、DES加密
des对称加密算法现不推荐使用,因为des使用56位密钥,以现代计算能力,24小时内即可被破解,另外 密码key须是8的整数倍,下面还是将算法列举出来
//des加密算法
public static byte[] encrypt2(byte[] datasource, String password) {
try{
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes());
//创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
//Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
//现在,获取数据并加密
//正式执行加密操作
return cipher.doFinal(datasource);
}catch(Throwable e){
e.printStackTrace();
}
return null;
}
1.2.2,DES解密
//des解密算法
private static byte[] decrypt2(byte[] src, String password) throws Exception {
// DES算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec(password.getBytes());
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 将DESKeySpec对象转换成SecretKey对象
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
// 真正开始解密操作
return cipher.doFinal(src);
}
1.2.3、测试结果
1.3、对称加密之SHA
1.3.1、SHA加密
SHA系列的算法属于不可逆的单向哈希算法,主要应用还是验证如数字签名等。
/**
* SHA加密
*
* @param strSrc
* 明文
* @return 加密之后的密文
*/
public static String shaEncrypt(String strSrc) {
MessageDigest md = null;
String strDes = null;
byte[] bt = strSrc.getBytes();
try {
md = MessageDigest.getInstance("SHA-1");// 将此换成SHA-1、SHA-512、SHA-384等参数
md.update(bt);
strDes = bytes2Hex(md.digest()); // to HexString
} catch (NoSuchAlgorithmException e) {
return null;
}
return strDes;
}
/**
* byte数组转换为16进制字符串
*
* @param bts
* 数据源
* @return 16进制字符串
*/
public static String bytes2Hex(byte[] bts) {
String des = "";
String tmp = null;
for (int i = 0; i < bts.length; i++) {
tmp = (Integer.toHexString(bts[i] & 0xFF));
if (tmp.length() == 1) {
des += "0";
}
des += tmp;
}
return des;
}
1.3.2、测试结果
二、非对称加密
一对密钥由公钥和私钥组成(可以使用很多对密钥)。私钥解密公钥加密数据,公钥解密私钥加密数据(私钥公钥可以互相加密解密)。
私钥只能由一方保管,不能外泄。公钥可以交给任何请求方。
2.1、对称加密算法之MD5
2.1.1、MD5加解密
MD5属于hash算法,严格意义上并不算加密算法,但是这里还是列举一下其用法:
/***
* MD5加码 生成32位md5码
*/
public static String string2MD5(String inStr){
MessageDigest md5 = null;
try{
md5 = MessageDigest.getInstance("MD5");
}catch (Exception e){
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++){
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
/**
* 加密解密算法 执行一次加密,两次解密
*/
public static String convertMD5(String inStr){
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++){
a[i] = (char) (a[i] ^ 't');
}
String s = new String(a);
return s;
}
2.1.2、测试结果
2.2、对称加密算法之RSA
2.2.1、RSA加解密算法
这里只是简单地利用了公钥加密,私钥解密,较为全面的还有私钥加密,公钥解密,更为全面的请参考Central-Perk的博客
public static void generateKey() {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
PublicKey pbkey = kp.getPublic();
PrivateKey prkey = kp.getPrivate();
// 保存公钥
FileOutputStream f1 = new FileOutputStream("pubkey.dat");
ObjectOutputStream b1 = new ObjectOutputStream(f1);
b1.writeObject(pbkey);
// 保存私钥
FileOutputStream f2 = new FileOutputStream("privatekey.dat");
ObjectOutputStream b2 = new ObjectOutputStream(f2);
b2.writeObject(prkey);
} catch (Exception e) {
}
}
public static void encrypt() throws Exception {
String s = "helloworld";
// 获取公钥及参数e,n
FileInputStream f = new FileInputStream("pubkey.dat");
ObjectInputStream b = new ObjectInputStream(f);
RSAPublicKey pbk = (RSAPublicKey) b.readObject();
BigInteger e = pbk.getPublicExponent();
BigInteger n = pbk.getModulus();
System.out.println("e= " + e);
System.out.println("n= " + n);
// 获取明文m
byte ptext[] = s.getBytes("UTF-8");
BigInteger m = new BigInteger(ptext);
// 计算密文c
BigInteger c = m.modPow(e, n);
System.out.println("c= " + c);
// 保存密文
String cs = c.toString();
BufferedWriter out =
new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("encrypt.dat")));
out.write(cs, 0, cs.length());
out.close();
}
public static void decrypt() throws Exception {
// 读取密文
BufferedReader in =
new BufferedReader(
new InputStreamReader(new FileInputStream("encrypt.dat")));
String ctext = in.readLine();
BigInteger c = new BigInteger(ctext);
// 读取私钥
FileInputStream f = new FileInputStream("privatekey.dat");
ObjectInputStream b = new ObjectInputStream(f);
RSAPrivateKey prk = (RSAPrivateKey) b.readObject();
BigInteger d = prk.getPrivateExponent();
// 获取私钥参数及解密
BigInteger n = prk.getModulus();
System.out.println("d= " + d);
System.out.println("n= " + n);
BigInteger m = c.modPow(d, n);
// 显示解密结果
System.out.println("m= " + m);
byte[] mt = m.toByteArray();
String s = new String(mt,"UTF-8");
System.out.println("\n解密后的明文:" + s);
}
2.2.2、测试结果
参考博客:
三、视频快速加密
对于大文件加解密使用传统方式比较费时间,这种场景可使用
本地视频快速加密与解密工具类,附视频地址
public class JavaTest {
private final int REVERSE_LENGTH = 10;
/**
* 加解密
*
* @param strFile 源文件绝对路径
* @return
*/
private boolean encrypt(String strFile) {
int len = REVERSE_LENGTH;
try {
File f = new File(strFile);
RandomAccessFile raf = new RandomAccessFile(f, "rw");
long totalLen = raf.length();
if (totalLen < REVERSE_LENGTH)
len = (int) totalLen;
FileChannel channel = raf.getChannel();
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_WRITE, 0, REVERSE_LENGTH);
byte tmp;
for (int i = 0; i < len; ++i) {
byte rawByte = buffer.get(i);
tmp = (byte) (rawByte ^ i);
buffer.put(i, tmp);
}
buffer.force();
buffer.clear();
channel.close();
raf.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void main(String[] args) {
new JavaTest().encrypt("/Users/zhanglei/Desktop/惊鸿一面.mp4");
}
}