• 【加密与解密】【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)
    }
    
  • 相关阅读:
    Java(类和对象笔记)
    STM32 通过USB接口读写挂载的SD卡(支持fatfs文件系统)
    Linux进程
    浅析人脸活体检测技术的功能及几种分类
    详解typora配置华为云图床
    【JavaSe笔记】——final关键字,常量,抽象类的定义使用和特征
    Python机器学习算法备忘单之5 种常见算法的快速参考指南
    Keepalived+Nginx实现网站的高可用架构
    MyBatis-plus 分页功能实现
    网络协议的基本概念
  • 原文地址:https://blog.csdn.net/u013718730/article/details/139933155