【加密与解密】【06】Java加密套件全解析

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)
}
  • 64
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值