sm4算法加密解密

sm4算法加密解密一、基本知识分组加密(英语:Blockcipher),又称分块加密或块密码,是一种对称密钥算法。它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。 对称加密、加密算法主要可以分为两种,一个是非对称加密算法,另一个就是对称加密算法。对称加密简单来说就是有一个明文,通过一个密钥加密之后得到一个密文,这个密文可以通过相同的密要解密得出和原来相同的明文二、sm…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、基本知识

  1. 分组加密(英语:Block cipher),又称分块加密或块密码,是一种对称密钥算法。它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。
  2. 对称加密、加密算法主要可以分为两种,一个是非对称加密算法,另一个就是对称加密算法。对称加密简单来说就是有一个明文,通过一个密钥加密之后得到一个密文,这个密文可以通过相同的密要解密得出和原来相同的明文

二、sm4算法

  1. 算法定义:SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。
  2. 基本运算     

       ⊕  异或

      <<<i  循环左移i位

     3.算法实现

sm4算法加密解密

即首先执行32次轮函数迭代运算,然后在对最后一轮数据反序变换并得到密文输出

三、步骤详解

1.轮函数F

 

sm4算法加密解密

示意图

sm4算法加密解密

SM4的轮函数将输入部分看做了4个32bit长度的数据,每轮的后3个部分都向左移动32bit的数据长度,这三组数据异或后进入非线性部分τ和线性部分L,运算后的结果与第一组数据异或置于最右面。如此循环往复32轮,也就是数据一共左移了8个周期,将其中的混乱因素不断扩散至每个bit位中

2.T函数

sm4算法加密解密

s盒如下:

sm4算法加密解密

使用规则:sm4算法加密解密

3.秘钥扩展算法

sm4算法加密解密

系统参数FK的取值

FK0=(A3B1BAC6),FK1=(56AA3350),FK2=(677D9197),FK3=(B27022DC)

固定参数CK的取值

00070e15, 1c232a31, 383f464d, 545b6269,

70777e85, 8c939aa1, a8afb6bd, c4cbd2d9, 

e0e7eef5,  fc030a11,  181f262d, 343b4249,

50575e65, 6c737a81, 888f969d, a4abb2b9

c0c7ced5,  dce3eaf1,  f8ff060d,  141b2229, 

30373e45, 4c535a61, 686f767d, 848b9299

a0a7aeb5, bcc3cad1,  d8dfe6ed, f4fb0209,

 10171e25, 2c333a41, 484f565d, 646b7279

四、java代码实现

 

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Random;
/**
* @ClassName: Sm4Util
* @Author: tanp
* @Description: sm4加解密工具类
* @Date: 2020/5/8 15:24
*/
public class Sm4Util {
/**
* 加密标识
*/
private static final int ENCRYPT = 1;
/**
* 解密标识
*/
private static final int DECRYPT = 0;
/**
* F轮函数循环次数
*/
private static final int ROUND = 32;
private static final int BLOCK = 16;
private static final int FOUR = 4;
private static final int ZERO = 0;
/**
* s盒
*/
private byte[] sbox = {(byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
(byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
(byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
(byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
(byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
(byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
(byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
(byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
(byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
(byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
(byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
(byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
(byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
(byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
(byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
(byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
(byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
(byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
(byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
(byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
(byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
(byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
(byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
(byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
(byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
(byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
(byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
(byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48};
/**
* 固定的ck参数
*/
private int[] ck = {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5,
0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81,
0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d,
0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25,
0x2c333a41, 0x484f565d, 0x646b7279};
/**
* 固定的fk参数
*/
private int[] fk = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};
/**
* @Description 将传入的x参数循环左移num位
* @Author tanp
*/
private int leftMove(int x, int num) {
//假如数据为无符号的数,长度为N,需要循环移动n位。可以用下面的公式:
//循环左移n位: (x>>(N - n) ) | (x<<n);
return x << num | x >>> (32 - num);
}
/**
* @Description s盒的非线性变化函数
* @Author tanp
*/
private int byteSub(int x) {
return (sbox[x >>> 24 & 0xFF] & 0xFF) << 24
| (sbox[x >>> 16 & 0xFF] & 0xFF) << 16
| (sbox[x >>> 8 & 0xFF] & 0xFF) << 8
| (sbox[x & 0xFF] & 0xFF);
}
/**
* @Description 轮函数中T函数的线性变化L函数
* @Author tanp
*/
private int transLf(int x) {
//B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8);
return x ^ leftMove(x, 2) ^ leftMove(x, 10) ^ leftMove(x, 18) ^ leftMove(x, 24);
}
/**
* @Description 秘钥扩展算法中的T'函数的线性变化L函数
* @Author tanp
*/
private int transTf(int x) {
// B^(B<<13|B>>>19)^(B<<23|B>>>9);
return x ^ leftMove(x, 13) ^ leftMove(x, 23);
}
/**
* @Description 秘钥扩展算法T置换
* @Author tanp
*/
private int transTh(int in) {
return transTf(byteSub(in));
}
/**
* @Description 轮函数T置换
* @Author tanp
*/
private int transLth(int in) {
return transLf(byteSub(in));
}
/**
* @param key       秘钥
* @param cryptFlag 加解密标识
* @Description 获取轮秘钥
* @Author tanp
*/
private int[] sm4KeyExt(byte[] key, int cryptFlag) {
int r, mid;
int[] x = new int[4];
int[] tmp = new int[4];
int[] rk = new int[ROUND];
getValue(key, x, tmp);
//获取轮秘钥之前,先将秘钥与系统函数FK异或
for (r = ZERO; r < FOUR; r++) {
x[r] = x[r] ^ (fk[r]);
}
//轮训执行T置换
for (r = ZERO; r < ROUND; r += FOUR) {
rk[r] = x[0] ^= transTh(x[1] ^ x[2] ^ x[3] ^ ck[r]);
rk[r + 1] = x[1] ^= transTh(x[2] ^ x[3] ^ x[0] ^ ck[r + 1]);
rk[r + 2] = x[2] ^= transTh(x[3] ^ x[0] ^ x[1] ^ ck[r + 2]);
rk[r + 3] = x[3] ^= transTh(x[0] ^ x[1] ^ x[2] ^ ck[r + 3]);
}
// 解密时轮密钥使用顺序:rk31,rk30,...,rk0
if (cryptFlag == DECRYPT) {
for (r = 0; r < BLOCK; r++) {
mid = rk[r];
rk[r] = rk[31 - r];
rk[31 - r] = mid;
}
}
return rk;
}
/**
* @Description 轮函数F
* @param input 加密解密的字节数组
* @param rk 轮秘钥
* @Author tanp
*/
private void sms4Crypt(byte[] input, byte[] output, int[] rk) {
int r;
int[] x = new int[4];
int[] tmp = new int[4];
getValue(input, x, tmp);
for (r = ZERO; r < ROUND; r += FOUR) {
x[0] = x[0] ^ transLth(x[1] ^ x[2] ^ x[3] ^ rk[r]);
x[1] = x[1] ^ transLth(x[2] ^ x[3] ^ x[0] ^ rk[r + 1]);
x[2] = x[2] ^ transLth(x[3] ^ x[0] ^ x[1] ^ rk[r + 2]);
x[3] = x[3] ^ transLth(x[0] ^ x[1] ^ x[2] ^ rk[r + 3]);
}
// Reverse
for (int j = ZERO; j < BLOCK; j += FOUR) {
output[j] = (byte) (x[3 - j / 4] >>> 24 & 0xFF);
output[j + 1] = (byte) (x[3 - j / 4] >>> 16 & 0xFF);
output[j + 2] = (byte) (x[3 - j / 4] >>> 8 & 0xFF);
output[j + 3] = (byte) (x[3 - j / 4] & 0xFF);
}
}
private void getValue(byte[] input, int[] x, int[] tmp) {
for (int i = ZERO; i < FOUR; i++) {
tmp[0] = input[4 * i] & 0xff;
tmp[1] = input[1 + 4 * i] & 0xff;
tmp[2] = input[2 + 4 * i] & 0xff;
tmp[3] = input[3 + 4 * i] & 0xff;
x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
}
}
/**
* @param in        需加密或者解密的字节数组
* @param inLen     加密解密的字节长度
* @param key       秘钥
* @param out       加密解密后的字节数组,用来返回
* @param cryptFlag 加解密标识
* @Description 加密 解密方法
* @Author tanp
*/
private byte[] sms4(byte[] in, int inLen, byte[] key, byte[] out, int cryptFlag) {
int point = 0;
//获取轮秘钥
int[] roundKey = sm4KeyExt(key, cryptFlag);
byte[] input;
byte[] output = new byte[16];
while (inLen >= BLOCK) {
input = Arrays.copyOfRange(in, point, point + 16);
//每16个字节执行一次轮函数
sms4Crypt(input, output, roundKey);
System.arraycopy(output, 0, out, point, BLOCK);
inLen -= BLOCK;
point += BLOCK;
}
return out;
}
/**
* 字符串加密
*
* @param plaintext 明文
* @param key       秘钥
* @return 加密后的明文字符串
* @Author tanp
*/
private static String encodeSms4ToHex(String plaintext, byte[] key) {
if (plaintext == null || plaintext.length() <= 0) {
return null;
}
StringBuilder plaintextBuilder = new StringBuilder(plaintext);
for (int i = plaintextBuilder.toString().getBytes().length % BLOCK; i < BLOCK; i++) {
plaintextBuilder.append('\0');
}
plaintext = plaintextBuilder.toString();
return bytesToHexString(encodeSms4(plaintext.getBytes(), key));
}
/**
* 字符串形式的密文解密成明文
*
* @param enHex 密文
* @param key   秘钥
* @return 解密后的明文
* @Author tanp
*/
private static String decodeSms4HexToString(String enHex, byte[] key) {
byte[] plaintext = decodeSms4(hexStringToBytes(enHex),key);
return new String(plaintext).trim();
}
/**
* SMS4加密,加密字符数组
*
* @param plaintext 字节数组形式的明文
* @param key       秘钥
* @return 明文加密后的字接数组
*/
private static byte[] encodeSms4(byte[] plaintext, byte[] key) {
byte[] ciphering = new byte[plaintext.length];
int k = 0;
int plainLen = plaintext.length;
while (k + BLOCK <= plainLen) {
byte[] cellPlain = new byte[16];
System.arraycopy(plaintext, k, cellPlain, 0, 16);
byte[] cellCipher = encode16(cellPlain, key);
System.arraycopy(cellCipher, 0, ciphering, k, cellCipher.length);
k += 16;
}
return ciphering;
}
/**
* 不限明文长度的SMS4解密
*
* @param ciphering 需要解密的字节数组
* @param key 秘钥
* @return 解密后的字节数组
*/
private static byte[] decodeSms4(byte[] ciphering, byte[] key) {
byte[] plaintext = new byte[ciphering.length];
int k = 0;
int cipherLen = ciphering.length;
while (k + BLOCK <= cipherLen) {
byte[] cellCipher = new byte[16];
System.arraycopy(ciphering, k, cellCipher, 0, 16);
byte[] cellPlain = decode16(cellCipher, key);
System.arraycopy(cellPlain, 0, plaintext, k, cellPlain.length);
k += BLOCK;
}
return plaintext;
}
/**
* 只加密16位明文
*
* @param plaintext 明文字节数组
* @param key       秘钥
* @return 加密后的字节数组
*/
private static byte[] encode16(byte[] plaintext, byte[] key) {
byte[] cipher = new byte[16];
Sm4Util sm4 = new Sm4Util();
//调用加密方法
return sm4.sms4(plaintext, 16, key, cipher, ENCRYPT);
}
/**
* 只解密16位密文
*
* @param ciphering 需解密的密文
* @param key 秘钥
* @return 解密后的明文字节
*/
private static byte[] decode16(byte[] ciphering, byte[] key) {
byte[] plain = new byte[16];
Sm4Util sm4 = new Sm4Util();
sm4.sms4(ciphering, 16, key, plain, DECRYPT);
return plain;
}
/**
* 只加密32位明文
*
* @param plaintext 明文字节数组
* @param key       秘钥
* @return 加密后的字节数组
*/
private static byte[] encode32(byte[] plaintext, byte[] key) {
byte[] cipher = new byte[32];
Sm4Util sm4 = new Sm4Util();
return sm4.sms4(plaintext, 32, key, cipher, ENCRYPT);
}
/**
* 只解密32位密文
*
* @param ciphering 需解密的密文
* @param key 秘钥
* @return 解密后的明文字节
*/
private static byte[] decode32(byte[] ciphering, byte[] key) {
byte[] plain = new byte[32];
Sm4Util sm4 = new Sm4Util();
sm4.sms4(ciphering, 32, key, plain, DECRYPT);
return plain;
}
/**
* 字节数组转字符串
*
* @param src 字节数组
* @return String
*/
private static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (byte aSrc : src) {
int v = aSrc & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
* 字符串转字节数组
*
* @param hexString the hex string
* @return byte[]
*/
private static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.length() <= 0) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* Convert char to byte
*
* @param c char
* @return byte
*/
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/**
* @Description 随机获取中文
* @Date 2020/5/9 14:17
* @Author tanp
*/
private static char getRandomChar() {
String str = "";
int hightPos;
int lowPos;
Random random = new Random();
hightPos = (176 + Math.abs(random.nextInt(39)));
lowPos = (161 + Math.abs(random.nextInt(93)));
byte[] b = new byte[2];
b[0] = (Integer.valueOf(hightPos)).byteValue();
b[1] = (Integer.valueOf(lowPos)).byteValue();
try {
str = new String(b, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.out.println("错误");
}
return str.charAt(0);
}
public static void main(String[] args) {
final byte[] key = {0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab,
(byte) 0xcd, (byte) 0xef, (byte) 0xfe, (byte) 0xdc,
(byte) 0xba, (byte) 0x98, 0x76, 0x54, 0x32, 0x10};
StringBuilder msg = new StringBuilder();
for(int a=0;a<ROUND;a++){
for (int i = 1; i < ROUND; i++) {
msg.append(getRandomChar());
}
System.out.println("加密前:" + msg.toString());
String enStr = encodeSms4ToHex(msg.toString(), key);
System.out.println("加密后:" + enStr);
String deStr = decodeSms4HexToString(enStr, key);
System.out.println("解密后:" + deStr);
//查看经过加密再解密后的字符串是否与最开始的原生字符串是否一致
System.out.println(msg.toString().equals(deStr));
}
}
}

 

五、参考文献

SM4分组密码算法:https://wenku.baidu.com/view/e66938055acfa1c7aa00cca7.html?from=search

SM4分组密码算法综述:https://wenku.baidu.com/view/5c900609001ca300a6c30c22590102020640f252.html?fr=search

SM4算法及实现方式:http://www.mamicode.com/info-detail-2603734.html

SM4加密解密:https://blog.csdn.net/Mr_ye931/article/details/105680359

六、总结

本篇博客为查看参考文献中的相关文档学习总结所得,有错误的地方大家多多指教

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/185344.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • redflag linux安装教程,硬盘安装REDFlag LINUX体会

    redflag linux安装教程,硬盘安装REDFlag LINUX体会我是一名LINUX的初学者,在看了许多LINUX的介绍之后,在本着大胆和心细的原则下,尝试了一回安装LINUX。现把我的一些心得和体会和大家分享,希望对一些入门级的朋友有所帮助。我装的是REDFlagLINUX,我原来的操作系统是WINXP,本着学习LINUX的和省钱至上的想法,我选择了安装WINXP和LINUX的双系统,我在网上下载了LINUX的ISO文件,先保存在随意的一个硬盘里,只要不是…

  • Java HttpURLConnection setRequestProperty(“content-length“, “0“)不起作用

    Java HttpURLConnection setRequestProperty(“content-length“, “0“)不起作用Post验证Url合法的时候,今天突然遇到一个用IIS的客户,结果返回411的statuscode.搜索原因是请求头中没有设置Content-Lenght。网上的教程说用setRequestProperty(“content-length”,“0”)设置一下,结果我测试还是返回411.调试发现:为了安全,这些头默认是不允许指自定义的。可以通过下面方法打开,尽量将下面的语句放到main中:System.setProperty(“sun.net.http.allowRestrictedHead

  • 为有机会进大厂,程序员必须掌握的核心算法有哪些?

    由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是零散的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过…

  • matplotlib常用函数介绍及使用

    matplotlib常用函数介绍及使用

  • Heartbleed第二篇:Heartbleed漏洞剖析

    Heartbleed第二篇:Heartbleed漏洞剖析Heartbleed漏洞剖析

  • Java 的下载安装教程[通俗易懂]

    Java 的下载安装教程[通俗易懂]Java17的下载安装教程说明:本文介绍的是Windows下安装Java的方法。对于Linux下Java的安装,可见笔者的另一篇博客:在Linux操作系统中安装Java:https://blog.csdn.net/wangpaiblog/article/details/120093325笔者的安装环境:JDK17Windows10教育版安装Java就是安装JDK。Java有三大分支,这里选择的是JavaSE。关于

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号