前言
數(shù)字簽名,信息加密是前后端開發(fā)都常用到的技術(shù),應(yīng)用場(chǎng)景包括了用戶登入唉擂、交易、信息通訊场靴、oath等等,不同的應(yīng)用場(chǎng)景也會(huì)需要用到不同的簽名加密算法≈及或者需要搭配不一樣的簽名加密算法咧欣,來(lái)達(dá)到業(yè)務(wù)目標(biāo)。這里簡(jiǎn)要介紹下集中常見的簽名加密算法及一些典型的應(yīng)用場(chǎng)景轨帜。
1魄咕、數(shù)字簽名
數(shù)字簽名,簡(jiǎn)單來(lái)說(shuō)就是通過提供可鑒別的數(shù)字信息驗(yàn)證自身身份的一種方式蚌父,一套數(shù)字簽名通常定義兩種互補(bǔ)的運(yùn)算哮兰,一個(gè)用于簽名,一個(gè)用于驗(yàn)證苟弛。分別由發(fā)送者持有能夠代表自己身份的私鑰(私鑰不可泄露)由接收者持有與私鑰對(duì)應(yīng)的公鑰喝滞,能夠在接收到發(fā)送者信息時(shí)驗(yàn)證其身份。
注意膏秫,圖中加密過程有別于公鑰加密右遭,。簽名最根本的用途是能夠唯一證明發(fā)送方的身份缤削,防止中間人攻擊窘哈,CSRF跨域身份偽造,基于這一點(diǎn)在諸如設(shè)備認(rèn)證亭敢、用戶認(rèn)證滚婉、第三方認(rèn)證等認(rèn)證體系中都會(huì)用到簽名算法。彼此的實(shí)現(xiàn)方式會(huì)有差異帅刀。
2满哪、加密和解密
數(shù)據(jù)加密的基本過程,就是對(duì)原來(lái)就是對(duì)原來(lái)為明文的文件或者數(shù)據(jù)進(jìn)行處理劝篷,使其成為不可讀的一段代碼,通常成為 密文民宿,來(lái)達(dá)到保護(hù)數(shù)據(jù)娇妓,而不被人非法獲取、閱讀的目的活鹰。
加密的你過程稱為解密哈恰,即將該編碼信息轉(zhuǎn)化為其原來(lái)數(shù)據(jù)的過程。
3志群、對(duì)稱加密和非對(duì)稱加密
加密算法分對(duì)稱加密和非對(duì)稱加密着绷,其中對(duì)稱加密算法的加密和解密密鑰相同,非對(duì)稱加密的加密密鑰和解密密鑰不同锌云,才外還有一類不需要密鑰的散列算法荠医。
常見的對(duì)稱加密算法 DES、3DES、AES等彬向,常見的非對(duì)稱算法主要有 RSA兼贡、DSA等,散列算法有
SHA-1
娃胆、MD5
等遍希。
對(duì)稱加密算法是應(yīng)用較早的加密算法,又稱為共享密鑰加密算法里烦,在對(duì)稱加密算法發(fā)中凿蒜,使用的密鑰只有一個(gè),發(fā)送和接收雙方都使用這個(gè)密鑰對(duì)數(shù)據(jù)進(jìn)行加密和解密胁黑。這就要求加密方和解密方都指定密鑰废封。
1、數(shù)據(jù)加密過程:在對(duì)稱加密算法中别厘,數(shù)據(jù)發(fā)送方將明文(原始數(shù)據(jù))和加密密鑰一起經(jīng)過特殊加密處理虱饿,生成復(fù)雜的加密密文進(jìn)行發(fā)送。
2触趴、數(shù)據(jù)解密過程:數(shù)據(jù)接收方收到密文后氮发,若想讀取原數(shù)據(jù),則需要使用加密使用的密鑰及相同算法的逆算法對(duì)加密的密文進(jìn)行解密冗懦,才能使其恢復(fù)成可讀明文爽冕。
非對(duì)稱加密算法又稱為公開密鑰加密算法,他需要兩個(gè)密鑰披蕉,一個(gè)分為公開密鑰(public key ),即公鑰颈畸,另一個(gè)為私有密鑰(private key)即私鑰。
因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰没讲,所以這種算法稱為非對(duì)稱加密算法眯娱。
1、如果使用公鑰對(duì)數(shù)據(jù)進(jìn)行加密爬凑,只有用對(duì)應(yīng)的私鑰才能解密
2徙缴、如果使用私鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的公鑰才能解密
例子:甲方生成一對(duì)密鑰嘁信,并將其中的一把作為公鑰向其他人公開于样,得到該公鑰的乙方,使用該密鑰對(duì)機(jī)密信息進(jìn)行加密后再發(fā)送給甲方潘靖,甲方再使用自己保存的另一把專用密鑰(私鑰)穿剖,對(duì)加密后的信息進(jìn)行解密。
4卦溢、常見的簽名加密算法
4.1. MD5算法
MD5
用的是哈希函數(shù)糊余,它的典型應(yīng)用是對(duì)一段信息產(chǎn)生信息摘要秀又,以防止被纂改,嚴(yán)格來(lái)說(shuō)MD5
不是一種加密算法啄刹,而是摘要算法涮坐,無(wú)論是多長(zhǎng)的輸入,MD5
都會(huì)輸出長(zhǎng)度為128bits
的一個(gè)串誓军, (通常用 16
進(jìn)制 表示為 32
個(gè)字符)袱讹。 java 語(yǔ)言的代碼如下:
public class MD5Main {
public static void main(String[] args) {
String content = "this is a message";
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.digest(content.getBytes());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
4.2. SHA1算法
SHA1
是和 MD5
一樣流行的 消息摘要算法,然而 SHA1
比 MD5
的 安全性更強(qiáng)昵时。對(duì)于長(zhǎng)度小于 2 ^ 64
位的消息捷雕,SHA1
會(huì)產(chǎn)生一個(gè) 160
位的 消息摘要∫忌基于 MD5
救巷、SHA1
的信息摘要特性以及 不可逆 (一般而言),可以被應(yīng)用在檢查 文件完整性 以及 數(shù)字簽名 等場(chǎng)景句柠。
public class MD5Main {
public static void main(String[] args) {
String content = "this is a message";
try {
MessageDigest md5 = MessageDigest.getInstance("SHA1");
System.out.println("---------" + md5.digest(content.getBytes()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
4.3. HMAC算法
HMAC
是密鑰相關(guān)的浦译,哈希運(yùn)算消息認(rèn)證碼(Hash-based Message Authentication Code ),HMAC
運(yùn)算利用 哈希算法 (MD5
溯职、SHA1
等)精盅, 以一個(gè)密鑰和一個(gè)消息為輸入,生成一個(gè)消息摘要為輸出谜酒。
HMAC
發(fā)送方 和 接收方 都有的 key
進(jìn)行計(jì)算叹俏, 而沒有這把key
的第三方,則是無(wú)法計(jì)算出正確的散列值的僻族,這樣的話就可以防止數(shù)據(jù)被纂改粘驰。
package net.pocrd.util;
import net.pocrd.annotation.NotThreadSafe;
import net.pocrd.define.ConstField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
@NotThreadSafe
public class HMacHelper {
private static final Logger logger = LoggerFactory.getLogger(HMacHelper.class);
private Mac mac;
/**
* MAC算法可選以下多種算法
* HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
*/
private static final String KEY_MAC = "HmacMD5";
public HMacHelper(String key) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(ConstField.UTF8), KEY_MAC);
mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
} catch (Exception e) {
logger.error("create hmac helper failed.", e);
}
}
public byte[] sign(byte[] content) {
return mac.doFinal(content);
}
public boolean verify(byte[] signature, byte[] content) {
try {
byte[] result = mac.doFinal(content);
return Arrays.equals(signature, result);
} catch (Exception e) {
logger.error("verify sig failed.", e);
}
return false;
}
}
測(cè)試結(jié)論:
HMAC
算法實(shí)例在多線程環(huán)境下是不安全的,但是需要在多線程訪問時(shí)述么,進(jìn)行同步的輔助類蝌数,使用ThreadLocal
為每個(gè)線程緩存一個(gè)實(shí)例可以避免進(jìn)行鎖操作。
4.4. AES/DES/3DES算法
AES
度秘、DES
籽前、3DES
都是 對(duì)稱 的 塊加密算法,加解密 的過程是 可逆的敷钾。常用的有 AES128
、AES192
肄梨、AES256
(默認(rèn)安裝的 JDK
尚不支持 AES256
阻荒,需要安裝對(duì)應(yīng)的 jce
補(bǔ)丁進(jìn)行升級(jí) jce1.7
,jce1.8
)众羡。
4.4.1. DES算法
DES
加密算法是一種分組密碼侨赡,以 64
位為 分組對(duì)數(shù)據(jù) 加密, 它的密鑰長(zhǎng)度時(shí)56
位,加密解密用同一算法羊壹。
DES
算法是對(duì)密鑰進(jìn)行保密蓖宦,而公開算法,包括加密和解密算法油猫,這樣只有掌握了和發(fā)送方相同密鑰的人才能解讀由DES 加密算法加密的密文數(shù)據(jù)稠茂。因此破解DES
加密算法實(shí)際上就是搜索密鑰的編碼。對(duì)于 56
位長(zhǎng)度的 密鑰 來(lái)說(shuō)情妖,如果用 窮舉法 來(lái)進(jìn)行搜索的話睬关,其運(yùn)算次數(shù)為 2 ^ 56
次。
4.4.2. 3DES算法
是基于 DES
的 對(duì)稱算法毡证,對(duì) 一塊數(shù)據(jù) 用 三個(gè)不同的密鑰 進(jìn)行 三次加密电爹,強(qiáng)度更高。
4.4.3. AES算法
AES
加密算法是密碼學(xué)中的高級(jí)加密標(biāo)準(zhǔn)料睛,該加密算法采用對(duì)稱分組密碼體制丐箩,密鑰長(zhǎng)度最少支持為128
位、 192
位恤煞、256
位屎勘,分組長(zhǎng)度 128
位, 算法應(yīng)易于各種軟件和硬件實(shí)現(xiàn)阱州。這種加密算法是美國(guó)聯(lián)邦政府采用的 區(qū)塊加密標(biāo)準(zhǔn)挑秉。
AES
本身就是為了取代 DES
的,AES
具有更好的 安全性苔货、效率 和 靈活性犀概。
import net.pocrd.annotation.NotThreadSafe;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
@NotThreadSafe
public class AesHelper {
private SecretKeySpec keySpec;
private IvParameterSpec iv;
public AesHelper(byte[] aesKey, byte[] iv) {
if (aesKey == null || aesKey.length < 16 || (iv != null && iv.length < 16)) {
throw new RuntimeException("錯(cuò)誤的初始密鑰");
}
if (iv == null) {
iv = Md5Util.compute(aesKey);
}
keySpec = new SecretKeySpec(aesKey, "AES");
this.iv = new IvParameterSpec(iv);
}
public AesHelper(byte[] aesKey) {
if (aesKey == null || aesKey.length < 16) {
throw new RuntimeException("錯(cuò)誤的初始密鑰");
}
keySpec = new SecretKeySpec(aesKey, "AES");
this.iv = new IvParameterSpec(Md5Util.compute(aesKey));
}
public byte[] encrypt(byte[] data) {
byte[] result = null;
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
result = cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
public byte[] decrypt(byte[] secret) {
byte[] result = null;
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
result = cipher.doFinal(secret);
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
public static byte[] randomKey(int size) {
byte[] result = null;
try {
KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(size, new SecureRandom());
result = gen.generateKey().getEncoded();
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
4.5. RSA算法
RSA
加密算法是目前最有影響力的 公鑰加密算法,并且被普遍認(rèn)為是目前 最優(yōu)秀的公鑰方案 之一夜惭。RSA
是第一個(gè)能同時(shí)用于 加密 和 數(shù)字簽名 的算法姻灶,它能夠 抵抗 到目前為止已知的 所有密碼攻擊,已被 ISO
推薦為公鑰數(shù)據(jù)加密標(biāo)準(zhǔn)诈茧。
RSA
加密算法基于一個(gè)十分簡(jiǎn)單的數(shù)論事實(shí):將兩個(gè)大素?cái)?shù)相乘十分容易产喉,但想要對(duì)其乘積進(jìn)行因式分解缺極其困難,因此可以將乘積公開作為加密密鑰敢会。
import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@NotThreadSafe
public class RsaHelper {
private static final Logger logger = LoggerFactory.getLogger(RsaHelper.class);
private RSAPublicKey publicKey;
private RSAPrivateCrtKey privateKey;
static {
Security.addProvider(new BouncyCastleProvider()); //使用bouncycastle作為加密算法實(shí)現(xiàn)
}
public RsaHelper(String publicKey, String privateKey) {
this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
}
public RsaHelper(byte[] publicKey, byte[] privateKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
if (privateKey != null && privateKey.length > 0) {
this.privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public RsaHelper(String publicKey) {
this(Base64Util.decode(publicKey));
}
public RsaHelper(byte[] publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] encrypt(byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
if (content == null) {
return null;
}
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int size = publicKey.getModulus().bitLength() / 8 - 11;
ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 11));
int left = 0;
for (int i = 0; i < content.length; ) {
left = content.length - i;
if (left > size) {
cipher.update(content, i, size);
i += size;
} else {
cipher.update(content, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] decrypt(byte[] secret) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
if (secret == null) {
return null;
}
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int size = privateKey.getModulus().bitLength() / 8;
ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size - 12) / (size - 11) * size);
int left = 0;
for (int i = 0; i < secret.length; ) {
left = secret.length - i;
if (left > size) {
cipher.update(secret, i, size);
i += size;
} else {
cipher.update(secret, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
logger.error("rsa decrypt failed.", e);
}
return null;
}
public byte[] sign(byte[] content) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
if (content == null) {
return null;
}
try {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
signature.update(content);
return signature.sign();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean verify(byte[] sign, byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
if (sign == null || content == null) {
return false;
}
try {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
signature.update(content);
return signature.verify(sign);
} catch (Exception e) {
logger.error("rsa verify failed.", e);
}
return false;
}
}
4.6. ECC算法
ECC
也是一種 非對(duì)稱加密算法曾沈,主要優(yōu)勢(shì)是在某些情況下,它比其他的方法使用 更小的密鑰鸥昏,比如 RSA
加密算法塞俱,提供 相當(dāng)?shù)幕蚋叩燃?jí) 的安全級(jí)別。不過一個(gè)缺點(diǎn)是 加密和解密操作 的實(shí)現(xiàn)比其他機(jī)制 時(shí)間長(zhǎng) (相比 RSA
算法吏垮,該算法對(duì) CPU
消耗嚴(yán)重)障涯。
import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@NotThreadSafe
public class EccHelper {
private static final Logger logger = LoggerFactory.getLogger(EccHelper.class);
private static final int SIZE = 4096;
private BCECPublicKey publicKey;
private BCECPrivateKey privateKey;
static {
Security.addProvider(new BouncyCastleProvider());
}
public EccHelper(String publicKey, String privateKey) {
this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
}
public EccHelper(byte[] publicKey, byte[] privateKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
if (privateKey != null && privateKey.length > 0) {
this.privateKey = (BCECPrivateKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
}
} catch (ClassCastException e) {
throw new RuntimeException("", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public EccHelper(String publicKey) {
this(Base64Util.decode(publicKey));
}
public EccHelper(byte[] publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] encrypt(byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
try {
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int size = SIZE;
ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 45));
int left = 0;
for (int i = 0; i < content.length; ) {
left = content.length - i;
if (left > size) {
cipher.update(content, i, size);
i += size;
} else {
cipher.update(content, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] decrypt(byte[] secret) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
try {
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int size = SIZE + 45;
ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size + 44) / (size + 45) * size);
int left = 0;
for (int i = 0; i < secret.length; ) {
left = secret.length - i;
if (left > size) {
cipher.update(secret, i, size);
i += size;
} else {
cipher.update(secret, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
logger.error("ecc decrypt failed.", e);
}
return null;
}
public byte[] sign(byte[] content) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
try {
Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
signature.initSign(privateKey);
signature.update(content);
return signature.sign();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean verify(byte[] sign, byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
try {
Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
signature.initVerify(publicKey);
signature.update(content);
return signature.verify(sign);
} catch (Exception e) {
logger.error("ecc verify failed.", e);
}
return false;
}
}
5. 各種加密算法對(duì)比
5.1. 散列算法比較
名稱 | 安全性 | 速度 |
---|---|---|
SHA-1 | 高 | 慢 |
MD5 | 中 | 快 |
5.2. 對(duì)稱加密算法比較
名稱 | 密鑰名稱 | 運(yùn)行速度 | 安全性 | 資源消耗 |
---|---|---|---|---|
DES | 56位 | 較快 | 低 | 中 |
3DES | 112位或168位 | 慢 | 中 | 高 |
AES | 128罐旗、192、256位 | 快 | 高 | 低 |
5.3. 非對(duì)稱加密算法比較
名稱 | 成熟度 | 安全性 | 運(yùn)算速度 | 資源消耗 |
---|---|---|---|---|
RSA | 高 | 高 | 中 | 中 |
ECC | 高 | 高 | 慢 | 高 |
5.4. 對(duì)稱算法與非對(duì)稱加密算法
5.4.1. 對(duì)稱算法
- 密鑰管理:比較難唯蝶,不適合互聯(lián)網(wǎng)九秀,一般用于內(nèi)部系統(tǒng)
- 安全性:中
-
加密速度:快好 幾個(gè)數(shù)量級(jí) (軟件加解密速度至少快
100
倍,每秒可以加解密數(shù)M
比特 數(shù)據(jù))粘我,適合大數(shù)據(jù)量的加解密處理
5.4.2. 非對(duì)稱算法
- 密鑰管理:密鑰容易管理
- 安全性:高
- 加密速度:比較慢鼓蜒,適合 小數(shù)據(jù)量 加解密或數(shù)據(jù)簽名
小結(jié)
本文介紹了 數(shù)字簽名,加密和解密涂滴,對(duì)稱加密和非對(duì)稱加密友酱,然后詳細(xì)介紹了 MD5
,SHA-1
柔纵,HMAC
缔杉,DES/AES
,RSA
和 ECC
這幾種加密算法和代碼示例搁料。