區塊鏈基礎:非對稱演算法
阿新 • • 發佈:2019-02-09
1.Hash演算法
package cn.hadron.security;
import java.security.MessageDigest;
import java.util.UUID;
import org.eclipse.jetty.util.security.Credential.MD5;
/**
* crypto['krɪptoʊ]祕密成員,
* 一些語言的crypto模組的目的是為了提供通用的加密和雜湊演算法
* 加密工具類
*/
public class CryptoUtil {
//工具類,隱藏構造器
private CryptoUtil () {}
/**
* 計算給定字串的SHA256值
*/
public static String sha256(String str) {
MessageDigest messageDigest;
String hash = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
hash = byte2Hex(messageDigest.digest());
} catch (Exception e) {
System.out.println("getSHA256 is error" + e.getMessage());
}
return hash;
}
/**
* 計算str的md5碼(技巧:去除前幾位,增強安全性)
*/
public static String md5(String str) {
String resultStr = MD5.digest(str);
return resultStr.substring(4, resultStr.length());
}
/**
* UUID的目的是讓分散式系統中的所有元素都能有唯一的辨識
* 獲取一個UUID值,預設格式帶有"-",需要刪除所有的"-"
*/
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("\\-", "");
}
/**
* 二進位制位元組資料轉換為十六進位制字串形式
* @param bytes
*/
private static String byte2Hex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
String tmp;
for (int i = 0; i < bytes.length; i++) {
/**
* 注意toHexString(int i)的引數型別是32位int型,而傳輸入8位byte型資料會轉換int型。
* 轉換後高24為也看作有效位,正數不影響,而負數會導致錯誤。
* java中採用的是補碼的形式表示負整數,比如byte的-1(0xff,11111111),會轉換成int型的-1(0xffffffff),
* 而oxff預設是int型,表示為0000 0000 0000 0000 0000 0000 1111 1111
* 一個byte跟0xff &運算,高的24個位元就總會被清0,得到我們想要的結果。
*/
tmp = Integer.toHexString(bytes[i] & 0xFF);
if (tmp.length() == 1) {
sb.append("0");
}
sb.append(tmp);
}
return sb.toString();
}
public static void main(String[] args){
String s="chengyuqiang";
System.out.println(CryptoUtil.md5(s));
System.out.println(CryptoUtil.sha256(s));
System.out.println(CryptoUtil.getUUID());
}
}
1163a12be8b90e692445a7115ca900f4
c7a8233d922f3db03f1c7a0864675cb5092ce850d033b7ea07ca5208da27edfe
b286928d476b4de0aa5b8c83b7b27e54
2、RSA非對稱演算法
package cn.hadron.security;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
/**
* RSA安全編碼元件
*/
public abstract class RsaUtil extends Coder {
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
/**
* 初始化金鑰
*/
public static Map<String, Object> initKey() throws Exception {
//RSA金鑰對生成器
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化
keyPairGen.initialize(1024);
//耗時操作,動態生成金鑰對
KeyPair keyPair = keyPairGen.generateKeyPair();
//獲取公鑰
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//獲取私鑰
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//儲存金鑰對
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 取得私鑰
*/
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return encryptBASE64(key.getEncoded());
}
/**
* 取得公鑰
*/
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return encryptBASE64(key.getEncoded());
}
/*******************公鑰加密,私鑰解密**************************/
/**
* 訊息傳送者用對方公鑰加密
*/
public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception {
// 對公鑰BASE64解密,取得公鑰
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decryptBASE64(key));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
// 對資料加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//將Cipher初始化為加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//資料將被加密或解密
return cipher.doFinal(data);
}
/**
* 訊息接收者用自己的私鑰解密
*/
public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {
// decryptBASE64(key)對金鑰解密,取得私鑰
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(decryptBASE64(key));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 對資料解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//將Cipher初始化為解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//資料將被加密或解密
return cipher.doFinal(data);
}
/*******************祕鑰加密,公鑰驗證***********************/
/**
* 訊息傳送者用自己的私鑰加密
*/
public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
// 對金鑰解密,取得私鑰
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(decryptBASE64(key));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 對資料加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//加密模式
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 用公鑰解密
*/
public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
//對金鑰解密, 取得公鑰
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decryptBASE64(key));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
// 對資料解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
//解密模式
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/****************數字簽名:私鑰加密,公鑰驗證**********************/
/**
* 用傳送者的私鑰對資訊生成數字簽名
* @param data : 加密資料
* @param privateKey: 私鑰
*/
public static String sign(byte[] data, String privateKey) throws Exception {
// 解密由base64編碼的私鑰,構造PKCS8EncodedKeySpec物件
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(decryptBASE64(privateKey));
//指定的加密演算法RSA
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//取私鑰匙物件
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
//Signature類用來提供數字簽名演算法功能
//可以將簽名演算法指定為 MD2withRSA、MD5withRSA 或 SHA1withRSA
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
//用私鑰初始化這個用於簽名的物件
signature.initSign(priKey);
//使用指定的byte陣列更新要簽名或驗證的資料
signature.update(data);
//sign()返回已更新資料的簽名位元組,再進行BASE64加密
return encryptBASE64(signature.sign());
}
/**
* 使用傳送者的公鑰校驗數字簽名
* 通過傳送者的公鑰publicKey驗證他簽名內容sign是否符合data資料
* @param data: 加密資料
* @param publicKey: 公鑰
* @param sign: 數字簽名
* @return 校驗成功返回true 失敗返回false
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
// 解密由base64編碼的公鑰,構造X509EncodedKeySpec物件
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decryptBASE64(publicKey));
// 指定加密演算法RSA
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取公鑰匙物件
PublicKey pubKey = keyFactory.generatePublic(keySpec);
//Signature類用來提供數字簽名演算法功能
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
//用公鑰初始化驗證物件
signature.initVerify(pubKey);
//使用指定的byte陣列更新要簽名或驗證的資料
signature.update(data);
// 驗證簽名是否正常
return signature.verify(decryptBASE64(sign));
}
public static void main(String[] args) throws Exception{
String s="chengyuqiang";
/**
* 測試公鑰加密,私有解密
*/
Map<String, Object> map=RsaUtil.initKey();
String publicKey=RsaUtil.getPublicKey(map);
String privateKey=RsaUtil.getPrivateKey(map);
System.out.println("公鑰:\n"+publicKey);
System.out.println("私鑰:\n"+privateKey);
//公鑰加密
byte[] msg=RsaUtil.encryptByPublicKey(s.getBytes(), publicKey);
//祕鑰解密
msg=RsaUtil.decryptByPrivateKey(msg, privateKey);
System.out.println("解密:\n"+new String(msg));
/**
* 測試私簽名,公鑰驗證簽名
*/
// 產生簽名
String sign = RsaUtil.sign(s.getBytes(), privateKey);
System.out.println("簽名內容:\n"+sign);
//驗證簽名
boolean status = RsaUtil.verify(s.getBytes(), publicKey, sign);
System.out.println("簽名正確:\n"+status);
}
}
公鑰:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2N1dAK2NzzcOjRwb3rBjT+NvpMKKgL98Pr3D0
jE99hfJL2MpuKflA0U18EKnZT1QjrninAeLHiR1BlnuJpHVGKNPkzXuIhggiHlvdb9WwsfB+u+pf
Igca7cURYR+4bELE+hlUVP8nyMuD9Vs8bY23oHG2Ff/svVQEo/j4uOMAywIDAQAB
私鑰:
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALY3V0ArY3PNw6NHBvesGNP42+kw
oqAv3w+vcPSMT32F8kvYym4p+UDRTXwQqdlPVCOueKcB4seJHUGWe4mkdUYo0+TNe4iGCCIeW91v
1bCx8H676l8iBxrtxRFhH7hsQsT6GVRU/yfIy4P1WzxtjbegcbYV/+y9VASj+Pi44wDLAgMBAAEC
gYBOOEFvHXEK1CiIXcQi67CYxfp5BtS42PPzQsfFYrn401gosP5s/f2ukmqluG2BCKnAy3OllYyp
RTXW4udTNdLVOiglX5TSCk1zp3Hn6oLbbjWIpoqAhx5PJslZY35MscNYVViz69FwLHjCeDWRitsV
f/eDHyC+r6vb3PQTgpjegQJBAOvtWqLhMNhAOel14pirf+A520xz/gzpSj/dCzTS53oLGvCJqzn1
HJqA4xmhEf8MMcHN4+SiVtjQdKVINaFbeUECQQDFuCBzCMLKHNfrUp35lOlnmAT5RBEU+0CV85jl
oERpLTU1v6igsP6mxXJXXRQpNzP2orN1IbrVVwF8uuUU/wsLAkBiDtH4Fs69YtxvG08mE0ngAUwT
l7ZE2YXBy3bH6szI3erBhQbE3QqZcO5zDY40SnY3zgJlWc/s559DvyKDQUjBAkEAqa7filnWcgZW
98orcWpu9Uzt186mqk8Gmqo4abklfO4jYEFfwqijoxSIkJl9F/IcUmpHgRq1cSn+SMFMoLxRCQJA
PJFE5keSZgjJpGsMAdEIpHKKUxF5vd+oS9+Z7EpSn7VGTRPLycSIDKQT2F9/QV1z5IKni1jqbnXs
imRw1coviw==
解密:
chengyuqiang
簽名內容:
BqJgQ4ciZNH0bE0TQeTgQQbF+h0jPNauHbgc95L8QggwD0p8qb4fdEjsmevdiN0OszOqyR9z71S9
LXCeH+ZeKVZagRWG0jx0Bfk74Rf5Pt2MMPqjzlDRfCTJyg0z8GjC/U70IaxgfgkrFVf3rsk4XzAB
R045Sjf2P+nJf/hf4wE=
簽名正確:
true
3、RsaUtil 的父類
package cn.hadron.security;
import java.security.MessageDigest;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* 基礎加密元件
*
*/
public abstract class Coder {
public static final String KEY_SHA = "SHA";
public static final String KEY_MD5 = "MD5";
//HMAC(Hash Message Authentication Code),雜湊訊息鑑別碼,基於金鑰的Hash演算法的認證協議
public static final String KEY_MAC = "HmacMD5";
//BASE64實現主要就是BASE64Encoder、BASE64Decoder兩個類,我們只需要知道使用對應的方法即可。
/**
* BASE64加密,把任意序列的8位位元組描述為一種不易被人直接識別的形式。
* BASE加密後產生的位元組位數是8的倍數,如果不夠位數以=符號填充
*/
public static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
/**
* BASE64解密
*/
public static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
/**
* JDK提供的MD5演算法實現
*/
public static byte[] encryptMD5(byte[] data) throws Exception {
MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
md5.update(data);
return md5.digest();
}
/**
* JDK提供的SHA演算法
*/
public static byte[] encryptSHA(byte[] data) throws Exception {
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
sha.update(data);
return sha.digest();
}
/**
* 初始化HMAC金鑰
*/
public static String initMacKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
SecretKey secretKey = keyGenerator.generateKey();
return encryptBASE64(secretKey.getEncoded());
}
/**
* HMAC加密
*/
public static byte[] encryptHMAC(byte[] data, String key) throws Exception {
SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return mac.doFinal(data);
}
}