All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.labijie.application.crypto.RsaUtils.kt Maven / Gradle / Ivy

package com.labijie.application.crypto

import com.labijie.infra.utils.throwIfNecessary
import java.io.ByteArrayOutputStream
import java.nio.charset.Charset
import java.security.KeyFactory
import java.security.PublicKey
import java.security.Signature
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.InvalidKeySpecException
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import java.util.*
import javax.crypto.Cipher


/**
 * Created with IntelliJ IDEA.
 * @author Anders Xiao
 * @date 2019-12-12
 */
object RsaUtils {
    /**
     * RSA最大加密明文大小
     */
    private const val MAX_ENCRYPT_BLOCK = 117

    const val ENCRTPY_RSA = "RSA/ECB/PKCS1Padding"

    const val SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"

    const val SIGN_ALGORITHMS = "SHA1WithRSA"
    /**
     * @param sortedParams
     * @return
     */
    private fun getSignContent(sortedParams: Map): String {
        val content = StringBuilder()
        val keys: List = ArrayList(sortedParams.keys).sorted()
        keys.forEachIndexed { index, key ->
            val value = sortedParams[key]
            if (key.isNotBlank() && !value.isNullOrBlank()) {
                content.append(if (index == 0) "" else "&").append("$key=$value")
            }
        }
        return content.toString()
    }

    /**
     * sha256WithRsa 加签
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     */
    fun rsaSignSHA256(
        content: String, privateKey: String,
        charset: Charset = Charsets.UTF_8
    ): String {
        return try {
            val priKey = getPrivateKeyFromPKCS8(
                privateKey.toByteArray(Charsets.UTF_8)
            )
            val signature: Signature = Signature.getInstance(SIGN_SHA256RSA_ALGORITHMS)
            signature.initSign(priKey)
            signature.update(content.toByteArray(charset))
            val signed: ByteArray = signature.sign()
            Base64.getEncoder().encodeToString(signed)
        } catch (e: Exception) {
            e.throwIfNecessary()
            throw RsaException(
                "RSAcontent = $content; charset = $charset",
                e
            )
        }
    }

    /**
     * sha1WithRsa 加签
     *
     * @param content
     * @param privateKey
     * @param charset
     * @return
     */
    fun rsaSignSHA1(
        content: String, privateKey: String,
        charset: Charset = Charsets.UTF_8
    ): String {
        return try {
            val priKey = getPrivateKeyFromPKCS8(
                privateKey.toByteArray(Charsets.UTF_8)
            )
            val signature: Signature = Signature
                .getInstance(SIGN_ALGORITHMS)
            signature.initSign(priKey)
            signature.update(content.toByteArray(charset))
            val signed: ByteArray = signature.sign()
            Base64.getEncoder().encodeToString(signed)
        } catch (ie: InvalidKeySpecException) {
            throw RsaException(
                "RSA private key format is not correct, check that the PKCS8 format is configured correctly",
                ie
            )
        } catch (e: Exception) {
            throw RsaException(
                "RSAcontent = $content; charset = $charset",
                e
            )
        }
    }

    fun rsaSignSHA1(
        params: Map, privateKey: String,
        charset: Charset = Charsets.UTF_8
    ): String {
        val signContent = getSignContent(params)
        return rsaSignSHA1(signContent, privateKey, charset)
    }

    fun rsaSignSHA256(
        params: Map, privateKey: String,
        charset: Charset = Charsets.UTF_8
    ): String {
        val signContent = getSignContent(params)
        return rsaSignSHA256(
            signContent,
            privateKey,
            charset
        )
    }

    private fun getPublicKeyFromX509(
        keyContent: ByteArray
    ): RSAPublicKey {
        val keyFactory: KeyFactory = KeyFactory.getInstance("RSA")
        val encodedKey = Base64.getDecoder().decode(keyContent)
        return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)) as RSAPublicKey
    }

    private fun getPrivateKeyFromPKCS8(
        keyContent: ByteArray
    ): RSAPrivateKey {
        if (keyContent.isEmpty()) {
            throw RsaException("Key or algorithm cant not be null.")
        }
        val keyFactory: KeyFactory = KeyFactory.getInstance("RSA")
        val key = Base64.getDecoder().decode(keyContent)
        val spec = PKCS8EncodedKeySpec(key)
        return keyFactory.generatePrivate(spec) as RSAPrivateKey
    }


    fun verifySHA256(
        content: String,
        sign: String,
        publicKey: String,
        charset: Charset = Charsets.UTF_8
    ): Boolean {
        return try {
            val pubKey: PublicKey = getPublicKeyFromX509(
                publicKey.toByteArray(Charsets.UTF_8)
            )
            val signature: Signature = Signature
                .getInstance(SIGN_SHA256RSA_ALGORITHMS)
            signature.initVerify(pubKey)
            signature.update(content.toByteArray(charset))
            signature.verify(Base64.getDecoder().decode(sign))
        } catch (e: Exception) {
            e.throwIfNecessary()
            throw RsaException(
                "RSAcontent = $content,sign=$sign,charset = $charset",
                e
            )
        }
    }

    fun verifySHA256(
        context: Map,
        sign: String,
        publicKey: String,
        charset: Charset = Charsets.UTF_8
    ): Boolean {
        val str = getSignContent(context)
        return verifySHA256(str, sign, publicKey, charset)
    }

    fun verifySHA1(
        content: String, sign: String, publicKey: String,
        charset: Charset = Charsets.UTF_8
    ): Boolean {
        return try {
            val pubKey: PublicKey = getPublicKeyFromX509(
                publicKey.toByteArray(Charsets.UTF_8)
            )
            val signature: Signature = Signature
                .getInstance(SIGN_ALGORITHMS)
            signature.initVerify(pubKey)
            signature.update(content.toByteArray(charset))
            signature.verify(Base64.getDecoder().decode(sign))
        } catch (e: Exception) {
            e.throwIfNecessary()
            throw RsaException(
                "RSAcontent = $content,sign=$sign,charset = $charset", e
            )
        }
    }

    fun verifySHA1(
        context: Map,
        sign: String,
        publicKey: String,
        charset: Charset = Charsets.UTF_8
    ): Boolean {
        val str = getSignContent(context)
        return verifySHA1(str, sign, publicKey, charset)
    }



    /**
     * 公钥加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @param charset   字符集,如UTF-8, GBK, GB2312
     * @return 密文内容
     */
    fun encrypt(
        content: String, publicKey: String,
        charset: Charset = Charsets.UTF_8
    ): String {
        return try {
            val pubKey: PublicKey = getPublicKeyFromX509(
                publicKey.toByteArray(Charsets.UTF_8)
            )
            val cipher: Cipher = Cipher.getInstance(ENCRTPY_RSA)
            cipher.init(Cipher.ENCRYPT_MODE, pubKey)
            val data = content.toByteArray(Charsets.UTF_8)
            val inputLen = data.size
            var offSet = 0
            var i = 0
            val bytes = ByteArrayOutputStream().use { out ->
                // 对数据分段加密
                while (inputLen - offSet > 0) {
                    val buffer = if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                        cipher.doFinal(data, offSet,
                            MAX_ENCRYPT_BLOCK
                        )
                    } else {
                        cipher.doFinal(data, offSet, inputLen - offSet)
                    }
                    out.write(buffer, 0, buffer.size)
                    i++
                    offSet = i * MAX_ENCRYPT_BLOCK
                }
                val encryptedData = out.toByteArray()
                Base64.getEncoder().encode(encryptedData)
            }
            bytes.toString(charset)
        } catch (e: Exception) {
            e.throwIfNecessary()
            throw RsaException(
                "EncryptContent = $content,charset = $charset",
                e
            )
        }
    }

    /**
     * 私钥解密
     *
     * @param content    待解密内容
     * @param privateKey 私钥
     * @param charset    字符集,如UTF-8, GBK, GB2312
     * @return 明文内容
     */
    fun decrypt(
        content: String,
        privateKey: String,
        charset: Charset = Charsets.UTF_8
    ): String {
        val keyBytes = privateKey.toByteArray(Charsets.UTF_8)
        return try {
            val priKey = getPrivateKeyFromPKCS8(
                keyBytes
            )
            //填充问题处理, 1024 密钥使用 128 个字节
            //
            val blockSize = priKey.modulus.bitLength() / 8
            val cipher: Cipher = Cipher.getInstance(ENCRTPY_RSA)
            cipher.init(Cipher.DECRYPT_MODE, priKey)
            val bytes = content.toByteArray(charset)
            val encryptedData: ByteArray = Base64.getDecoder().decode(bytes)
            val inputLen = encryptedData.size
            var offSet = 0
            var cache: ByteArray
            var i = 0
            val decryptedData = ByteArrayOutputStream().use { out ->
                // 对数据分段解密
                while (inputLen - offSet > 0) {
                    cache = if (inputLen - offSet > blockSize) {
                        cipher.doFinal(encryptedData, offSet, blockSize)
                    } else {
                        cipher.doFinal(encryptedData, offSet, inputLen - offSet)
                    }
                    out.write(cache, 0, cache.size)
                    i++
                    offSet = i * blockSize
                }
                out.toByteArray()
            }
            decryptedData.toString(Charsets.UTF_8)
        } catch (e: Exception) {
            e.throwIfNecessary()
            throw RsaException(
                "EncodeContent = $content,charset = $charset",
                e
            )
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy