[TOC]
## 1. 加密技術
### 1.1 對稱加密
> * 加密和解密都是使用同一把秘鑰,這種方法稱之為對稱加密,也成為單秘鑰加密
> * 常見的對稱加密算法有:
> AES、DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK 等
DES
> 全稱為Data Encryption Standard,即數據加密標準,是一種使用密鑰加密的塊算法,1976 年被美國聯邦政府的國家標準局確定為聯邦資料處理標準(FIPS),隨后在國際上廣泛流傳開來。
3DES
> 也叫Triple DES,是三重數據加密算法(TDEA,Triple Data Encryption Algorithm)塊密碼的通稱。
> 它相當于是對每個數據塊應用三次DES 加密算法。由于計算機運算能力的增強,原版DES 密碼的密鑰長度變得容易被暴力破解;3DES 即是設計用來提供一種相對簡單的方法,即通過增加DES 的密鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼算法。
AES
> 高級加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael 加密法,是美國聯邦政府采用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高級加密標準由美國國家標準與技術研究院(NIST)于2001 年11 月26 日發布于FIPS PUB 197,并在2002 年5 月26 日成為有效的標準。2006 年,高級加密標準已然成為對稱密鑰加密中最流行的算法之一。
#### 1.1.1 DES
DES 加密原理(對比特位進行操作,交換位置,異或等等,無需詳細了解)
> 1. Bit是計算機傳輸的最小單位,以0或1表示(二進制),例如3的二進制為00000011
> 2. Byte與Bit的區別
> 數據存儲以‘字節’為單位,數據傳輸大多是以‘位’(bit,又名‘比特’)為單位,每8 個位(bit,簡寫為b)組成一個字節(Byte,簡寫為B),是最小一級的信息單位(完成的信息)。
>
Byte的取值范圍是-128到127,第一個高位是符號位1表示負數

即10000000 到01111111 之間, 轉換成十進制就是-128到127
#### 1.1.2 對稱加密的具體應用方式
1. 生成秘鑰并保存到硬盤上,以后讀取該秘鑰進行加密解密操作,實際開發中用得比較少
~~~
//生成隨機秘鑰
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
//序列化秘鑰到磁盤上
FileOutputStream fos = new FileOutputStream(new File("heima.key"));
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(secretKey);
//從磁盤里讀取秘鑰
FileInputStream fis = new FileInputStream(new File("heima.key"));
ObjectInputStream ois = new ObjectInputStream(fis);
Key key = (Key) ois.readObject();
~~~
2、使用自定義秘鑰(秘鑰寫在代碼里)
~~~
//創建密鑰寫法1
KeySpec keySpec = new DESKeySpec(key.getBytes());
SecretKey secretKey = SecretKeyFactory.getInstance(ALGORITHM).
generateSecret(keySpec);
//創建密鑰寫法2
//SecretKey secretKey = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
//得到key 后,后續代碼就是Cipher 的寫法,此處省略...
~~~
注意事項
把秘鑰寫在代碼里有一定風險,當別人反編譯代碼的時候,可能會看到秘鑰,android 開發里建議用JNI 把秘鑰值寫到C 代碼里,甚至拆分成幾份,最后再組合成真正的秘鑰
### 1.2 非對稱加密
與對稱加密算法不同,非對稱加密算法需要兩個密鑰:公鑰(publickey)和私鑰(privatekey)。公鑰與私鑰是一對,如果用公鑰對數據進行加密,只有用對應的私鑰才能解密;如果用私鑰對數據進行加密,那么只有用對應的公鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
RSA、Elgamal、背包算法、Rabin、D-H、ECC(橢圓曲線加密算法)等,其中支付寶使用的就是RSA算法

## 2. 生成pfx證書
打開Microsoft .NET Framework 的SDK命令提示,按以下步驟操作:
> (所有的工具可在C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\中找到)沒有就安裝,這里是我的百度網盤地址:
> 鏈接:http://pan.baidu.com/s/1qYPwmTY 密碼:ji03
1. 利用makecert.exe工具生成X.509證書(.cer包含公鑰)和一個.pvk私鑰文件
makecert.exe -r -n "CN=aixin" -e 12/31/2019 -sv aixin.pvk aixin.cer

-r: 自簽名
-n :"cn=MyCA": 證書的subject name,
-e :證書過期時間
-sv :生成.pvk文件
執行命令后會提示輸入私鑰密碼,要求密碼長度不能小于六

aixin.cer aixin.spc在當前目錄下生成
2. 利用X.509證書(.cer)創建發行者證書 (.spc),使用工具cert2spc.exe
cert2spc.exe aixin.cer aixin.spc

ramkykey. spc在當前目錄下生成
3. 導出pfx證書
執行:
pvkimprt.exe -pfx aixin.spc aixin.pvk
輸入私鑰密碼

ok,下一步

下一步,選擇導出私鑰

下一步,選擇個人信息交換

下一步,輸入證書保護密碼


完成
2. 驗證簽名
Isign(接口),簽名
~~~
package cn.com.bigssl.crypto;
import java.security.PrivateKey;
public interface ISign {
public String sign(String data, long timestamp, PrivateKey key) throws Exception;
public String sign(byte[] data, long timestamp, PrivateKey key) throws Exception;
public String sign(String data, PrivateKey key) throws Exception;
public String sign(byte[] data, PrivateKey key) throws Exception;
}
~~~
sign(實現類),簽名
~~~
package cn.com.bigssl.crypto;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import javax.crypto.Cipher;
import java.security.MessageDigest;
import java.security.PrivateKey;
public class Sign implements ISign {
public String sign(String data, long timestamp, PrivateKey key) throws Exception {
return sign(data.getBytes("utf-8"), timestamp, key);
}
public String sign(String data, PrivateKey key) throws Exception{
return sign(data.getBytes("utf-8"), 0, key);
}
public String sign(byte [] data, PrivateKey key) throws Exception {
return sign(data, 0, key);
}
public String sign(byte [] data, long timestamp, PrivateKey key) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256"); //1. 加密
md.update(data);
if(timestamp > 0){
md.update(EncodeUtil.toBE(timestamp));
}
byte[] hash = md.digest(); // 2. 獲得加密后的byte
Cipher cipher = Cipher.getInstance("RSA"); // 3. 獲得加解密類Cipher(RSA非對稱加密)
cipher.init(Cipher.ENCRYPT_MODE, key); // 4. 初始化Cipher為加密類(用私鑰加密)
byte[] encrypted = cipher.doFinal(hash); // 5. 獲得由Cipher加密后的byte[]
return HexBin.encode(encrypted); //6. 返回字符串
}
}
~~~
驗證簽名類(接口)
~~~
package cn.com.bigssl.crypto;
import java.security.cert.X509Certificate;
public interface IVerify {
public boolean verify(String data, long timestamp, String encodedEncryptedStr,
X509Certificate userCert) throws Exception ;
public boolean verify(String data, String encodedEncryptedStr,
X509Certificate userCert) throws Exception;
public boolean verify(byte[] data, String encodedEncryptedStr,
X509Certificate userCert) throws Exception;
public boolean verify(byte[] data, long timestamp, String encodedEncryptedStr,
X509Certificate userCert) throws Exception;
}
~~~
驗證簽名類(實現類)
~~~
package cn.com.bigssl.crypto;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import javax.crypto.Cipher;
import java.security.MessageDigest;
import java.security.cert.X509Certificate;
import java.util.Arrays;
public class Verify implements IVerify {
public boolean verify(String data, long timestamp, String encodedEncryptedStr,
X509Certificate userCert) throws Exception
{
return verify(data.getBytes("utf-8"), timestamp, encodedEncryptedStr, userCert);
}
public boolean verify(String data, String encodedEncryptedStr,
X509Certificate userCert) throws Exception
{
return verify(data.getBytes("utf-8"), 0, encodedEncryptedStr, userCert);
}
public boolean verify(byte [] data, String encodedEncryptedStr,
X509Certificate userCert) throws Exception{
return verify(data,0, encodedEncryptedStr, userCert);
}
public boolean verify(byte [] data, long timestamp, String encodedEncryptedStr,
X509Certificate userCert) throws Exception
{
MessageDigest md = MessageDigest.getInstance("SHA-256");// 1. SHA加密
md.update(data);
if(timestamp > 0){
md.update(EncodeUtil.toBE(timestamp));
}
byte[] hash = md.digest(); // 2. 獲取SHA加密后的Byte數組
byte[] encryptedStr = HexBin.decode(encodedEncryptedStr); // 3. HexBin把十六進制字符串解析成Byte數組
Cipher cipher = Cipher.getInstance("RSA"); // 4. 建立解密類Cipher(類型RSA非對稱加密)
cipher.init(Cipher.DECRYPT_MODE, userCert); // 5. 使用解密模式,解密要是為公鑰
byte[] plain = cipher.doFinal(encryptedStr); // 6. 獲得解密后的Byte數組
boolean ok = Arrays.equals(hash, plain); // 7. 比較data(SHA加密的)byte數組,與傳過來的用私鑰加密的數組是否一樣,判斷對方是否有我的證書
return ok;
}
}
~~~
簽名測試類(私鑰加密,公鑰解密)
~~~
package cn.com.bigssl.crypto;
import com.aexit.motordriver.commons.utils.URLParameter;
import org.apache.log4j.Logger;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
public class TestSignAndVerify {
private static Logger logger = Logger.getLogger(TestSignAndVerify.class);
public static void main(String[] args) throws Exception {
String password = "4rfv$RFV";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
//導入證書
try (InputStream input = new FileInputStream("C:\\Users\\Administrator\\Desktop\\aixin.pfx")) {
keyStore.load(input, password.toCharArray());//todo 這里加載較慢,建議加入單例
}
// * 每個證書都有自己的別名,秘鑰要通過【別名】+【私鑰密碼】獲得,公鑰通過【別名獲得】
Enumeration<String> aliases = keyStore.aliases();
if (!aliases.hasMoreElements()) {
throw new RuntimeException("no alias found");
}
String alias = aliases.nextElement();
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
String data = "{\"district\":\"220100\",\"licnum\":\"112233445566\",\"name\":\"愛信測試駕校\"}";
long timestamp = new Date().getTime();
ISign sign = new Sign();
String sign_hex = sign.sign(data, timestamp, privateKey);
logger.debug("數據簽名字符串:" + sign_hex);
IVerify verify = new Verify();
boolean ok = verify.verify("gdfwfhkwl", timestamp, sign_hex, cert);
logger.debug("數據簽名校驗成功:" + ok);
String url = URLParameter.getFromTimingUrlParameter(data,timestamp);
logger.debug("數據簽名URL:" + url);
}
}
~~~
- Docker
- 什么是docker
- Docker安裝、組件啟動
- docker網絡
- docker命令
- docker swarm
- dockerfile
- mesos
- 運維
- Linux
- Linux基礎
- Linux常用命令_1
- Linux常用命令_2
- ip命令
- 什么是Linux
- SELinux
- Linux GCC編譯警告:Clock skew detected. 錯誤解決辦法
- 文件描述符
- find
- 資源統計
- LVM
- Linux相關配置
- 服務自啟動
- 服務器安全
- 字符集
- shell腳本
- shell命令
- 實用腳本
- shell 數組
- 循環與判斷
- 系統級別進程開啟和停止
- 函數
- java調用shell腳本
- 發送郵件
- Linux網絡配置
- Ubuntu
- Ubuntu發送郵件
- 更換apt-get源
- centos
- 防火墻
- 虛擬機下配置網絡
- yum重新安裝
- 安裝mysql5.7
- 配置本地yum源
- 安裝telnet
- 忘記root密碼
- rsync+ crontab
- Zabbix
- Zabbix監控
- Zabbix安裝
- 自動報警
- 自動發現主機
- 監控MySQL
- 安裝PHP常見錯誤
- 基于nginx安裝zabbix
- 監控Tomcat
- 監控redis
- web監控
- 監控進程和端口號
- zabbix自定義監控
- 觸發器函數
- zabbix監控mysql主從同步狀態
- Jenkins
- 安裝Jenkins
- jenkins+svn+maven
- jenkins執行shell腳本
- 參數化構建
- maven區分環境打包
- jenkins使用注意事項
- nginx
- nginx認證功能
- ubuntu下編譯安裝Nginx
- 編譯安裝
- Nginx搭建本地yum源
- 文件共享
- Haproxy
- 初識Haproxy
- haproxy安裝
- haproxy配置
- virtualbox
- virtualbox 復制新的虛擬機
- ubuntu下vitrualbox安裝redhat
- centos配置雙網卡
- 配置存儲
- Windows
- Windows安裝curl
- VMware vSphere
- 磁盤管理
- 增加磁盤
- gitlab
- 安裝
- tomcat
- Squid
- bigdata
- FastDFS
- FastFDS基礎
- FastFDS安裝及簡單實用
- api介紹
- 數據存儲
- FastDFS防盜鏈
- python腳本
- ELK
- logstash
- 安裝使用
- kibana
- 安準配置
- elasticsearch
- elasticsearch基礎_1
- elasticsearch基礎_2
- 安裝
- 操作
- java api
- 中文分詞器
- term vector
- 并發控制
- 對text字段排序
- 倒排和正排索引
- 自定義分詞器
- 自定義dynamic策略
- 進階練習
- 共享鎖和排它鎖
- nested object
- 父子關系模型
- 高亮
- 搜索提示
- Redis
- redis部署
- redis基礎
- redis運維
- redis-cluster的使用
- redis哨兵
- redis腳本備份還原
- rabbitMQ
- rabbitMQ安裝使用
- rpc
- RocketMQ
- 架構概念
- 安裝
- 實例
- 好文引用
- 知乎
- ACK
- postgresql
- 存儲過程
- 編程語言
- 計算機網絡
- 基礎_01
- tcp/ip
- http轉https
- Let's Encrypt免費ssl證書(基于haproxy負載)
- what's the http?
- 網關
- 網絡IO
- http
- 無狀態網絡協議
- Python
- python基礎
- 基礎數據類型
- String
- List
- 遍歷
- Python基礎_01
- python基礎_02
- python基礎03
- python基礎_04
- python基礎_05
- 函數
- 網絡編程
- 系統編程
- 類
- Python正則表達式
- pymysql
- java調用python腳本
- python操作fastdfs
- 模塊導入和sys.path
- 編碼
- 安裝pip
- python進階
- python之setup.py構建工具
- 模塊動態導入
- 內置函數
- 內置變量
- path
- python模塊
- 內置模塊_01
- 內置模塊_02
- log模塊
- collections
- Twisted
- Twisted基礎
- 異步編程初探與reactor模式
- yield-inlineCallbacks
- 系統編程
- 爬蟲
- urllib
- xpath
- scrapy
- 爬蟲基礎
- 爬蟲種類
- 入門基礎
- Rules
- 反反爬蟲策略
- 模擬登陸
- problem
- 分布式爬蟲
- 快代理整站爬取
- 與es整合
- 爬取APP數據
- 爬蟲部署
- collection for ban of web
- crawlstyle
- API
- 多次請求
- 向調度器發送請求
- 源碼學習
- LinkExtractor源碼分析
- 構建工具-setup.py
- selenium
- 基礎01
- 與scrapy整合
- Django
- Django開發入門
- Django與MySQL
- java
- 設計模式
- 單例模式
- 工廠模式
- java基礎
- java位移
- java反射
- base64
- java內部類
- java高級
- 多線程
- springmvc-restful
- pfx數字證書
- 生成二維碼
- 項目中使用log4j
- 自定義注解
- java發送post請求
- Date時間操作
- spring
- 基礎
- spring事務控制
- springMVC
- 注解
- 參數綁定
- springmvc+spring+mybatis+dubbo
- MVC模型
- SpringBoot
- java配置入門
- SpringBoot基礎入門
- SpringBoot web
- 整合
- SpringBoot注解
- shiro權限控制
- CommandLineRunner
- mybatis
- 靜態資源
- SSM整合
- Aware
- Spring API使用
- Aware接口
- mybatis
- 入門
- mybatis屬性自動映射、掃描
- 問題
- @Param 注解在Mybatis中的使用 以及傳遞參數的三種方式
- mybatis-SQL
- 逆向生成dao、model層代碼
- 反向工程中Example的使用
- 自增id回顯
- SqlSessionDaoSupport
- invalid bound statement(not found)
- 脈絡
- beetl
- beetl是什么
- 與SpringBoot整合
- shiro
- 什么是shiro
- springboot+shrio+mybatis
- 攔截url
- 枚舉
- 圖片操作
- restful
- java項目中日志處理
- JSON
- 文件工具類
- KeyTool生成證書
- 兼容性問題
- 開發規范
- 工具類開發規范
- 壓縮圖片
- 異常處理
- web
- JavaScript
- 基礎語法
- 創建對象
- BOM
- window對象
- DOM
- 閉包
- form提交-文件上傳
- td中內容過長
- 問題1
- js高級
- js文件操作
- 函數_01
- session
- jQuery
- 函數01
- data()
- siblings
- index()與eq()
- select2
- 動態樣式
- bootstrap
- 表單驗證
- 表格
- MUI
- HTML
- iframe
- label標簽
- 規范編程
- layer
- sss
- 微信小程序
- 基礎知識
- 實踐
- 自定義組件
- 修改自定義組件的樣式
- 基礎概念
- appid
- 跳轉
- 小程序發送ajax
- 微信小程序上下拉刷新
- if
- 工具
- idea
- Git
- maven
- svn
- Netty
- 基礎概念
- Handler
- SimpleChannelInboundHandler 與 ChannelInboundHandler
- 網絡編程
- 網絡I/O
- database
- oracle
- 游標
- PLSQL Developer
- mysql
- MySQL基準測試
- mysql備份
- mysql主從不同步
- mysql安裝
- mysql函數大全
- SQL語句
- 修改配置
- 關鍵字
- 主從搭建
- centos下用rpm包安裝mysql
- 常用sql
- information_scheme數據庫
- 值得學的博客
- mysql學習
- 運維
- mysql權限
- 配置信息
- 好文mark
- jsp
- jsp EL表達式
- C
- test