加密與安全

目錄

一、URL編碼:

二、Base64編碼:

三、哈希算法:

四、Hmac算法:

五、對稱加密算法:


一、URL編碼:

URL編碼是瀏覽器發送數據給服務器時使用的編碼,它通常附加在URL的參數部分。之所以需要URL編碼,是因為出于兼容性考慮,很多服務器只識別ASCII字符。但如果URL中包含中文日文這些非ASCII字符怎么辦?不要緊,URL編碼有一套規則:

  • 如果字符是A~Za~z0~9以及-_.*,則保持不變;
  • 如果是其他字符,先轉換為UTF-8編碼,然后對每個字節以%XX表示。

例如:字符"中"UTF-8編碼是0xe4b8ad,因此,它的URL編碼是%E4%B8%ADURL編碼總是大寫。

Java標準庫提供了一個URLEncoder類來對任意字符串進行URL編碼:

import java.net.URLEncoder;
public class Main {public static void main(String[] args) {String encoded = URLEncoder.encode("中文!", "utf-8");System.out.println(encoded);}
}

URL編碼是編碼算法,不是加密算法。URL編碼的目的是把任意文本數據編碼為%前綴表示的文本,編碼后的文本僅包含A~Za~z0~9-_.*%,便于瀏覽器和服務器處理。

二、Base64編碼:

Base64編碼是對二進制數據進行編碼,表示成文本格式。Base64編碼可以把任意長度的二進制數據變為純文本,并且純文本內容中且只包含指定字符內容:A~Za~z0~9+/=。它的原理是把3字節的二進制數據按6bit一組,用4個整數表示,然后查表,把整數用索引對應到字符,得到編碼后的字符串。6位整數的范圍總是0~63,所以,能用64個字符表示:字符A~Z對應索引0~25,字符a~z對應索引26~51,字符0~9對應索引52~61,最后兩個索引6263分別用字符+/表示。

base64碼表:

碼值字符碼值字符碼值字符碼值字符
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

Java中,二進制數據就是byte[]數組。Java標準庫提供了Base64來對byte[]數組進行編解碼:

public class Main {public static void main(String[] args) {byte[] input = new byte[] { (byte) 0xe4, (byte) 0xb8, (byte) 0xad };String b64encoded = Base64.getEncoder().encodeToString(input);System.out.println(b64encoded);}
}

編碼后得到字符串結果:5Lit。要對這個字符使用Base64解碼,仍然用Base64這個類:

public class Main {public static void main(String[] args) {byte[] output = Base64.getDecoder().decode("5Lit");System.out.println(Arrays.toString(output)); // [-28, -72, -83]}
}

三、哈希算法:

哈希算法(Hash)又稱摘要算法(Digest),它的作用是:對任意一組輸入數據進行計算,得到一個固定長度的輸出摘要。哈希算法最重要的特點就是:

  • 相同的輸入一定得到相同的輸出;
  • 不同的輸入大概率得到不同的輸出。

所以,哈希算法的目的:為了驗證原始數據是否被篡改。Java字符串的hashCode()就是一個哈希算法,它的輸入是任意字符串,輸出是固定的4字節int整數:

"hello".hashCode(); // 0x5e918d2
"hello, java".hashCode(); // 0x7a9d88e8
"hello, bob".hashCode(); // 0xa0dbae2f

?1、哈希碰撞:兩個不同的輸入得到了相同的輸出。(不能避免,安全性低)

"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0

"通話".hashCode(); // 0x11ff03
"重地".hashCode(); // 0x11ff03

2、常用的哈希算法:

算法

輸出長度(位)

輸出長度(字節)

MD5

128 bits

16 bytes

SHA-1

160 bits

20 bytes

RipeMD-160

160 bits

20 bytes

SHA-256

256 bits

32 bytes

SHA-512

512 bits

64 bytes

1、MD5算法:

使用MessageDigest時,我們首先根據哈希算法獲取一個MessageDigest實例,然后,反復調用update(byte[])輸入數據。當輸入結束后,調用digest()方法獲得byte[]數組表示的摘要,最后,把它轉換為十六進制的字符串。

import java.security.MessageDigest;public class main {public static void main(String[] args)  {// 創建一個MessageDigest實例:MessageDigest md = MessageDigest.getInstance("MD5");// 反復調用update輸入數據:md.update("Hello".getBytes("UTF-8"));md.update("World".getBytes("UTF-8"));// 16 bytes: 68e109f0f40ca72a15e05cc22786f8e6byte[] results = md.digest(); StringBuilder sb = new StringBuilder();for(byte bite : results) {sb.append(String.format("%02x", bite));}System.out.println(sb.toString());}
}

2、哈希算法的用途:

(1)校驗下載文件

(2)存儲用戶密碼:(要避免彩虹表攻擊,對每個口令額外添加隨機數,這個方法稱之為加鹽saltdigest = md5(salt + inputPassword)

3、SHA-1算法:

SHA-1也是一種哈希算法,它的輸出是160 bits,即20字節。SHA-1是由美國國家安全局開發的,SHA算法實際上是一個系列,包括SHA-0(已廢棄)、SHA-1SHA-256SHA-512等。在Java中使用SHA-1,和MD5完全一樣,只需要把算法名稱改為"SHA-1":

import java.security.MessageDigest;public class main {public static void main(String[] args)  {// 創建一個MessageDigest實例:MessageDigest md = MessageDigest.getInstance("SHA-1");// 反復調用update輸入數據:md.update("Hello".getBytes("UTF-8"));md.update("World".getBytes("UTF-8"));// 20 bytes: db8ac1c259eb89d4a131b253bacfca5f319d54f2byte[] results = md.digest(); StringBuilder sb = new StringBuilder();for(byte bite : results) {sb.append(String.format("%02x", bite));}System.out.println(sb.toString());}
}

4、RipeMD160:

Java標準庫的java.security包提供了一種標準機制,允許第三方提供商無縫接入。我們要使用BouncyCastle提供的RipeMD160算法,需要先把BouncyCastle注冊一下

public class Main {public static void main(String[] args) throws Exception {// 注冊BouncyCastle提供的通知類對象BouncyCastleProviderSecurity.addProvider(new BouncyCastleProvider());// 獲取RipeMD160算法的"消息摘要對象"(加密對象)MessageDigest md = MessageDigest.getInstance("RipeMD160");// 更新原始數據md.update("HelloWorld".getBytes());// 獲取消息摘要(加密)byte[] result = md.digest();// 消息摘要的字節長度和內容System.out.println(result.length); // 160位=20字節System.out.println(Arrays.toString(result));// 16進制內容字符串String hex = new BigInteger(1,result).toString(16);System.out.println(hex.length()); // 20字節=40個字符System.out.println(hex);}
}

四、Hmac算法:

mac算法就是一種基于密鑰的消息認證碼算法,它的全稱是Hash-based Message Authentication Code,是一種更安全的消息摘要算法。Hmac算法總是和某種哈希算法配合起來用的。例如我們使用MD5算法,對應的就是Hmac MD5算法,它相當于“加鹽”的MD5HmacMD5 ≈md5(secure_random_key, input)

HmacMD5加密:

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;public class main {public static void main(String[] args) throws NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException, InvalidKeyException {// 獲取HmacMD5秘鑰生成器KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");// 產生秘鑰SecretKey secreKey = keyGen.generateKey();// 打印隨機生成的秘鑰:byte[] keyArray = secreKey.getEncoded();StringBuilder key = new StringBuilder();for(byte bite:keyArray) {key.append(String.format("%02x", bite));}System.out.println(key);// 使用HmacMD5加密Mac mac = Mac.getInstance("HmacMD5");mac.init(secreKey); // 初始化秘鑰mac.update("HelloWorld".getBytes("UTF-8"));byte[] resultArray = mac.doFinal();StringBuilder result = new StringBuilder();for(byte bite:resultArray) {result.append(String.format("%02x", bite));}System.out.println(result);}
}

解密:

// 原始密碼
String password = "nhmyzgq";// 通過"秘鑰的字節數組",恢復秘鑰
byte[] keyByteArray = {126, 49, 110, 126, -79, -5, 66, 34, -122, 123, 107, -63, 106, 100, -28, 67, 19, 23, 1, 23, 47, 63, 47, 109, 123, -111, -27, -121, 103, -11, 106, -26, 110, -27, 107, 40, 19, -8, 57, 20, -46, -98, -82, 102, -104, 96, 87, -16, 93, -107, 25, -56, -113, 12, -49, 96, 6, -78, -31, -17, 100, 19, -61, -58};// 恢復秘鑰
SecretKey key = new SecretKeySpec(keyByteArray,"HmacMD5");// 加密
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
mac.update(password.getBytes());
byte[] resultByteArray = mac.doFinal();StringBuilder resultStr = new StringBuilder();
for(byte b : resultByteArray) {resultStr.append(String.format("%02x", b));
}
System.out.println("加密結果:" + resultStr);

五、對稱加密算法:

對稱加密算法就是傳統的用一個秘鑰進行加密和解密。例如,我們常用的WinZIPWinRAR對壓縮包的加密和解密,就是使用對稱加密算法:

從程序的角度看,所謂加密,就是這樣一個函數,它接收密碼和明文,然后輸出密文:

secret = encrypt(key, message);

而解密則相反,它接收密碼和密文,然后輸出明文:

plain = decrypt(key, secret);

在軟件開發中,常用的對稱加密算法有:

算法

密鑰長度

工作模式

填充模式

DES

56/64

ECB/CBC/PCBC/CTR/...

NoPadding/PKCS5Padding/...

AES

128/192/256

ECB/CBC/PCBC/CTR/...

NoPadding/PKCS5Padding/PKCS7Padding/...

IDEA

128

ECB

PKCS5Padding/PKCS7Padding/...

?

密鑰長度直接決定加密強度,而工作模式和填充模式可以看成是對稱加密算法的參數和格式選擇。Java標準庫提供的算法實現并不包括所有的工作模式和所有填充模式。

1、使用AES加密:

(1)ECB模式:ECB模式是最簡單的AES加密模式,它需要一個固定長度的密鑰,固定的明文會生成固定的密文。

import java.security.*;
import java.util.Base64;import javax.crypto.*;
import javax.crypto.spec.*;public class Main {public static void main(String[] args) throws Exception {// 原文:String message = "Hello, world!";System.out.println("Message(原始信息): " + message);// 128位密鑰 = 16 bytes Key:byte[] key = "1234567890abcdef".getBytes();// 加密:byte[] data = message.getBytes();byte[] encrypted = encrypt(key, data);System.out.println("Encrypted(加密內容): " + Base64.getEncoder().encodeToString(encrypted));// 解密:byte[] decrypted = decrypt(key, encrypted);System.out.println("Decrypted(解密內容): " + new String(decrypted));}// 加密:public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {// 創建密碼對象,需要傳入算法/工作模式/填充模式Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// 根據key的字節內容,"恢復"秘鑰對象SecretKey keySpec = new SecretKeySpec(key, "AES");// 初始化秘鑰:設置加密模式ENCRYPT_MODEcipher.init(Cipher.ENCRYPT_MODE, keySpec);// 根據原始內容(字節),進行加密return cipher.doFinal(input);}// 解密:public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {// 創建密碼對象,需要傳入算法/工作模式/填充模式Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// 根據key的字節內容,"恢復"秘鑰對象SecretKey keySpec = new SecretKeySpec(key, "AES");// 初始化秘鑰:設置解密模式DECRYPT_MODEcipher.init(Cipher.DECRYPT_MODE, keySpec);// 根據原始內容(字節),進行解密return cipher.doFinal(input);}
}

Java標準庫提供的對稱加密接口非常簡單,使用時按以下步驟編寫代碼:

(1)根據算法名稱/工作模式/填充模式獲取Cipher實例;

(2)根據算法名稱初始化一個SecretKey實例,密鑰必須是指定長度;

(3)使用SerectKey初始化Cipher實例,并設置加密或解密模式;

(4)傳入明文或密文,獲得密文或明文。

2、CBC模式:ECB模式是最簡單的AES加密模式,這種一對一的加密方式會導致安全性降低。所以,更好的方式是通過CBC模式,它需要一個隨機數作為IV參數,這樣對于同一份明文,每次生成的密文都不同:

import java.security.*;
import java.util.Base64;import javax.crypto.*;
import javax.crypto.spec.*;public class Main {public static void main(String[] args) throws Exception {// 原文:String message = "Hello, world!";System.out.println("Message(原始信息): " + message);// 256位密鑰 = 32 bytes Key:byte[] key = "1234567890abcdef1234567890abcdef".getBytes();// 加密:byte[] data = message.getBytes();byte[] encrypted = encrypt(key, data);System.out.println("Encrypted(加密內容): " + Base64.getEncoder().encodeToString(encrypted));// 解密:byte[] decrypted = decrypt(key, encrypted);System.out.println("Decrypted(解密內容): " + new String(decrypted));}// 加密:public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {// 設置算法/工作模式CBC/填充Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// 恢復秘鑰對象SecretKeySpec keySpec = new SecretKeySpec(key, "AES");// CBC模式需要生成一個16 bytes的initialization vector:SecureRandom sr = SecureRandom.getInstanceStrong();byte[] iv = sr.generateSeed(16); // 生成16個字節的隨機數System.out.println(Arrays.toString(iv));IvParameterSpec ivps = new IvParameterSpec(iv); // 隨機數封裝成IvParameterSpec參數對象// 初始化秘鑰:操作模式、秘鑰、IV參數cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);// 加密byte[] data = cipher.doFinal(input);// IV不需要保密,把IV和密文一起返回:return join(iv, data);}// 解密:public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {// 把input分割成IV和密文:byte[] iv = new byte[16];byte[] data = new byte[input.length - 16];System.arraycopy(input, 0, iv, 0, 16); // IVSystem.arraycopy(input, 16, data, 0, data.length); //密文System.out.println(Arrays.toString(iv));// 解密:Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 密碼對象SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); // 恢復秘鑰IvParameterSpec ivps = new IvParameterSpec(iv); // 恢復IV// 初始化秘鑰:操作模式、秘鑰、IV參數cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);// 解密操作return cipher.doFinal(data);}// 合并數組public static byte[] join(byte[] bs1, byte[] bs2) {byte[] r = new byte[bs1.length + bs2.length];System.arraycopy(bs1, 0, r, 0, bs1.length);System.arraycopy(bs2, 0, r, bs1.length, bs2.length);return r;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917228.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917228.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917228.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

EasyExcel 公式計算大全

EasyExcel 是基于 Apache POI 的封裝,主要專注于簡化 Excel 的讀寫操作,對于公式計算的支持相對有限。以下是 EasyExcel 中處理公式計算的全面指南:1. 基本公式寫入1.1 寫入簡單公式Data public class FormulaData {ExcelProperty("數值…

2025年AI+數模競賽培訓意見征集-最后一輪

在過去幾天的“AI時代下2025年數模競賽培訓課程需求調研緊急征集”我們收到了大量老師、學生的反饋。我們通過大家的實際需求,編寫了下述2025年AI時代下最新的數學建模競賽教學課程課程表,具體授課內容以及相關課件、支撐材料都將會免費發布,…

Qwen2 RotaryEmbedding 位置編碼僅僅是第一層有嗎

Qwen2 RotaryEmbedding 位置編碼僅僅是第一層有嗎,還是全部層都有 Qwen2 模型中的 Rotary Embedding(旋轉位置編碼)是應用于所有 Transformer 層 的,而非僅第一層。 1. Transformer 架構的核心邏輯 Qwen2 基于 Decoder-only Transformer 架構,而位置編碼(如 Rotary Emb…

CNN卷積神經網絡之LeNet和AlexNet經典網絡模型(三)

CNN卷積神經網絡之LeNet和AlexNet經典網絡模型(三) 文章目錄CNN卷積神經網絡之LeNet和AlexNet經典網絡模型(三)深度學習兩大經典 CNN 模型速覽1. LeNet-5:CNN 的開山之作(1998)2. AlexNet&#…

江協科技STM32 12-2 BKP備份寄存器RTC實時時鐘

這一節我們要講的主要內容是RTC實時時鐘,實時時鐘本質上是一個定時器,但是這個定時器是專門用來產生年月日時分秒,這種日期和時間信息的。所以學會了STM32的RTC就可以在STM32內部擁有一個獨立運行的鐘表。想要記錄或讀取日期和時間&#xff0…

【10】大恒相機SDK C++開發 ——對相機采集的原圖像數據IFrameData裁剪ROI 實時顯示在pictureBox中,3種方法實現(效率不同)

文章目錄1 在回調函數中實現2 獨立封裝調用2.1 獲取圖像寬、高、pBuffer、channel2.2 內存圖像數據截取ROI并顯示2.3 回調函數調用3 for循環嵌套 方法24 for循環嵌套 方法35 按行復制數據提高效率,但很耗內存6 unsafe代碼 解釋及注意事項 看我另一篇文章7 ConvertTo…

ubuntu22.04系統入門 linux入門(二) 簡單命令 多實踐以及相關文件管理命令

以下有免費的4090云主機提供ubuntu22.04系統的其他入門實踐操作 地址:星宇科技 | GPU服務器 高性能云主機 云服務器-登錄 相關兌換碼星宇社區---4090算力卡免費體驗、共享開發社區-CSDN博客 之所以推薦給大家使用,是因為上面的云主機目前是免費使用的…

分布式ID方案(標記)

一、參考文章-標記 分布式ID方案有哪些?雪花算法如何搞定時鐘回撥和動態機器ID? 二、應用 1.百度 uid-generator github項目地址 原理參考 2.百度 uid-generator 擴展應用 燈官網 燈 項目代碼 lamp-util 單元模塊 lamp-util 單元模塊子模塊 lamp-…

std::map 加鎖

在并發環境下使用std::map,必須采取同步措施。 在并發環境下對 std::map 進行不加鎖的讀寫操作會導致嚴重的線程安全問題,主要會產生以下幾種問題: ?? 主要風險與后果數據競爭(Data Race) 當多個線程同時修改同一個鍵…

學習筆記090——Ubuntu 中 UFW 防火墻的使用

文章目錄1、允許特定的端口訪問2、允許特定 IP 訪問某個端口3、允許某個范圍的端口4、查看 UFW 狀態5、重新加載 UFW6、啟用 UFW7、關閉 UFW1、允許特定的端口訪問 # 允許 TCP 端口(例如 80): sudo ufw allow 80/tcp# 允許 UDP 端口&#xf…

移動端 WebView 內存泄漏與性能退化問題如何排查 實戰調試方法匯總

在混合 App 應用中,WebView 頁面常承載復雜業務邏輯與交互。隨著用戶使用時間增長,特別在切換多個頁面或反復打開界面后,常常會出現性能下降、頁面卡頓、甚至白屏崩潰等現象。這通常是因為頁面存在內存泄漏、事件監聽未解綁或垃圾回收阻塞導致…

JSON 對象在瀏覽器中順序與后端接口返回不一致的問題

一、問題描述 后端接口返回一個字典表的JSON對象,頁面展示排序與預期排序不一致。 在瀏覽器調試面板Response中看到接口原始響應字符串,是期望順序:在Preview中看到, key “22” 被提到最前,順序發生變化:頁…

Spring MVC數據傳遞全攻略

Spring MVC數據傳遞一、前端到后端的數據傳遞1. 使用 RequestParam 傳遞簡單參數2. 使用 PathVariable傳遞路徑參數3. 使用RequestBody傳遞 JSON 數據二、后端到前端的數據傳遞1. 使用Model或 ModelAndView傳遞數據到前端2. 使用HttpServletResponse直接寫回數據3.使用Response…

倉庫管理系統-12-前端之頭部區域Header基于嵌套路由訪問個人中心

文章目錄 1 個人中心 1.1 DateUtils.vue(子組件) 1.2 Home.vue(父組件) 1.3 router/index.js(嵌套路由) 1.4 index.vue(路由占位符) 2 Header.vue 2.1 頁面布局 2.2 toUser方法 2.3 初始加載 2.4 Header.vue 頭部區域Header中有一個個人中心下拉菜單,點擊個人中心選項,通過嵌…

【智能協同云圖庫】第七期:基于AI調用阿里云百煉大模型,實現AI圖片編輯功能

摘要:AI 高速發展賦能傳統業務,圖庫網站亦有諸多 AI 應用空間。以 AI 擴圖功?能為例,讓我們來學習如何在項目?中快速接入 AI 繪圖大模型。?用戶可以選擇一張已上傳的圖片,?通過 AI 擴圖得到新的圖片,希望可以幫到大…

Notepad++插件安裝

方式一:自動安裝(有些notepad并不好用,推薦方式二)工具欄-》插件-》插件管理如下點擊安裝后會提示,后端安裝,安裝成功后自動啟動,本人使用的v8.6.4的版本,插件基本都無法自動安裝&am…

git pull和git fetch的區別

git pull和git fetch是git版本控制系統中的兩個基本命令,它們都用于從遠程倉庫更新本地倉庫的信息,但執行的具體操作不同。git fetch:git fetch下載遠程倉庫最新的內容到你的本地倉庫,但它并不自動合并或修改你當前的工作。它取回了遠程倉庫的…

Item35:考慮virtual函數以外的其他選擇

在C++中,虛函數是實現多態的傳統方式,但并非唯一選擇。過度依賴虛函數可能導致派生類與基類的強耦合,或難以在運行時靈活切換行為。《Effective C++》Item35指出:應根據場景選擇更合適的替代方案,包括NVI模式、函數指針、策略模式等。本文解析這些方案的原理、適用場景及實…

Vue3 狀態管理新選擇:Pinia 從入門到實戰

一、什么是pinia? 在 Vue3 生態中,狀態管理一直是開發者關注的核心話題。隨著 Vuex 的逐步淡出,Pinia 作為官方推薦的狀態管理庫,憑借其簡潔的 API、強大的功能和對 Vue3 特性的完美適配,成為了新時代的不二之選。今天我們就來深…

Unity相機控制

相機的控制無非移動和旋轉,每種操作各3個軸6個方向,一共12種方式。在某些需要快速驗證的項目或Demo里常常需要絲滑的控制相機調試效果。相機控制雖然不是什么高深的技術,但是要寫的好用還是很磨人的。 鎖定Z軸的旋轉 一個自由的相機可以繞 …