Android深入Android

Android中RSA加密工具类示例

2021-08-15  本文已影响0人  静水红阳

概述

RSA是一种比较常见的非对称加密算法,需要有着两个秘钥:公钥和私钥。
公钥和私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能够解密;如果用私钥对数据进行加密,那么只有用对应的公钥才能解密。
因为加密和解密使用的是两个不同的秘钥,所以这种算法叫做非对称加密算法。
RSA的算法原理在此不再陈述,本文注重于如何在Android中调用这种算法对数据进行加密和解密。

代码实现

class RSACipherUtil {
    private var publicKey: PublicKey?
    private var privateKey: PrivateKey?

    val KEY_ALGORITHM = "RSA"
    private val PUBLIC_KEY = "RSAPublicKey"
    private val PRIVATE_KEY = "RSAPrivateKey"
    val SIGNATURE_ALGORITHM = "MD5withRSA"

        //公钥和私钥Base64字符串
    var publicKeyString = ""
    var privateKeyString = ""
    /**
     * RSA最大加密明文大小
     */
    private val MAX_ENCRYPT_BLOCK = 117

    /**
     * RSA最大解密密文大小
     */
    private val MAX_DECRYPT_BLOCK = 128

    private val keySize = 1024
    private val seedStr = "test"

    init {
        initKey()
        publicKey = getPublicKey(publicKeyString)
        privateKey = getPrivateKey(privateKeyString)
    }

    /**
     * 初始化秘钥
     */
    private fun initKey() {
        //2,通过秘钥对生成器KeyPairGenerator 生成公钥和私钥
        var keyGen = KeyPairGenerator.getInstance(KEY_ALGORITHM)
        keyGen.initialize(keySize, SecureRandom(seedStr.toByteArray()))
        //使用公钥进行加密,私钥进行解密(也可以反过来使用)
        val keyPair = keyGen.generateKeyPair()
        publicKey = keyPair.public
        privateKey = keyPair.private
        var privateEncoded = privateKey?.encoded
        var publicEncoded = publicKey?.encoded
        //生成公钥和私钥64编码字符串
        var publicKey64 = Base64.encodeToString(publicEncoded, Base64.NO_WRAP)
        var privateKey64 = Base64.encodeToString(privateEncoded, Base64.NO_WRAP)
        LogUtil.instance.d("公钥:" + publicKey64)
        LogUtil.instance.d("私钥:" + privateKey64)
        publicKeyString = publicKey64
        privateKeyString = privateKey64
    }

    /**
     * 保存秘钥到文件进行存储
     */
    private fun saveKeyToFile() {
        var oosPublic: ObjectOutputStream? = null
        var oosPrivate: ObjectOutputStream? = null
        try {
            oosPublic = ObjectOutputStream(FileOutputStream(PUBLIC_KEY))
            oosPrivate = ObjectOutputStream(FileOutputStream(PRIVATE_KEY))
            oosPublic.writeObject(publicKey)
            oosPrivate.writeObject(privateKey)
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            oosPublic?.close()
            oosPrivate?.close()
        }
    }

    /**
     * 根据字符串生成私钥
     * @param dataString:Base64转码后的私钥字符串
     */
    private fun getPrivateKey(dataString: String): PrivateKey {
        val decode = Base64.decode(dataString, Base64.NO_WRAP)
        val pkcs8EncodedKeySpec =
            PKCS8EncodedKeySpec(decode)
        val kf =
            KeyFactory.getInstance(KEY_ALGORITHM)
        return kf.generatePrivate(pkcs8EncodedKeySpec)
    }

    /**
     * 根据字符串生成公钥
     * @param dataString:Base64转码后的公钥字符串
     */
    private fun getPublicKey(dataString: String): PublicKey {
        val decode = Base64.decode(dataString, Base64.NO_WRAP)
        //      PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode); //java底层 RSA公钥只支持X509EncodedKeySpec这种格式
        val x509EncodedKeySpec =
            X509EncodedKeySpec(decode)
        val kf =
            KeyFactory.getInstance(KEY_ALGORITHM)
        return kf.generatePublic(x509EncodedKeySpec)
    }

    //************************加密解密**************************
    /**
     * 加密
     * 使用私钥加密
     */
    /**
     * 加密
     * @param data
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws InvalidKeyException
     * @throws IOException
     */
    @Throws(
        NoSuchAlgorithmException::class,
        InvalidKeySpecException::class,
        NoSuchPaddingException::class,
        IllegalBlockSizeException::class,
        BadPaddingException::class,
        InvalidKeyException::class,
        IOException::class
    )
    fun encrypt(data: String): String? {
        val ci =
            Cipher.getInstance(KEY_ALGORITHM)
        ci.init(Cipher.ENCRYPT_MODE, privateKey)
        val bytes = data.toByteArray()
        val inputLen = bytes.size
        var offLen = 0 //偏移量
        var i = 0
        val bops = ByteArrayOutputStream()
        while (inputLen - offLen > 0) {
            var cache: ByteArray?
            cache = if (inputLen - offLen > MAX_ENCRYPT_BLOCK) {
                ci.doFinal(bytes, offLen, MAX_ENCRYPT_BLOCK)
            } else {
                ci.doFinal(bytes, offLen, inputLen - offLen)
            }
            bops.write(cache)
            i++
            offLen = MAX_ENCRYPT_BLOCK * i
        }
        bops.close()
        val encryptedData = bops.toByteArray()
//        return Base64.getEncoder().encodeToString(encryptedData)
        return Base64.encodeToString(encryptedData, Base64.NO_WRAP)

    }


    /**
     * 解密
     * 使用公钥解密
     * @param data
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws NoSuchPaddingException
     * @throws InvalidKeySpecException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws IOException
     */
    @Throws(
        NoSuchAlgorithmException::class,
        InvalidKeyException::class,
        NoSuchPaddingException::class,
        InvalidKeySpecException::class,
        IllegalBlockSizeException::class,
        BadPaddingException::class,
        IOException::class
    )
    fun decrypt(data: String?): String? {
        val ci =
            Cipher.getInstance(KEY_ALGORITHM)
        ci.init(Cipher.DECRYPT_MODE, publicKey)
        val bytes = Base64.decode(data, Base64.NO_WRAP)
        val inputLen = bytes.size
        var offLen = 0
        var i = 0
        val byteArrayOutputStream = ByteArrayOutputStream()
        while (inputLen - offLen > 0) {
            var cache: ByteArray? = if (inputLen - offLen > MAX_DECRYPT_BLOCK) {
                ci.doFinal(bytes, offLen, MAX_DECRYPT_BLOCK)
            } else {
                ci.doFinal(bytes, offLen, inputLen - offLen)
            }
            byteArrayOutputStream.write(cache)
            i++
            offLen = MAX_DECRYPT_BLOCK * i
        }
        byteArrayOutputStream.close()
        val byteArray = byteArrayOutputStream.toByteArray()
        return String(byteArray)
    }

    companion object {
        val instance by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { RSACipherUtil() }
    }
}

注意点

1. 一次性加密数据的长度有限

RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错

javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes

所以RSA中需要有分段加密和解密,如上述示例代码所示。

//一次性加密数据的长度不能大于117 字节
private static final int ENCRYPT_BLOCK_MAX = 117;
//一次性解密的数据长度不能大于128 字节
private static final int DECRYPT_BLOCK_MAX = 128;
2. 加密速度较慢

非对称加密一般不会单独拿来使用,他并不是为了取代对称加密而出现的,非对称加密速度比对称加密慢很多,极端情况下会慢1000 倍,所以一般不会用来加密大量数据,通常我们经常会将对称加密和非对称加密两种技术联合起来使用,例如用非对称加密来给称加密里的秘钥进行加密(即秘钥交换)。

总结

RSA加密代码Demo示例。

上一篇下一篇

猜你喜欢

热点阅读