背景
本博客主要参考:
-
Java官方文档:
Java Cryptography Architecture(JCA)
Java Secure Socket Extension (JSSE)
Simple Authentication and Security Layer (SASL) -
Java官方文档:https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#Introduction
-
Java官方文档:Java Cryptography Extension (JCE), https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html , package:
java.security -
Java官方文档:配置算法 https://www.java.com/en/configure_crypto.html
-
Java中绕过TLS证书检查: https://howtodoinjava.com/security/bypass-ssl-certificate-checking-java/
加密和编码的主要区别:编码是使用一种的算法对数据进行转换,编码后的数据只需要使用相同的算法发即可得到数据;加密是使用一种算法和密钥(key)对数据进行转换,加密后的数据仅知道加密算法是无法解密的,还需要知道密钥。
Java加密解密体系


三类引擎:
- 加密引擎,提供加密,解密,消息摘要服务
- 生成器或转换器
- 证书或密钥对象
主要算法和服务:
- 生成随机数:SecureRandom
- 消息摘要(hash):Message Digest
- 签名:Signature, 使用密钥初始化,用于签名或验证数据
- 加密工具:Cipher,使用密钥初始化,用于加密和解密数据
- 消息认证编码:MAC,与MessageDigest类似,但是需要使用密钥初始化以保证消息的完整性
- 密钥转换:KeyFactory, 将通用类型的Key转换成算法相关类型key,比如RsaKeySpec
- 私钥转换(用于对称加密):SecretKeyFactory,将SecretKey转换为相关类型key(KeyFactory的子类)
- 密钥对生成:KeyPairGenerator
- 密钥生成:KeyGenerator
- 密钥交换:KeyAgreement
- 密钥和证书管理:KeyStore
- 证书生成:CertificateFactory
- 证书链:CertPathBuilder
- 证书链校验:CertPathValidator
- 证书仓库:CertStore,用于获取证书和CRL
注:Genarator生成全新的数据,Factory基于已有数据创建数据

JCA使用Provider来提供算法服务,程序中可以使用对应Provider的getInstance(算法名,[提供者名])获取服务,如下
md = MessageDigest.getInstance("SHA-256");
md = MessageDigest.getInstance("SHA-256", "ProviderC");
如果没有指定提供者名称,则会搜索所有的provider,直到返回第一个。
Key和KeySpec
Key的子类:PublicKey, PrivateKey, SecretKey(对称加密的key)
Key和KeySpec是密钥数据的两种表现形式。Cipher使用Key来初始化算法。
Key的数据是不透明的,但是KeySpec包含特定的get方法,能够获取key包含的参数。
转换:
PublicKey KeyFactory.generatePublic(KeySpec keySpec)
PrivateKey KeyFactory.generatePrivate(KeySpec keySpec)
KeySpec KeyFactory.getKeySpec(Key key, Class keySpec)
例子:
DSAPrivateKeySpec dsaPrivKeySpec = new DSAPrivateKeySpec(x, p, q, g);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privKey = keyFactory.generatePrivate(dsaPrivKeySpec);
Signature sig = Signature.getInstance("SHA256withDSA");
sig.initSign(privKey);
sig.update(someData);
byte[] signature = sig.sign();
验证:
// encodedPubKey是byte[],通过PublicKey.getEncoded()
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedPubKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Signature sig = Signature.getInstance("SHA256withDSA");
sig.initVerify(pubKey);
sig.update(data);
sig.verify(signature);
SecretKey
创建SecretKey的两种方法:
1.使用Factory
// Note the following bytes are not realistic secret key data
// bytes but are simply supplied as an illustration of using data
// bytes (key material) you already have to build a DESedeKeySpec.
byte[] desEdeKeyData = getKeyData();
DESedeKeySpec desEdeKeySpec = new DESedeKeySpec(desEdeKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey secretKey = keyFactory.generateSecret(desEdeKeySpec);
2.SecretKeySpec
SecretKey只能从KeySpec生成
byte[] aesKeyData = getKeyData();
SecretKeySpec secretKey = new SecretKeySpec(aesKeyData, "AES");
KeyPairGenerator
KeyPairGenerator可生成PublicKey和PrivateKey
Key的生成与具体算法有关,所有算法都共享的参数:keysize和random
其他算法参数:AlgorithmParameterSpec
void initialize(int keysize, SecureRandom random)
void initialize(int keysize) // 使用系统提供的random
void initialize(AlgorithmParameterSpec params,
SecureRandom random)
void initialize(AlgorithmParameterSpec params)

KeyGenerator
KeyGenerator可生成SecretKey,初始化方法与KeyPairGenerator相同
KeyAgreement
参与方使用init初始化私钥,并将公钥发送给对方,使用doPhase生成最终的密钥

初始化方法
public void init(Key key);
public void init(Key key, SecureRandom random);
public void init(Key key, AlgorithmParameterSpec params);
public void init(Key key, AlgorithmParameterSpec params,
SecureRandom random);
Phase
public Key doPhase(Key key, boolean lastPhase);
KeyStore
keystore是存储密钥和证书的地方,
keystore位于:
系统级:${JAVA_HOME}/lib/ext/cacerts
用户级:${user.home}/.keystore目录下。
JDK有3个与keystore相关的工具:keytool,jarsigner和policytool(GUI).
通过KeyStore.getInstance()获取keystore管理类,
keystore的类型:jks(默认),pkcs12(网络标准),jceks(3DES加密),`dks)
keystore中包含两种类型数据:1.私钥 2,被信任的证书
RSA
简介
参考链接:
- RSA算法:https://www.javamex.com/tutorials/cryptography/rsa_algorithm.shtml
- RSA解密:https://www.javamex.com/tutorials/cryptography/rsa_encryption.shtml
RSA加密算法是以其创造者Rivest, Shamir & Adleman三人的首字母命名,是一种非对称加密。
RSA加密的构成:公钥, 私钥和加解密算法。
RSA的理论基础:验证大数是否是素数很容易,但要分解素数很困难。
算法思想:
1.将待加密的数据看成一个数字m
2.寻找两个大素数p和q
3.将p和q相乘,得到模n
4.找到两个指数e和d,使得 m^ed (mod n) = m (mod n)
5.加密密文 s=m^d (mod n)
6.解密密文 m=s^e (mod n)
e和d就是两个key,通过对消息m以e或d为指数进行指数运算,得到密文,再将密文与另外一个指数进行指数运算,即可得到解密后的数据。
实践者,一般e取较小的数字,比如65537,而d的计算,就是RSA算法的基础。为了计算d,必须知道p和q,但是p和q都是由创建者随机选取的大数,只有p和q的乘积是公开的,p和q本身是保密的,因此只有创建者能够知道d。
n称为模,e称为公开指数,d称为私有指数; (e,n)称为公钥,(d,n)称为密钥。
通常为了使得数据随机分布,会在密文尾部加上随机的数据对齐到某个整数,同时避免密文过短导致 m^e < n,从而能够对密文进行开方解密得到消息。
Java代码示例
首先需要密钥对,包括选择公钥e(一般选取65537),和两个不同的随机大素数p和q, 然后计算模数和私钥d
JDK提供了KeyPairGenerator来生成密钥对, 流程:
- 创建
KeyPaireGenerator的实例 - 初始化生成器实例,设置模数的位长度
- 调用
getKeyPair(),返回的对象包含getPublic()和getPrivate()两个方法分别表示公钥和私钥
生成密钥对的方法:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);// 长度一般是1024或2048,折中考虑性能和安全性
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
// 由于Key是通用的接口,要获取具体的信息(模数和指数),还需要进一步使用KeyFactory转换成RSAPublicSpec
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),
RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),
RSAPrivateKeySpec.class);
pub.getModulus() instanceof BigInteger
pub.getPublicExponent() instanceof BigInteger
pub.getPrivateExponent() instanceof BigInteger
使用密钥对加密
// n和e是公钥的模和指数
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(n, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
// byte[] data
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data); // 加密后的数据
解密
// n和d是私钥的模和指数
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(n, d);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(keySpec);
// byte[] data
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(data); // 解密后的数据
AES
简介
参考链接:
AES是对称加密,AES加密算法的key无需特别选取。
Java代码示例
加密
byte[] key = //... secret sequence of bytes
byte[] dataToSend = ...
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k =
new SecretKeySpec(key, "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal(dataToSend);
解密
byte[] key = //... we know the secret!
byte[] encryptedData = //... received from Alice
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k =
new SecretKeySpec(key, "AES");
c.init(Cipher.DECRYPT_MODE, k);
byte[] data = c.doFinal(encryptedData);
// do something with data
其他代码
片段
private static final String key = "aesEncryptionKey";
private static final String initVector = "encryptionIntVec";
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
解密
public static String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
DES
简介
参考:
- https://www.journaldev.com/1309/java-des-algorithm-program
DES是一种比较基础的对称加密算法
Java代码示例
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class DESEncryptionExample {
private static Cipher encryptCipher;
private static Cipher decryptCipher;
private static final byte[] iv = { 11, 22, 33, 44, 99, 88, 77, 66 };
public static void main(String[] args) {
String clearTextFile = "/Users/pankaj/source.txt";
String cipherTextFile = "/Users/pankaj/cipher.txt";
String clearTextNewFile = "/Users/pankaj/source-new.txt";
try {
// create SecretKey using KeyGenerator
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
// get Cipher instance and initiate in encrypt mode
encryptCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
// get Cipher instance and initiate in decrypt mode
decryptCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
// method to encrypt clear text file to encrypted file
encrypt(new FileInputStream(clearTextFile), new FileOutputStream(cipherTextFile));
// method to decrypt encrypted file to clear text file
decrypt(new FileInputStream(cipherTextFile), new FileOutputStream(clearTextNewFile));
System.out.println("DONE");
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IOException e) {
e.printStackTrace();
}
}
private static void encrypt(InputStream is, OutputStream os) throws IOException {
// create CipherOutputStream to encrypt the data using encryptCipher
os = new CipherOutputStream(os, encryptCipher);
writeData(is, os);
}
private static void decrypt(InputStream is, OutputStream os) throws IOException {
// create CipherOutputStream to decrypt the data using decryptCipher
is = new CipherInputStream(is, decryptCipher);
writeData(is, os);
}
// utility method to read data from input stream and write to output stream
private static void writeData(InputStream is, OutputStream os) throws IOException {
byte[] buf = new byte[1024];
int numRead = 0;
// read and write operation
while ((numRead = is.read(buf)) >= 0) {
os.write(buf, 0, numRead);
}
os.close();
is.close();
}
Diffie-Hellman
介绍
参考:
- Stackoverflow:https://stackoverflow.com/questions/21081713/diffie-hellman-key-exchange-in-java
- https://codedost.com/css/java-program-diffie-hellman-algorithm/
- java2s: http://www.java2s.com/Tutorial/Java/0490__Security/DiffieHellmanKeyAgreement.htm
Diffie-Hellman是一种密钥交换方法,这种算法比RSA先提出。
其基本思想如下:
- 发起方选择一个大素数p和一个较小的数g,以及一个数a,生成A = g^a (mod p); 然后将p,g,A传送给接收方;
- 接收方选择一个数b,生成B = g^b (mod p),将B传送给A
- 则发送方的密钥为 keyA = B^a (mod p), 接收方的密钥为keyB = A ^ b(mod p), 并且keyA = keyB
注意,最终发送方和接收方都获取到了密钥,并且密钥相同;但是密钥并没有被传输。
注意,为了使得密钥不容易被猜测,a,b,p都必须非常大,g则无需很大,通常取2或者5。其中,只有a和b是秘密的,其他数据都可以明文传输。
该加密算法的理论技术是下面的等式:
(g^a mod p)^b mod p = (g^b mod p)^a mod p
最终的密钥就是等式一边的结果。
Java代码示例
官方代码示例:
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import com.sun.crypto.provider.SunJCE;
public class DHKeyAgreement2 {
private DHKeyAgreement2() {}
public static void main(String argv[]) throws Exception {
/*
* Alice creates her own DH key pair with 2048-bit key size
*/
System.out.println("ALICE: Generate DH keypair ...");
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(2048);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
// Alice creates and initializes her DH KeyAgreement object
System.out.println("ALICE: Initialization ...");
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());
// Alice encodes her public key, and sends it over to Bob.
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
/*
* Let's turn over to Bob. Bob has received Alice's public key
* in encoded format.
* He instantiates a DH public key from the encoded key material.
*/
KeyFactory bobKeyFac = KeyFactory.getInstance("DH");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(alicePubKeyEnc);
PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);
/*
* Bob gets the DH parameters associated with Alice's public key.
* He must use the same parameters when he generates his own key
* pair.
*/
DHParameterSpec dhParamFromAlicePubKey = ((DHPublicKey)alicePubKey).getParams();
// Bob creates his own DH key pair
System.out.println("BOB: Generate DH keypair ...");
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamFromAlicePubKey);
KeyPair bobKpair = bobKpairGen.generateKeyPair();
// Bob creates and initializes his DH KeyAgreement object
System.out.println("BOB: Initialization ...");
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKpair.getPrivate());
// Bob encodes his public key, and sends it over to Alice.
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
/*
* Alice uses Bob's public key for the first (and only) phase
* of her version of the DH
* protocol.
* Before she can do so, she has to instantiate a DH public key
* from Bob's encoded key material.
*/
KeyFactory aliceKeyFac = KeyFactory.getInstance("DH");
x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);
System.out.println("ALICE: Execute PHASE1 ...");
aliceKeyAgree.doPhase(bobPubKey, true);
/*
* Bob uses Alice's public key for the first (and only) phase
* of his version of the DH
* protocol.
*/
System.out.println("BOB: Execute PHASE1 ...");
bobKeyAgree.doPhase(alicePubKey, true);
/*
* At this stage, both Alice and Bob have completed the DH key
* agreement protocol.
* Both generate the (same) shared secret.
*/
try {
byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
int aliceLen = aliceSharedSecret.length;
byte[] bobSharedSecret = new byte[aliceLen];
int bobLen;
} catch (ShortBufferException e) {
System.out.println(e.getMessage());
} // provide output buffer of required size
bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 0);
System.out.println("Alice secret: " +
toHexString(aliceSharedSecret));
System.out.println("Bob secret: " +
toHexString(bobSharedSecret));
if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret))
throw new Exception("Shared secrets differ");
System.out.println("Shared secrets are the same");
/*
* Now let's create a SecretKey object using the shared secret
* and use it for encryption. First, we generate SecretKeys for the
* "AES" algorithm (based on the raw shared secret data) and
* Then we use AES in CBC mode, which requires an initialization
* vector (IV) parameter. Note that you have to use the same IV
* for encryption and decryption: If you use a different IV for
* decryption than you used for encryption, decryption will fail.
*
* If you do not specify an IV when you initialize the Cipher
* object for encryption, the underlying implementation will generate
* a random one, which you have to retrieve using the
* javax.crypto.Cipher.getParameters() method, which returns an
* instance of java.security.AlgorithmParameters. You need to transfer
* the contents of that object (e.g., in encoded format, obtained via
* the AlgorithmParameters.getEncoded() method) to the party who will
* do the decryption. When initializing the Cipher for decryption,
* the (reinstantiated) AlgorithmParameters object must be explicitly
* passed to the Cipher.init() method.
*/
System.out.println("Use shared secret as SecretKey object ...");
SecretKeySpec bobAesKey = new SecretKeySpec(bobSharedSecret, 0, 16, "AES");
SecretKeySpec aliceAesKey = new SecretKeySpec(aliceSharedSecret, 0, 16, "AES");
/*
* Bob encrypts, using AES in CBC mode
*/
Cipher bobCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
bobCipher.init(Cipher.ENCRYPT_MODE, bobAesKey);
byte[] cleartext = "This is just an example".getBytes();
byte[] ciphertext = bobCipher.doFinal(cleartext);
// Retrieve the parameter that was used, and transfer it to Alice in
// encoded format
byte[] encodedParams = bobCipher.getParameters().getEncoded();
/*
* Alice decrypts, using AES in CBC mode
*/
// Instantiate AlgorithmParameters object from parameter encoding
// obtained from Bob
AlgorithmParameters aesParams = AlgorithmParameters.getInstance("AES");
aesParams.init(encodedParams);
Cipher aliceCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aliceCipher.init(Cipher.DECRYPT_MODE, aliceAesKey, aesParams);
byte[] recovered = aliceCipher.doFinal(ciphertext);
if (!java.util.Arrays.equals(cleartext, recovered))
throw new Exception("AES in CBC mode recovered text is " +
"different from cleartext");
System.out.println("AES in CBC mode recovered text is "
"same as cleartext");
}
/*
* Converts a byte to hex digit and writes to the supplied buffer
*/
private static void byte2hex(byte b, StringBuffer buf) {
char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
int high = ((b & 0xf0) >> 4);
int low = (b & 0x0f);
buf.append(hexChars[high]);
buf.append(hexChars[low]);
}
/*
* Converts a byte array to hex string
*/
private static String toHexString(byte[] block) {
StringBuffer buf = new StringBuffer();
int len = block.length;
for (int i = 0; i < len; i++) {
byte2hex(block[i], buf);
if (i < len-1) {
buf.append(":");
}
}
return buf.toString();
}
}
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.DHParameterSpec;
public class MainClass {
private static BigInteger g512 = new BigInteger("1234567890", 16);
private static BigInteger p512 = new BigInteger("1234567890", 16);
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
DHParameterSpec dhParams = new DHParameterSpec(p512, g512);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
keyGen.initialize(dhParams, new SecureRandom());
KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "BC");
KeyPair aPair = keyGen.generateKeyPair();
KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "BC");
KeyPair bPair = keyGen.generateKeyPair();
aKeyAgree.init(aPair.getPrivate());
bKeyAgree.init(bPair.getPrivate());
aKeyAgree.doPhase(bPair.getPublic(), true);
bKeyAgree.doPhase(aPair.getPublic(), true);
MessageDigest hash = MessageDigest.getInstance("SHA1", "BC");
System.out.println(new String(hash.digest(aKeyAgree.generateSecret())));
System.out.println(new String(hash.digest(bKeyAgree.generateSecret())));
}
}
EC Diffie-Hellman算法
EC Diffie-Hellman算法,在安全领域一般表示为ECDH或者ECHDE,其中后缀E只是表示公钥是使用恒定的数字还是临时生成的数据。
本文详细介绍了Java加密解密体系,涵盖三类引擎:加密引擎、生成器或转换器、证书或密钥对象。解析了主要算法和服务,如SecureRandom、MessageDigest、Cipher、MAC、KeyFactory等。并深入探讨了JCA使用Provider提供算法服务的方式,以及Key和KeySpec的概念和转换方法。同时,提供了RSA、AES、DES等加密算法的Java代码示例。

365

被折叠的 条评论
为什么被折叠?



