1 sha加密:
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。该算法经过加密专家多年来的发展和改进已日益完善,并被广泛使用。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种“指纹”或是“摘要”所以对散列值的数字签名就可以视为对此明文的数字签名。
散列算法
原理
SHA-1与MD5的比较
JAVA 已经实现了 SHA-256 和 SHA-512 两种 Hash 算法
利用 java.security.MessageDigest 调用已经集成的 Hash 算法
创建 Encrypt 对象,并调用 SHA256 或者 SHA512 并传入要加密的文本信息,分别得到 SHA-256 或 SHA-512 两种被加密的 hash 串。
若要改为 MD5 算法,修改传入参数 strType 为 "MD5" 即可得到 MD5 加密功能。
/**
* @file Encrypt.java
* @date 2016年8月5日
* @version 3.4.1
*
* Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved.
*/
package encrypt;
/**
*
*
* @author chengjian.he
* @version 3.4, 2016年8月5日 上午10:05:37
* @since
*/
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Encrypt
{
/**
* 传入文本内容,返回 SHA-256 串
*
* @param strText
* @return
*/
public String SHA256(final String strText)
{
return SHA(strText, "SHA-256");
}
/**
* 传入文本内容,返回 SHA-512 串
*
* @param strText
* @return
*/
public String SHA512(final String strText)
{
return SHA(strText, "SHA-512");
}
/**
* 字符串 SHA 加密
*
* @param strSourceText
* @return
*/
private String SHA(final String strText, final String strType)
{
// 返回值
String strResult = null;
// 是否是有效字符串
if (strText != null && strText.length() > 0)
{
try
{
// SHA 加密开始
// 创建加密对象 并傳入加密類型
MessageDigest messageDigest = MessageDigest.getInstance(strType);
// 传入要加密的字符串
messageDigest.update(strText.getBytes());
// 得到 byte 類型结果
byte byteBuffer[] = messageDigest.digest();
// 將 byte 轉換爲 string
StringBuffer strHexString = new StringBuffer();
// 遍歷 byte buffer
for (int i = 0; i < byteBuffer.length; i++)
{
String hex = Integer.toHexString(0xff & byteBuffer[i]);
if (hex.length() == 1)
{
strHexString.append('0');
}
strHexString.append(hex);
}
// 得到返回結果
strResult = strHexString.toString();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
}
return strResult;
}
public static void main(String args[]){
Encrypt ey = new Encrypt();
System.out.println(ey.SHA("ILoveYou", "MD5"));//62accaf23ac9a73c0b28765b7dfaf75a
}
}
2 Base64
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
/**
* @file Base64.java
* @date 2016年8月5日
* @version 3.4.1
*
* Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved.
*/
package encrypt;
import java.io.UnsupportedEncodingException;
import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;
/**
*
*
* @author chengjian.he
* @version 3.4, 2016年8月5日 上午10:32:23
* @since Yeexun 3.4
*/
public class Base64 {
// 加密
public String getBase64(String str) {
byte[] b = null;
String s = null;
try {
b = str.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (b != null) {
s = new BASE64Encoder().encode(b);
}
return s;
}
// 解密
public String getFromBase64(String s) {
byte[] b = null;
String result = null;
if (s != null) {
BASE64Decoder decoder = new BASE64Decoder();
try {
b = decoder.decodeBuffer(s);
result = new String(b, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
public static void main(String args[]){
Base64 b6 = new Base64();
System.out.println(b6.getBase64("ILoveYou"));
System.out.println(b6.getFromBase64(b6.getBase64("ILoveYou")));
}
}
SUxvdmVZb3U=ILoveYou
3 Base64Encoder
一直以来Base64的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder的sun.misc.BASE64Encoder/BASE64Decoder类。这人个类是sun公司的内部方法,并没有在java api中公开过,不属于JDK标准库范畴,但在JDK中包含了该类,可以直接使用。
/**
* @file Base64Encoder.java
* @date 2016年8月5日
* @version 3.4.1
*
* Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved.
*/
package encrypt;
/**
*
*
* @author chengjian.he
* @version 3.4, 2016年8月5日 上午10:44:22
* @since Yeexun 3.4
*/
public class Base64Encoder {
public static String getBASE64(String s) {
if (s == null)
return null;
return (new sun.misc.BASE64Encoder()).encode(s.getBytes());
}
// 将 BASE64 编码的字符串 s 进行解码 解密
public static String getFromBASE64(String s) {
if (s == null)
return null;
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
try {
byte[] b = decoder.decodeBuffer(s);
return new String(b);
} catch (Exception e) {
return null;
}
}
public static String mTOa(Object ming){
return Base64Encoder.getBASE64(Base64Encoder.getBASE64(Base64Encoder.getBASE64((String)ming)));
}
public static String aTOm(String an){
return Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(an)));
}
public static void main(String[] args) {
String a = mTOa("100000.89".toString());
System.out.println(a);//加密
System.out.println(aTOm(a));//解密
}
}
4 RSA
/**
* @file RSATool.java
* @date 2016年8月5日
* @version 3.4.1
*
* Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved.
*/
package encrypt;
/**
*
*
* @author chengjian.he
* @version 3.4, 2016年8月5日 上午10:51:35
* @since Yeexun 3.4
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
public class RSATool {
public static void makekeyfile(String pubkeyfile, String privatekeyfile)
throws NoSuchAlgorithmException, FileNotFoundException, IOException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为1024位
keyPairGen.initialize(1024);
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 生成私钥
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
privatekeyfile));
oos.writeObject(privateKey);
oos.flush();
oos.close();
oos = new ObjectOutputStream(new FileOutputStream(pubkeyfile));
oos.writeObject(publicKey);
oos.flush();
oos.close();
System.out.println("make file ok!");
}
/**
*
* @param k
* @param data
* @param encrypt
* 1 加密 0解密
* @return
* @throws NoSuchPaddingException
* @throws Exception
*/
public static byte[] handleData(Key k, byte[] data, int encrypt)
throws Exception {
if (k != null) {
Cipher cipher = Cipher.getInstance("RSA");
if (encrypt == 1) {
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] resultBytes = cipher.doFinal(data);
return resultBytes;
} else if (encrypt == 0) {
cipher.init(Cipher.DECRYPT_MODE, k);
byte[] resultBytes = cipher.doFinal(data);
return resultBytes;
} else {
System.out.println("参数必须为: 1 加密 0解密");
}
}
return null;
}
public static void main(String[] args) throws Exception {
String pubfile = "d:/temp/pub.key";
String prifile = "d:/temp/pri.key";
makekeyfile(pubfile, prifile);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(pubfile));
RSAPublicKey pubkey = (RSAPublicKey) ois.readObject();
ois.close();
ois = new ObjectInputStream(new FileInputStream(prifile));
RSAPrivateKey prikey = (RSAPrivateKey) ois.readObject();
ois.close();
// 使用公钥加密
String msg = "~O(∩_∩)O哈哈~";
String enc = "UTF-8";
// 使用公钥加密私钥解密
System.out.println("原文: " + msg);
byte[] result = handleData(pubkey, msg.getBytes(enc), 1);
System.out.println("加密: " + new String(result, enc));
byte[] deresult = handleData(prikey, result, 0);
System.out.println("解密: " + new String(deresult, enc));
msg = "嚯嚯";
// 使用私钥加密公钥解密
System.out.println("原文: " + msg);
byte[] result2 = handleData(prikey, msg.getBytes(enc), 1);
System.out.println("加密: " + new String(result2, enc));
byte[] deresult2 = handleData(pubkey, result2, 0);
System.out.println("解密: " + new String(deresult2, enc));
}
}
make file ok!原文: ~O(∩_∩)O哈哈~加密: �A N�ډB�����ym��r�C��ʇ�������U
5 AES对称加密
加密技术可以分为对称与非对称两种.
对称加密,解密,即加密与解密用的是同一把秘钥,常用的对称加密技术有DES,AES等
而非对称技术,加密与解密用的是不同的秘钥,常用的非对称加密技术有RSA等
为什么要有非对称加密,解密技术呢
假设这样一种场景A要发送一段消息给B,但是又不想以明文发送,所以就需要对消息进行加密.如果采用对称加密技术,那么加密与解密用的是同一把秘钥.除非B事先就知道A的秘钥,并且保存好.这样才可以解密A发来的消息.
由于对称技术只有一把秘钥,所以秘钥的管理是一个很麻烦的问题.而非对称技术的诞生就解决了这个问题.非对称加密与解密使用的是不同的秘钥,并且秘钥对是一一对应的,即用A的私钥加密的密文只有用A的公钥才能解密.
这样的话,每个人都有两把秘钥,私钥和公钥,私钥是只有自己才知道的,不能告诉别人,而公钥是公开的,大家都可以知道.这样,当A想要发送消息给B的时候,只需要用B的公钥对消息进行加密就可以了,由于B的私钥只有B才拥有,所以A用B的公钥加密的消息只有B才能解开.而B想更换自己的秘要时也很方便,只须把公钥告诉大家就可以了.
那么,既然非对称加密如此之好,对称加密就没有存在的必要了啊,其实不然,由于非对称加密算法的开销很大,所以如果直接以非对称技术来加密发送的消息效率会很差.那么怎么办呢?解决的办法也很简单,就是把对称加密技术与非对称加密技术结合起来使用.
还是这个例子:A要发送一个消息给B.
一,A先生成一个对称秘钥,这个秘钥可以是随机生成的,
二,A用B的公钥加密第一步生成的这个对称秘钥
三,A把加密过的对称秘钥发给B
四,A用第一步生成的这个对称秘钥加密实际要发的消息
五,A把用对称秘钥加密的消息发给B
对于B
他先收到A发来的对称秘钥,这个秘钥是用B的公钥加密过的,所以B需要用自己的私钥来解密这个秘钥
然后B又收到A发来的密文,这时候用刚才解密出来的秘钥来解密密文
这样子的整个过程既保证了安全,又保证了效率.
接下来是Java实现:
我这个Java实现使用的是AES的对称加密和RSA的非对称加密(DES的对称加密实现方法和AES的是一样的,但是由于DES算法本身有缺陷,容易被破解,所以现在多用其升级版AES对称加密)
/**
* @file AES.java
* @date 2016年8月5日
* @version 3.4.1
*
* Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved.
*/
package encrypt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
*
*
* @author chengjian.he
* @version 3.4, 2016年8月5日 上午11:35:13
* @since Yeexun 3.4
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
public class AES {
private Key key;
/**
* 生成AES对称秘钥
* @throws NoSuchAlgorithmException
*/
public void generateKey() throws NoSuchAlgorithmException {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
keygen.init(random);
this.key = keygen.generateKey();
}
/**
* 加密
* @param in
* @param out
* @throws InvalidKeyException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws IOException
*/
public void encrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
this.crypt(in, out, Cipher.ENCRYPT_MODE);
}
/**
* 解密
* @param in
* @param out
* @throws InvalidKeyException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws IOException
*/
public void decrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
this.crypt(in, out, Cipher.DECRYPT_MODE);
}
/**
* 实际的加密解密过程
* @param in
* @param out
* @param mode
* @throws IOException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
*/
public void crypt(InputStream in, OutputStream out, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(mode, this.key);
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;
boolean more = true;
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else {
more = false;
}
}
if (inLength > 0)
outBytes = cipher.doFinal(inBytes, 0, inLength);
else
outBytes = cipher.doFinal();
out.write(outBytes);
out.flush();
}
public void setKey(Key key) {
this.key = key;
}
public Key getKey() {
return key;
}
public static void main(String[] args) throws Exception {
AES aes = new AES();
aes.generateKey();
File file = new File("D:/aa.jpg");
FileInputStream in = new FileInputStream(file);
File file1 = new File("D:/temp/pub.key");
FileOutputStream out = new FileOutputStream(file1);
aes.encrypt(in, out);
aes.decrypt(in, out);
}
}