java 编解码和加解密
1、String转byte[]的作用
网络传输:
在通过网络(如TCP/IP)发送数据时,数据通常需要被转换为字节流。这是因为网络传输是基于字节的,而不是基于字符的
文件存储:
将字符串写入文件时,通常需要将字符串转换为字节,因为文件是以字节形式存储数据的。例如,使用FileOutputStream写入文件时,需要先将字符串转换为字节
加密和解密:
在加密和解密过程中,数据通常需要先转换为字节,因为加密算法通常处理的是字节数据
哈希计算:
在计算字符串的哈希值(如MD5、SHA-1、SHA-256等)时,需要将字符串转换为字节,因为哈希函数作用于字节数据
2、编解码
2.1、标准编码表编码方式名称(仅java)
合法 UFT-8 UFT8 uft-8 uft8 不合法 UFT_8 utf_8
合法 GBK gbk
合法 ISO8859-1 ISO-8859-1 ISO_8859_1 ISO_8859-1 iso8859-1 iso-8859-1 iso_8859_1 iso_8859-1 不合法 ISO-8859_1 iso-8859_1
合法 ASCII ascii US-ASCII us-ascii 不合法 US_ASCII us_ascii
2.1、String与byte[]互转
byte[] getBytes(String charsetName) //String转byte[]
String(byte bytes[], String charsetName) //byte[]转String
import java.io.UnsupportedEncodingException;
public class E1 {
public static void main(String[] args) throws UnsupportedEncodingException {
//String转byte[]
byte[] bytes = "this is 字符串".getBytes("UTF-8"); // [116,104,105,115,32,105,115,32,-27,-83,-105,-25,-84,-90,-28,-72,-78]
//byte[]转String
String str = new String(new byte[]{116,104,105,115,32,105,115,32,-27,-83,-105,-25,-84,-90,-28,-72,-78}, "UTF-8");
}
}
2.2、Url编解码(避免特殊字符如?, #, &破坏URL结构)
static String encode(String s, String enc) //url编码
static String decode(String s, String enc) //url解码
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class E1 {
public static void main(String[] args) throws UnsupportedEncodingException {
//url编码
String encodeUrl = URLEncoder.encode("http://localhost:8080/首 页.html", "UTF-8"); // http%3A%2F%2Flocalhost%3A8080%2F%E9%A6%96+%E9%A1%B5.html
//url解码
String decodeURL = URLDecoder.decode("http%3A%2F%2Flocalhost%3A8080%2F%E9%A6%96+%E9%A1%B5.html", "UTF-8"); // http://localhost:8080/首 页.html
}
}
2.3、16进制编解码
public class E2 {
public static void main(String[] args) {
//编码
byte[] originalTextBytes1 = "this is 原文".getBytes();
StringBuilder stringBuilder = new StringBuilder();
for (byte b : originalTextBytes1) {
stringBuilder.append(String.format("%02X", b));
}
String cipherTextStr = stringBuilder.toString(); // 7468697320697320E58E9FE69687
//解码
byte[] originalTextBytes2 = new byte[cipherTextStr.length()/2];
for (int i = 0; i < cipherTextStr.length(); i += 2) {
String substring = cipherTextStr.substring(i, i + 2);
originalTextBytes2[i/2] = (byte) Integer.parseInt(substring, 16);
}
String originalTextStr = new String(originalTextBytes2); // this is 原文
}
}
2.4、Base64加解密(常用于http中传递图片数据或密码token数据)
import java.util.Base64;
public class E3 {
public static void main(String[] args) {
//编码
byte[] originalTextBytes1 = "this is 原文".getBytes(); // [116,104,105,115,32,105,115,32,-27,-114,-97,-26,-106,-121]
byte[] cipherTextBytes1 = Base64.getEncoder().encode(originalTextBytes1); // [100,71,104,112,99,121,66,112,99,121,68,108,106,112,47,109,108,111,99,61]
String cipherTextStr = new String(cipherTextBytes1); // dGhpcyBpcyDlrZfnrKbkuLI=
//解码
byte[] cipherTextBytes2 = cipherTextStr.getBytes(); // [100,71,104,112,99,121,66,112,99,121,68,108,106,112,47,109,108,111,99,61]
byte[] originalTextBytes2 = Base64.getDecoder().decode(cipherTextBytes2); // [116,104,105,115,32,105,115,32,-27,-83,-105,-25,-84,-90,-28,-72,-78]
String originalTextStr2 = new String(originalTextBytes2); // this is 原文
}
}
2.5、哈希加密(摘要加密)
2.5.1 MD5加密(计算出的结果为128bit的数据,可以转为base64或16进制使用)
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;
public class E4 {
public static void main(String[] args) throws NoSuchAlgorithmException {
//加密
byte[] originalTextBytes = "this is 原文".getBytes();
MessageDigest md5Digest = MessageDigest.getInstance("MD5"); //指定算法
md5Digest.update(originalTextBytes); //指定要加密的数据
byte[] cipherTextByte = md5Digest.digest(); //计算出结果 [-126, 65, -95, -21, 5, -36, -27, -118, -90, -35, -24, -124, -18, -10, 84, 98]
}
}
2.5.2 SHA-256加密(推荐使用,计算出的结果为256bit的数据,可以转为base64或16进制使用)
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;
public class E5 {
public static void main(String[] args) throws NoSuchAlgorithmException {
//加密
byte[] originalTextBytes = "this is 原文".getBytes();
MessageDigest SHA256Digest = MessageDigest.getInstance("SHA-256"); //指定算法
SHA256Digest.update(originalTextBytes); //指定要加密的数据
byte[] cipherTextByte = SHA256Digest.digest(); //计算出结果 [-41, 91, -57, 93, 55, -63, 35, 93, 31, 39, 79, -53, 44, 48, 17, -104, 80, 78, -76, -82, 79, -92, -70, 32, 68, 20, 68, -76, -71, -76, -128, -53]
}
}
2.5.2 SHA-512加密(计算出的结果为512bit的数据,可以转为base64或16进制使用)
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;
public class E6 {
public static void main(String[] args) throws NoSuchAlgorithmException {
//加密
byte[] originalTextBytes = "this is 原文".getBytes();
MessageDigest SHA512Digest = MessageDigest.getInstance("SHA-512"); //指定算法
SHA512Digest.update(originalTextBytes); //指定要加密的数据
byte[] cipherTextByte = SHA512Digest.digest(); //计算出结果 [28, -57, -70, 79, -70, 25, -73, -8, 120, 122, -53, -89, -7, -78, -76, 63, -62, 46, 50, 81, -34, -93, 125, 11, -73, -109, 120, 92, -36, 81, -120, 50, -89, -118, -34, -104, 24, -76, 77, -98, 11, 97, -116, 2, 25, 105, 124, 123, 74, -62, -46, -40, 20, -22, -12, 58, 85, -107, -43, -34, 29, -111, -28, 109]
}
}
2.6、对称加密
2.6.1 DES加密
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class E7 {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String secretKey = "secretke"; //密钥
String ivVector = "ivvector"; //IV向量
/*加密*/
String originalText = "this is 原文"; //原文
//【AES算法(需要密钥byte[]长度只能为8)】/【ECB(无需向量参数) CBC(需要向量参数,且向量的byte[]长度必须是8)】/【PKCS5Padding(对原文长度无要求) NoPadding(要求原文byte[]的长度是8的倍数)】
Cipher cipher1 = Cipher.getInstance("DES/CBC/PKCS5Padding"); //指定算法和模式
SecretKeySpec secretKeySpec1 = new SecretKeySpec(secretKey.getBytes(), "DES"); //创建AES密钥器并指定密钥
IvParameterSpec ivParameterSpec1 = new IvParameterSpec(ivVector.getBytes()); //创建IV向量器并指定IV向量
cipher1.init(
Cipher.ENCRYPT_MODE, //指定为使用加密模式
secretKeySpec1, //指定使用的密钥器
ivParameterSpec1 //指定使用的IV向量器
);
byte[] encryptedBytes = cipher1.doFinal(originalText.getBytes()); //对原文的byte[]进行加密 得到byte密文
/*解密*/
Cipher cipher2 = Cipher.getInstance("DES/CBC/PKCS5Padding"); //指定算法和模式
SecretKeySpec secretKeySpec2 = new SecretKeySpec(secretKey.getBytes(), "DES"); //创建AES密钥器并指定密钥
IvParameterSpec ivParameterSpec2 = new IvParameterSpec(ivVector.getBytes()); //创建IV向量器并指定IV向量
cipher2.init(
Cipher.DECRYPT_MODE, //指定为使用解密模式
secretKeySpec2, //指定使用的密钥器
ivParameterSpec2 //指定使用的IV向量器
);
byte[] decryptedBytes = cipher2.doFinal(encryptedBytes); //对byte密文进行解密 得到原文的byte[]
}
}
2.6.2 AES加密(推荐使用)
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class E8 {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
/*生成密钥(非必须,可以通过表密钥生成里密钥,也可以直接生成随机密钥)*/
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //AES密钥器
SecureRandom sha1PRNG = SecureRandom.getInstance("SHA1PRNG"); //生成密钥用的算法
sha1PRNG.setSeed(new byte[] {49,50,51,52,97,98,99,100}); //指定密钥种子,相同的种子结果相同
keyGenerator.init(128,sha1PRNG); //指定生成的密钥为128bit(支持 128 192 256)
SecretKey secretKey = keyGenerator.generateKey(); //密钥对象
byte[] encoded = secretKey.getEncoded(); //byte密钥
String secretKey = "thisis secretkey"; //密钥
String ivVector = "this is ivvector"; //IV向量
/*加密*/
String originalText = "this is 原文"; //原文
//【AES算法(需要密钥byte[]长度只能为16 24 32)】/【ECB(无需向量参数) CBC(需要向量参数,且向量的byte[]长度必须是16)】/【PKCS5Padding(对原文长度无要求) NoPadding(要求原文byte[]的长度是16的倍数)】
Cipher cipher1 = Cipher.getInstance("AES/CBC/PKCS5Padding"); //指定算法和模式
SecretKeySpec secretKeySpec1 = new SecretKeySpec(secretKey.getBytes(), "AES"); //创建AES密钥器并指定密钥
IvParameterSpec ivParameterSpec1 = new IvParameterSpec(ivVector.getBytes()); //创建IV向量器并指定IV向量
cipher1.init(
Cipher.ENCRYPT_MODE, //指定为使用加密模式
secretKeySpec1, //指定使用的密钥器
ivParameterSpec1 //指定使用的IV向量器
);
byte[] encryptedBytes = cipher1.doFinal(originalText.getBytes()); //对原文的byte[]进行加密 得到byte密文
/*解密*/
Cipher cipher2 = Cipher.getInstance("AES/CBC/PKCS5Padding"); //指定算法和模式
SecretKeySpec secretKeySpec2 = new SecretKeySpec(secretKey.getBytes(), "AES"); //创建AES密钥器并指定密钥
IvParameterSpec ivParameterSpec2 = new IvParameterSpec(ivVector.getBytes()); //创建IV向量器并指定IV向量
cipher2.init(
Cipher.DECRYPT_MODE, //指定为使用解密模式
secretKeySpec2, //指定使用的密钥器
ivParameterSpec2 //指定使用的IV向量器
);
byte[] decryptedBytes = cipher2.doFinal(encryptedBytes); //对byte密文进行解密 得到原文的byte[]
}
}
2.7、非对称加密
2.7.1 RSA加密(推荐使用,可以用来加密和签名)
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class E9 {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException {
String originalText = "this is 原文"; //原文
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); //RSA的密钥器
keyGen.initialize(2048); //指定密钥长度 要求512bit~4096bit推荐2048bit
KeyPair keyPair = keyGen.generateKeyPair(); //生成密钥对
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
byte[] publicKeyBytes = publicKey.getEncoded(); //byte公钥
byte[] privateKeyBytes = privateKey.getEncoded(); //byte私钥
/*加密*/
// RSA(算法)/ECB(RSA只能用ECB)/PKCS1Padding(原文长度无要求) NoPadding(不建议使用)
Cipher cipher1 = Cipher.getInstance("RSA/ECB/PKCS1Padding"); //加密器
//byte公钥转公钥对象start
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory1 = KeyFactory.getInstance("RSA");
PublicKey publicKey1 = keyFactory1.generatePublic(x509EncodedKeySpec); //公钥对象
//byte公钥转公钥对象end
cipher1.init(Cipher.ENCRYPT_MODE, publicKey1); //指定为加密模式
byte[] encryptedBytes = cipher1.doFinal(originalText.getBytes()); //加密
/*解密*/
Cipher cipher2 = Cipher.getInstance("RSA/ECB/PKCS1Padding"); //解密器
//byte私钥转私钥对象start
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
PrivateKey privateKey1 = keyFactory2.generatePrivate(pkcs8EncodedKeySpec); //私钥对象
//byte私钥转私钥对象end
cipher2.init(Cipher.DECRYPT_MODE, privateKey1); //指定为解密模式
byte[] decryptedBytes = cipher2.doFinal(encryptedBytes); //解密
}
}
2.7.2 DSA加密(只能用于签名,不能用于加密)
2.8、JWT
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.*;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class E10 {
public static void main(String[] args) {
//jwt结构:头部.载荷.签名
/*
头部:(工具自动生成的无需额外配置)
{
"alg": "HS256", //签名用的算法有HS256、RS256等
"typ": "JWT" //有没有都可以
}
载荷:(可用填入一些标准字段和非标准字段)
{
"iss": "www.xxx.com", //标准字段 签发者
"aud": "www.yyy.com", //标准字段 收用者(支持字符串和数组)
"sub": "ggh", //标准字段 主题(一般存储用户账号或者id)
"exp": 1764647851, //标准字段 过期时间(秒单位时间戳)
"nbf": 1719843675, //标准字段 生效时间(秒单位时间戳)
"iat": 1719843675, //标准字段 签发时间(秒单位时间戳)
"jti": "a1b2c3d4-5e6f-7g8h-9i0j-k1l2m3n4o5p6" //标准字段 唯一id
"data1": "xxx" //非标准字段
"data2": "xxx" //非标准字段
}
签名:(载荷+密钥+算法 计算)
*/
//生成token
String token = JWT.create()
/*载荷*/
//标准字段
.withIssuer("auth0")
.withAudience("999","aaa")
.withSubject("user123")
.withExpiresAt(new Date(System.currentTimeMillis() + 60*60*1000)) //需要传入毫秒值但使用时会转成秒使用
.withNotBefore(new Date(System.currentTimeMillis())) //需要传入毫秒值但使用时会转成秒使用
.withIssuedAt(new Date(System.currentTimeMillis())) //需要传入毫秒值但使用时会转成秒使用
.withJWTId("8a6ddff1-28ea-4a0f-a7bb-cafb7362beb9")
//非标准字段
.withClaim("username", "李小龙")
/*签名*/ /*头部*/
//进行签名 指定使用HS256算法和密钥,并生成对应头部
.sign(Algorithm.HMAC256("jwt密钥"));
//验证token
DecodedJWT decodedJWT = null;
//验证器
JWTVerifier jwtVerifier = JWT
.require(Algorithm.HMAC256("jwt密钥")) //验证 token格式、算法、是否被篡改。当存在过期时间时验证是否过期。当存在生效时间时验证是否生效(不能晚于当前时间)。当存在签发时间时验证签发时间(不能晚于当前时间)
.withIssuer("auth0") //验证签发者
.withAudience("aaa") //验证收用者
.withSubject("user123") //验证主题
.withJWTId("8a6ddff1-28ea-4a0f-a7bb-cafb7362beb9") //验证jwt唯一id
.withClaim("username","李小龙") //验证非标准字段
.build();
try {
//进行验证,并返回解析后的结果
decodedJWT = jwtVerifier.verify(token);
} catch (JWTDecodeException e) {
System.out.println("token格式错误");
} catch (AlgorithmMismatchException e) {
System.out.println("token头部算法说明错误");
} catch (SignatureVerificationException e) {
System.out.println("token被篡改了");
} catch (InvalidClaimException e) {
System.out.println("token未到生效时间 或 token签发时间错误 " +
"或 签发者不匹配 或 收用者不匹配 或 主题不匹配 或 jwt唯一id不匹配 或 非标准字段不匹配");
} catch (TokenExpiredException e) {
System.out.println("token过期了");
} catch (JWTVerificationException e) {
System.out.println("token异常");
}
//使用token
String header = decodedJWT.getHeader();
String payload = decodedJWT.getPayload();
String signature = decodedJWT.getSignature();
String issuer = decodedJWT.getIssuer();
List<String> audience = decodedJWT.getAudience();
String subject = decodedJWT.getSubject();
String jwtId = decodedJWT.getId();
Date expiresAt = decodedJWT.getExpiresAt();
Date notBefore = decodedJWT.getNotBefore();
Date issuedAt = decodedJWT.getIssuedAt();
Map<String, Claim> claims = decodedJWT.getClaims();
Claim usernameClaim = decodedJWT.getClaim("username");
String username = usernameClaim.asString();
}
}

浙公网安备 33010602011771号