您的Android密钥安全吗?一招教你安全加固

news2025/1/9 9:54:53

您的Android密钥安全吗?一招教你安全加固


你是否担心你的Android应用中的敏感数据会被披露出去?如果是的话,别担心,你并不是唯一一个有这样担忧的人。在今天的世界里,保护你的应用的URL和密钥免受逆向工程的风险变得比以往任何时候都更加重要。

别担心,它并不像听起来那么无聊!

逆向工程是通过反编译应用程序的代码来提取源代码的过程。坏人可以利用这种方法窃取你应用程序的敏感数据,比如URL和密钥。

但别担心,我们至少有一些方法可以让逆向工程师难以提取出你应用程序的URL和密钥。

本文将向你展示两种方法,帮助你保护应用程序的敏感数据,即CMake和Android密钥库系统。

顺便提一下:我们都知道没有百分之百的方法可以完全防止逆向工程,但这篇文章可以帮助你增加这个过程的难度。

那你还等什么呢?咱们开始吧!

🔐 CMake的工作原理

CMake是一种构建自动化工具,用于为Android创建本地库。它使用一个简单的配置文件来描述构建过程,你可以在该文件中指定源文件、编译器标志以及需要链接到本地库的库文件。

当你完成CMake的配置文件后,可以使用CMake构建工具来生成本地库。该工具会编译源文件,将其与所需的库文件进行链接,从而生成一个本地库文件。

开始使用吧!

1 - 从Android SDK安装CMake
安装Cmake
2 -app/src/main 下。创建一个 C/C++ 文件来存储和访问你的密钥,命名为 native-lib.cpp

注意:为了使该函数在Java/Kotlin代码中可用,函数名称的格式为Java包名_活动名_函数名。

//
// Created by Qamar Safadi on 16/06/2023.
//

#include <jni.h>
#include <string>

extern "C"
jstring
Java_com_qamar_myapplication_MainActivity_secureText(
        JNIEnv* env,
        jobject /* this */) {
    std::string baseURL = "https://test/";
    return env->NewStringUTF(baseURL.c_str());
}

3- 现在我们需要创建我们的CMakeLists,在应用程序上右键点击。

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        # Associated headers in the same location as their source
        # file are automatically included.
        src/main/native-lib.cpp)

4 — 最后一步是通过 build.gradle 将这个本地库与我们的项目连接起来。

   externalNativeBuild {
        cmake {
           path("CMakeLists.txt")
        }
    }

现在同步并刷新您的项目,将您的项目与本地程序库链接起来。

在你的 MainActiviy 中,你可以像下面这样访问你的密钥。

init {
        System.loadLibrary("native-lib")
    }

    external fun secureText(): String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting(secureText())
                }
            }
        }
    }

🔐 Android Keystore System的工作原理

Android Keystore System是一个内置的安全系统,允许您将敏感数据存储在设备上的安全位置。

Keystore系统使用硬件支持的加密密钥来加密您的数据,这使得在没有正确凭据的情况下难以访问。

使用Keystore系统将防止任何攻击者提取这个密钥,因为它使用被称为TEE的特定硬件。

入门

首先,我们将创建Encryptor和Decryptor类,用于处理解密和加密过程。

class Encryptor {
    lateinit var encryption: ByteArray
        private set
    lateinit var iv: ByteArray
        private set

    @Throws(
        UnrecoverableEntryException::class,
        NoSuchAlgorithmException::class,
        KeyStoreException::class,
        NoSuchProviderException::class,
        NoSuchPaddingException::class,
        InvalidKeyException::class,
        IOException::class,
        InvalidAlgorithmParameterException::class,
        SignatureException::class,
        BadPaddingException::class,
        IllegalBlockSizeException::class
    )
    fun encryptText(alias: String, textToEncrypt: String): ByteArray {
        val cipher: Cipher = Cipher.getInstance(TRANSFORMATION)
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias))
        iv = cipher.getIV()
        return cipher.doFinal(textToEncrypt.toByteArray(charset("UTF-8"))).also {
            encryption = it
        }
    }

    @Throws(
        NoSuchAlgorithmException::class,
        NoSuchProviderException::class,
        InvalidAlgorithmParameterException::class
    )
    private fun getSecretKey(alias: String): SecretKey {
        val keyGenerator: KeyGenerator = KeyGenerator
            .getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE)
        keyGenerator.init(
            KeyGenParameterSpec.Builder(
                alias,
                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
            )
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build()
        )
        return keyGenerator.generateKey()
    }

    companion object {
        private const val TRANSFORMATION = "AES/GCM/NoPadding"
        private const val ANDROID_KEY_STORE = "AndroidKeyStore"
    }
}
class Decryptor {
    private var keyStore: KeyStore? = null

    init {
        initKeyStore()
    }

    @Throws(
        KeyStoreException::class,
        CertificateException::class,
        NoSuchAlgorithmException::class,
        IOException::class
    )
    private fun initKeyStore() {
        keyStore = KeyStore.getInstance(ANDROID_KEY_STORE)
        keyStore?.load(null)
    }

    @Throws(
        UnrecoverableEntryException::class,
        NoSuchAlgorithmException::class,
        KeyStoreException::class,
        NoSuchProviderException::class,
        NoSuchPaddingException::class,
        InvalidKeyException::class,
        IOException::class,
        BadPaddingException::class,
        IllegalBlockSizeException::class,
        InvalidAlgorithmParameterException::class
    )
    fun decryptData(alias: String, encryptedData: ByteArray?, encryptionIv: ByteArray?): String {
        val cipher: Cipher = Cipher.getInstance(TRANSFORMATION)
        val spec = GCMParameterSpec(128, encryptionIv)
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec)
        return String(cipher.doFinal(encryptedData))
    }

    @Throws(
        NoSuchAlgorithmException::class,
        UnrecoverableEntryException::class,
        KeyStoreException::class
    )
    private fun getSecretKey(alias: String): SecretKey {
        return (keyStore?.getEntry(alias, null) as KeyStore.SecretKeyEntry).getSecretKey()
    }

    companion object {
        private const val TRANSFORMATION = "AES/GCM/NoPadding"
        private const val ANDROID_KEY_STORE = "AndroidKeyStore"
    }
}

现在在MainActivity中,我们开始使用这些类。

class MainActivity : AppCompatActivity() {
    lateinit var encryptor: Encryptor
    private val SAMPLE_ALIAS = BuildConfig.MY_ALIAS // save your ALIAS key in local.properties for more security 
 
  init {
        encryptText()
    }
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting(decryptText())
                }
            }
        }
    }
      
    private fun encryptText() {
        try {
            encryptor = EnCryptor()
            val encryptedText = encryptor.encryptText(SAMPLE_ALIAS, BuildConfig.SECRET_KEY) // your secret key form local.properties
            Base64.encodeToString(encryptedText, Base64.DEFAULT)
        } catch (e: Exception) {
            Log.e("TAG", e.message, e)
        }
    }
    private fun decryptText():String {
        val deCryptor = Decryptor()
        try {
            val secretKey = deCryptor.decryptData(SAMPLE_ALIAS, encryptor.encryption, encryptor.iv)
            return  secretKey
        } catch (e: Exception) {
            Log.e("TAG", e.message, e)
            return e.message.toString()
        }
    }
}

如何决定使用哪个?

正如您所见,Android密钥库系统比CMake更安全,但使用起来更复杂。CMake不太安全,但使用起来也更简单。

对于您来说,最佳选择将取决于您的具体需求。如果您需要最高级别的安全性,那么Android密钥库系统是最佳选择。如果您需要一个更灵活且更易于使用的解决方案,那么CMake是更好的选择。

别忘了启用R8和资源收缩👇🏻

结论

最后,确保您应用程序的秘密密钥的安全性是非常有趣的一件事。想象一下您将面临的挑战!您需要想出强大的密钥名称和密码,找到安全的存储位置,并使用混淆技术使应用程序代码更难被理解。

这就像一场猫捉老鼠的游戏,您是猫,逆向工程师是老鼠。而且最棒的是,您能够获胜!通过遵循本文中的建议,您可以大大增加逆向工程师获取您的秘密密钥的难度,从而保护应用程序的敏感数据安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/661649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端Vue图片上传组件支持单个文件多个文件上传 自定义上传数量 预览删除图片 图片压缩

前端Vue图片上传组件支持单个文件多个文件上传 自定义上传数量 预览删除图片 图片压缩&#xff0c; 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin?id13099 效果图如下&#xff1a; ## 1.0.0&#xff08;2023-06-18&#xff09; 组件初始化 #### …

三、多层感知机及模型优化

文章目录 前言一、多层感知机1.1 隐藏层1.1.1 什么叫隐藏层1.1.2 为什么需要隐藏层 1.2 激活函数1.2.1 ReLU函数1.2.2 Sigmoid函数1.2.3 tanh函数 1.3 多层感知机的代码实现 二、模型选择、欠拟合和过拟合2.1 训练误差和泛化误差2.2 模型选择2.2.1 模型复杂性2.2.2 验证集2.2.3…

机器学习强基计划9-1:图解匹配追踪(MP)与正交匹配追踪(OMP)算法

目录 0 写在前面1 字典学习2 稀疏表示与稀疏编码3 匹配追踪MP算法4 正交匹配追踪OMP算法 0 写在前面 机器学习强基计划聚焦深度和广度&#xff0c;加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理&#xff1b;“广”在分析多个机器学习模型&#xff…

CSS小技巧之悬停3D发光效果

今天要实现的效果如图所示&#xff0c;鼠标悬停是图片卡片会有3D翻转的效果&#xff0c;且动画过程中还带有发光的效果。类似这种3D悬停效果日常看到的比较多&#xff0c;但是今天实现的这个效果有以下几个亮点&#xff1a; 核心CSS代码不超过10行没有额外的元素&#xff08;只…

STM32 MCO+SPI获取24位模数转换(24bit ADC)高速芯片ADS1271采样数据

STM32 MCOSPI获取24位模数转换&#xff08;24bit ADC&#xff09;高速芯片ADS1271采样数据 STM32大部分芯片只有12位的ADC采样性能&#xff0c;如果要实现更高精度的模数转换如24位ADC采样&#xff0c;则需要连接外部ADC实现。ADS1271是 TI公司一款高速24位Σ-Δ型模数转换器(…

[每周一更]-(第50期):Go的垃圾回收GC

参考文章&#xff1a; https://juejin.cn/post/7111515970669117447https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-garbage-collector/https://colobu.com/2022/07/16/A-Guide-to-the-Go-Garbage-Collector/https://liangyaopei.github.io/2021/01/02/g…

【前端布局篇】浮动、定位、弹性布局,固比固、双飞翼、圣杯布局

一、布局方式介绍 布局模型是基于盒模型基础上进行的拓展&#xff0c;关于布局有流式布局&#xff08;标准的布局&#xff09;&#xff0c;浮动布局、定位布局、flex布局等。 1.1 标准流&#xff08;流动模型&#xff09; 描述&#xff1a;元素按照自己默认的元素类型在页面…

社区问答精选——长安链开发知多少?(6月)

此次整理的内容为5-6月社群内的问答供更多开发者参考&#xff08;社群中部分优质问题连贯性不足未能收录&#xff0c;欢迎点击公众号菜单栏加入社群共同交流&#xff09;。有更多问答在社区issue中描述更为细致&#xff0c;开发者提问前可以先按照关键词进行搜索。欢迎各位开发…

Doris FE启动流程源码解读

FE启动流程分析 Doris中FE主要负责接收和返回客户端请求、元数据以及集群管理、查询计划生成等工作。 本文主要看一下Doris的fe在启动时做了什么。 启动流程分析 启动流程图&#xff1a; 代码路径&#xff1a; doris/fe/fe-core/src/main/java/org/apache/doris/DorisFE.j…

华为云CodeArts Build快速上手编译构建-进阶玩家体验

华为云CodeArts Build编译构建为开发者提供配置简单的混合语言构建平台&#xff0c;实现编译构建云端化&#xff0c;支撑企业实现持续交付&#xff0c;缩短交付周期&#xff0c;提升交付效率。支持编译构建任务一键创建、配置和执行&#xff0c;实现获取代码、构建、打包等活动…

react+antd实现表格封装,可动态控制列显示隐藏。

实现效果 import { Table, Pagination, Button, Dropdown, Checkbox, message } from antd; import { useState, useEffect } from react; import { PicRightOutlined } from ant-design/icons;import ./index.less;const TableComponent (props) > {const powerList JSON…

【方法】Excel表格的“打开密码”不想要了,如何取消?

对于重要的Excel表格&#xff0c;很多小伙伴都会设置“打开密码”&#xff0c;这样就无法随意打开表格&#xff0c;只有输入正确的密码才可以打开。 如果后续表格不再需要保护&#xff0c;每次打开都要输一次密码&#xff0c;这样操作也是很麻烦。 那不想要“打开密码”&…

(5)(5.8) 保存微调和自动微调

文章目录 前言 1 保存微调 2 自动微调 3 保存微调和自动微调的视频演示 4 桌面方法 前言 当然&#xff0c;风对你的旋翼飞机有很大的影响&#xff0c;会把它推来推去。然而&#xff0c;你可能也会发现&#xff0c;在自稳模式下飞行时&#xff0c;即使在无风的环境中&#xff0…

chatgpt赋能python:Python重新编辑引擎优化(SEO)文章

Python重新编辑引擎优化(SEO)文章 介绍 Python是一种多用途的高级编程语言&#xff0c;用于开发网络应用程序&#xff0c;算法&#xff0c;科学计算和数据分析等。 随着越来越多的网站和应用程序采用Python编写&#xff0c;优化Python代码以提高搜索引擎优化(SEO)变得越来越重…

基于html+css的图展示133

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

科技孵化制造蝶变:国际智造节上,群硕获评2023杰出数字化创新企业

论起2023年的热点有哪些&#xff1f;由ChatGPT掀起的智能科技浪潮&#xff0c;绝对是逃不开的话题。 6月16日&#xff0c;以“科技驱动&#xff0c;智造未来”为主题的2023国际智造节&#xff0c;在北京隆重举行。通过此次活动&#xff0c;在数字化领域深耕二十年的群硕软件&a…

K8s Kubectl 技巧集锦

kubectl 是 Kubernetes 的一个命令行管理工具&#xff0c;可用于 Kubernetes 上的应用部署和日常管理。本文列举了 9 个常见的 kubectl 命令&#xff0c;并总结了一些使用技巧&#xff0c;希望可以帮助系统管理员简化管理工作。 一、使用 Kubectl 查询、创建、编辑和删除资源 …

【C数据结构】循环队列_CyclicQueue

目录 循环队列_CyclicQueue 【1】循环队列 【1.1】循环队列的各个接口 【1.2】循环队列初始化 【1.3】循环队列初销毁 【1.4】循环队列插入 【1.5】循环队列删除 【1.6】循环队列获取头位置数据 【1.7】循环队列获取尾位置数据 【1.8】循环队列判满 【1.9】循环队列…

MMOE(Multi-gate Mixture-of-Experts)

1.前提和动机 随着推荐技术的发展&#xff0c;目前越来越多的推荐场景&#xff0c;往往并不是单独的优化一个指标&#xff0c;比如&#xff1a; 视频推荐领域&#xff1a;推荐排序任务不仅需要考虑到用户点击率、完播率&#xff0c;也需要考虑到一些满意度指标&#xff0c;例如…

优秀java实习报告范文5篇

优秀java实习报告范文(一) 一:实习介绍 1)实习题目 学生信息管理系统的设计与开发 2)实习目的 《Java程序设计》课程是电子商务专业的一门专业必修课程&#xff0c;特针对此课程进行为期三周的实践教学&#xff0c;旨在提升本专业学生对此课程中的理论知识的综合应用能力、提高…