Java中的秘钥类
- PublicKey,公钥
- PrivateKey,私钥
- SecretKey,秘钥,特指对称加密中的秘钥
Key接口
上面的秘钥类均实现该接口
interface java.security.Key
// DSA
fun getAlgorithm() : String
// X.509
fun getFormat() : String
// key content
fun getEncoded() : ByteArray
KeyPairGenerator
用于生成公钥私钥对
@OptIn(ExperimentalStdlibApi::class)
fun generateKeyPair() {
val generator = KeyPairGenerator.getInstance("DSA")
generator.initialize(1024)
val keyPair = generator.genKeyPair()
val publicKey = keyPair.public
val privateKey = keyPair.private
println("PublicKey:" + publicKey.encoded.toHexString(HexFormat.UpperCase))
println("PrivateKey:" + privateKey.encoded.toHexString(HexFormat.UpperCase))
}
KeyGenerator
用于生成对称秘钥
@OptIn(ExperimentalStdlibApi::class)
fun generateSecretKey() {
val random = SecureRandom()
val generator = KeyGenerator.getInstance("DES")
generator.init(random)
val secretKey = generator.generateKey()
println("SecretKey:" + secretKey.encoded.toHexString(HexFormat.UpperCase))
}
KeySpec
定义秘钥规格的接口,所有秘钥类参数类,都当实现该接口
- SecretKeySpec,对称秘钥规格,支持所有对称加密算法
- X509EncodedKeySpec,公钥规格
- PKCS8EncodedKeySpec,私钥规格
- DESKeySpec,DES算法加密的秘钥规格
- SecretKeySpec本身可以直接作为Key来使用,其它Spec则不可以
- 可以通过KeyFactory.generate(spec)来生成Key
- 大多KeySpec根据bytes参数进行初始化
AlgorithmParameterSpec
定义算法规格的接口,所有算法参数类,都当实现该接口
- DSAParameterSpec,DSA算法参数规格
- 可以通过KeyGenerator.init(spec)来应用算法参数
- 大多ParameterSpec根据algorithm,random,offset等参数初始化
KeyFactory
非对称秘钥工厂
根据KeySpec生成公钥私钥,或公钥私钥生成KeySpec
val spec = PKCS8EncodedKeySpec(keyBytes)
val factory = KeyFactory.getInstance("RSA")
val key = factory.generatePrivate(spec)
println("PrivateKey:" + key.encoded.toHexString())
val key = factory.getKeySpec(key, PKCS8EncodedKeySpec::class.java)
SecretKeyFactory
对称秘钥工厂
和KeyFactory用法完成一致,只是对应的秘钥类型不一样
@OptIn(ExperimentalStdlibApi::class)
fun generateSecretKey() {
val generator = KeyGenerator.getInstance("DES")
val secretKey1 = generator.generateKey()
val keyBytes = secretKey1.encoded
val keySpec = DESedeKeySpec(keyBytes)
val keyFactory = SecretKeyFactory.getInstance("DES")
val secretKey2 = keyFactory.generateSecret(keySpec)
println(secretKey1.encoded.toHexString(HexFormat.UpperCase))
println(secretKey2.encoded.toHexString(HexFormat.UpperCase))
}
Certificate
一个证书文件可能包含多个Certificate,证书之间具有层级关系
通过上级证书可以颁发下级证书,这种关系叫做信任链
证书通过Certificate表示,证书信任链通过CertificatePath表示
可通过CertificateFactory来生成证书和证书信任链对象
val crtPath1 = "/home/easing/Temp/a.cer"
val crtPath2 = "/home/easing/Temp/b.cer"
val factory = CertificateFactory.getInstance("X.509")
val certificates1 = factory.generateCertificates(FileInputStream(crtPath1)).toList()
val certPath1 = factory.generateCertPath(certificates1)
val certificates2 = factory.generateCertificates(FileInputStream(crtPath2)).toList()
val certPath2 = factory.generateCertPath(certificates2)
KeyStore
秘钥库,用于保存秘钥和证书,比较常见的是JKS和PKCS12格式
可以理解为一个特殊格式的压缩包,可以设置密码,可以保存多份秘钥和证书
val keyStore = KeyStore.getInstance()
keyStore.load()
keyStore.store()
keyStore.size()
keyStore.aliases().toList()
keyStore.getCertificate()
keyStore.setKeyEntry()
keyStore.setCertificateEntry()
keyStore.getEntry()
keyStore.entryInstanceOf()
KeyStore.Entry
KeyStore通过别名,可以存储三种不同类型的数据
- PrivateKeyEntry,私钥
- SecretKeyEntry,对称秘钥
- TrustedCertificateEntry,信任证书
MessageDiagest
消息摘要工具类
通过对一段完整数据,进行特定的运算,可以得到一串散列值
散列运算是不可逆的,且同样的数据,生成的散列值是固定的
这种算法叫做消息摘要算法,可以用来校验数据的完整性
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.security.DigestInputStream
import java.security.MessageDigest
fun main() {
println(digestText("Hello World"))
println(digestInputStream(ByteArrayInputStream("Hello World".encodeToByteArray())))
}
@OptIn(ExperimentalStdlibApi::class)
fun digestText(content: String): String {
val input = content.encodeToByteArray()
val digest = MessageDigest.getInstance("SHA")
digest.update(input)
val output = digest.digest()
val sha = output.toHexString(HexFormat.UpperCase)
return sha
}
@OptIn(ExperimentalStdlibApi::class)
fun digestInputStream(inputStream: InputStream): String {
val digest = MessageDigest.getInstance("SHA")
val digestInputStream = DigestInputStream(inputStream, digest)
val buffer = ByteArray(512)
var offset = 0
while (true) {
val read = digestInputStream.read(buffer, offset, 64)
if (read <= 0) {
break
}
offset += read
}
val output = digest.digest()
digestInputStream.close()
val sha = output.toHexString(HexFormat.UpperCase)
return sha
}
Signature
签名工具类,用于私钥签名,或公钥校验
数据发送方对数据进行摘要,再通过私钥对摘要进行加密
数据接收方通过公钥对摘要进行解密,再对数据进行摘要,与解密出的摘要值进行对比,判断是否一致
这样既能保证发送方身份,也能保证数据完整性
fun generateKeyPair(): KeyPair {
val generator = KeyPairGenerator.getInstance("DSA")
generator.initialize(1024)
val keyPair = generator.genKeyPair()
return keyPair
}
fun signAndVerify() {
val keyPair = generateKeyPair()
val data = "Hello World".encodeToByteArray()
val signature = Signature.getInstance(keyPair.private.algorithm)
// sign
signature.initSign(keyPair.private)
signature.update(data)
val sign = signature.sign()
// verify
signature.initVerify(keyPair.public)
signature.update(data)
val result = signature.verify(sign)
println(result)
}
CodeSigner
用于封装签名信息,可用来对比两个签名是否一致
val date = Date()
val timestamp1 = Timestamp(date, certPath1)
val timestamp2 = Timestamp(date, certPath2)
val sign1 = CodeSigner(certPath1, timestamp1)
val sign2 = CodeSigner(certPath2, timestamp2)
println(sign1 == sign2)
SignedObject
SignedObject允许在内存中对数据进行签名和验证
SignedObject具有以下特点
- 独立于真实数据,不可被中途篡改
- 方便在代码中进行操作
- 通过重写verify方法,可以实现自定义的签名验证逻辑
public SignedObject(Serializable object, PrivateKey signingKey, Signature signingEngine)
public byte[] getSignature()
public boolean verify(PublicKey verificationKey, Signature verificationEngine)
Cipher
Cipher是一个超级强大的加密解密类
-
支持格式加密类型和加密算法
-
支持通过Key或Certificate来加密解密
-
支持Key的封包解包(Wrap/Unwrap)
Cipher对称加密解密
fun encryptAndDecrypt() {
val shareKey = KeyGenerator.getInstance("DES").generateKey()
val encryptKey = SecretKeySpec(shareKey.encoded, shareKey.algorithm)
val decryptKey = SecretKeySpec(shareKey.encoded, shareKey.algorithm)
// encrypt data
val cipher1 = Cipher.getInstance("DES")
cipher1.init(Cipher.ENCRYPT_MODE, encryptKey)
val encrypted = cipher1.doFinal("Hello World".encodeToByteArray())
// decrypt data
val cipher2 = Cipher.getInstance("DES")
cipher2.init(Cipher.DECRYPT_MODE, decryptKey)
val decrypted = cipher2.doFinal(encrypted)
println(decrypted.decodeToString())
}
Cipher非对称加密解密
fun encryptAndDecrypt() {
val keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair()
val privateKeySpec = PKCS8EncodedKeySpec(keyPair.private.encoded)
val publicKeySpec = X509EncodedKeySpec(keyPair.public.encoded)
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec)
val publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec)
// encrypt data
val cipher1 = Cipher.getInstance("RSA")
cipher1.init(Cipher.ENCRYPT_MODE, privateKey)
val encrypted = cipher1.doFinal("Hello World".encodeToByteArray())
// decrypt data
val cipher2 = Cipher.getInstance("RSA")
cipher2.init(Cipher.DECRYPT_MODE, publicKey)
val decrypted = cipher2.doFinal(encrypted)
println(decrypted.decodeToString())
}
Cipher封包解包
Key的封包解包是指Key本身被其它Key所加密,发送前需要先加密,使用时需要先解密
比如下面的例子,双方通过对称秘钥,可以是DH算法生成的交换秘钥,来加密解密其它秘钥
甲方通过shareKey对secretKey1进行加密,乙方通过shareKey解密出secretKey2,这两个应当相等
fun wrapAndUnwrap() {
val shareKey = KeyGenerator.getInstance("DES").generateKey()
val wrapKey = SecretKeySpec(shareKey.encoded, shareKey.algorithm)
val unwrapKey = SecretKeySpec(shareKey.encoded, shareKey.algorithm)
// wrap key
val secretKey1 = KeyGenerator.getInstance("DES").generateKey()
val cipher1 = Cipher.getInstance("DES")
cipher1.init(Cipher.WRAP_MODE, wrapKey)
val wrappedSecretKey = cipher1.wrap(secretKey1)
// unwrap key
val cipher2 = Cipher.getInstance("DES")
cipher2.init(Cipher.UNWRAP_MODE, unwrapKey)
val secretKey2 = cipher2.unwrap(wrappedSecretKey, "DES", Cipher.SECRET_KEY)
println(secretKey1 == secretKey2)
}
CipherInputStream和CipherOutputStream
对于较大的字节数据,不方便通过字节数组一次性读写的,可以通过Stream来操作
配合DataInputStream,可以很方便得读写加密解密后的字符串
SealedObject
用于在内存中,对可序列化的对象进行加密解密
这里我们通过apache的commons-lang库来实现对象的序列化和反序列化
api("org.apache.commons:commons-lang3:3.14.0")
fun encryptAndDecryptBySealedObject() {
val keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair()
val privateKeySpec = PKCS8EncodedKeySpec(keyPair.private.encoded)
val publicKeySpec = X509EncodedKeySpec(keyPair.public.encoded)
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec)
val publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec)
// encrypt data
val cipher1 = Cipher.getInstance("RSA")
cipher1.init(Cipher.ENCRYPT_MODE, privateKey)
val sealedObject1 = SealedObject("Hello World", cipher1)
val encrypted = SerializationUtils.serialize(sealedObject1)
// decrypt data
val sealedObject2 = SerializationUtils.deserialize<SealedObject>(encrypted)
val cipher2 = Cipher.getInstance("RSA")
cipher2.init(Cipher.DECRYPT_MODE, publicKey)
val decrypted = sealedObject2.getObject(cipher2)
println(decrypted)
}