美文网首页Android深入Android
Android中RSA加密工具类示例

Android中RSA加密工具类示例

作者: 静水红阳 | 来源:发表于2021-08-15 19:30 被阅读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示例。

    相关文章

      网友评论

        本文标题:Android中RSA加密工具类示例

        本文链接:https://www.haomeiwen.com/subject/kfsfbltx.html