纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

Android安全防护之加密算法 详解Android安全防护之加密算法

handsome黄   2021-06-08 我要评论
想了解详解Android安全防护之加密算法的相关内容吗handsome黄在本文为您仔细讲解Android安全防护之加密算法的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Android,安全防护,Android,加密算法下面大家一起来学习吧。

摘要

也许有些开发者或者企业觉得。我们公司的app数据量这些少会有那个黑客吃饱了没事做来破解啊。又不是支付宝或者其他那些用户量很多的应用。如果是这样想的话那只能说目光短浅了。

Android应用常用的加密算法

如果说按加密的内容是否可以还原可以分为可逆加密和非可逆加密。

非可逆加密:也就是说加密后的数据是不能还原成原来的数据。比如MD5加密 加密一个密码:123456 加密后成: afabsbfbabf437hfbbff73(结果并不一定是这个只是举例)。也就是说加密后的结果afabsbfbabf437hfbbff73是不能够在解密出123456这个值的。

可逆加密:可逆加密有一个公钥和一个私钥通过公钥进行数据的加密通过私钥进行解密。代表有:RSAAES。

对称加密和非对称加密:可逆加密根据其使用加解密是否使用同一个密钥又分为对称加密(加解密使用同一个密钥)和非对称加密(加解密的密钥分开)

MD5

MD5的特点:

1、压缩性:任意长度的数据算出来的MD5值的长度都是固定。

2、容易计算性:从原始数据计算出MD5值是很容易的。

3、抗修改性:愿数据只要有一点点的改动得到的MD5差别都是很大的。

4、强抗碰撞性:从原数据计算出来的MD5想要找到一个具有相同的MD5,非常难。

MD5的应用场景:

1、一致性验证(比如下载某个文件不知道文件是否下载完成可以MD5进行校验。加密文件比较耗时需要放到子线程中)

2、密码的存储(如登陆注册这些账号密码会保存到sp中直接就保存到账号密码的MD5值就好了。这样也可以避免服务器权限者知道这个密码)

MD5的简单使用

先写一个MD5的工具类

package com.example.huangjialin.md5test;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Utils {

    public static String md5(String content) {
        byte[] hash = null;
        try {
            hash = MessageDigest.getInstance("MD5").digest(content.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        StringBuilder stringBuilder = new StringBuilder(hash.length * 2);
        for (byte b: hash) {
            if ((b & 0xFF) < 0x10){
                stringBuilder.append("0");

            }
            stringBuilder.append(Integer.toHexString(b & 0xFF));

        }
        return stringBuilder.toString();
    }

}

简单的解释一下上面的首先是通过MessageDigest.getInstance(“MD5”)来获取到MessageDigest这个类这个类是java自带的一个加密类然后通过调用digest()方法来的获取到加密后的字节数组。该方法传入的参数是byte[] input 所以还需要将字符串转化为byte[]。得到加密后的字节数组以后将他们转换成16禁止的字符串然后拼接起来就可以了。

然后直接调用:

/**
* MD5加密
*/
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String md5_123456abc = Utils.md5("123456abc");
        String md5_huangjialin = Utils.md5("huangjialin");
        Log.i("huangjialin","    md5_123456abc算出的MD5值是:    " + md5_123456abc);
        Log.i("huangjialin","    md5_huangjialin算出的MD5值是:   " + md5_huangjialin);
    }
});

得出的结果:

09-20 15:33:12.208 7352-7352/com.example.huangjialin.md5test I/huangjialin:     md5_123456abc算出的MD5值是:    df10ef8509dc176d733d59549e7dbfaf

09-20 15:33:12.208 7352-7352/com.example.huangjialin.md5test I/huangjialin:     md5_huangjialin算出的MD5值是:   08e768954478c8669619d7d087db0070

这里说一句题外话:Log输出日志有很多种如Log.i();Log.d()等等但是现在有些手机厂商直接就把等级较低的日志给屏蔽掉所以有些日志输出在有些手机可以看到有些手机没有看到。解决办法就是换输出等级较高的就OK了。

RSA

RSA是现在比较流行的一种非对称加密的它需要一对密钥(公钥和私钥)公钥进行加密私钥进行解密。

RSA的加密原理

1、随机选择两个大的质数P和QP不等于Q计算出结果:N = P*Q;

2、选择一个大于1小于N的自然数EE必须和(P-1)*(Q-1)互素。

3、用公式计算出D:D*E = mod(P-1)*(Q-1)

4、销毁P和Q

最终得到的NE就是公钥D就是私钥了。

RSA加解密步骤

1、甲方生成密钥对(公钥和私钥公钥用来加密数据私钥自己保留用来解密数据)

2、甲方使用私钥加密数据然后用私钥对加密后的数据签名并把这些放送给乙方乙方使用公钥签名来验证带解密数据是否有效如果有效就使用公钥对数据进行解密

3、乙方使用公钥加密数据向甲方发送经过加密后的数据甲方或者加密数据后就可以通过私钥进行解密了。

RSA使用场景

项目中一些敏感的数据比如SFZ号银行卡等相关信息可通过加密后在传给服务器服务器使用私钥进行解密。

RSA密钥对生成

RSA的密钥对生成方式有两种

/*
      初始化KeyPairGenerator类并获取到公钥和私钥
    */
    byte[] publicKeyByte;
    byte[] prvateKtyByte;

    public void getKey() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(“RSA”);//KeyPairGenerator类是java专门提供生成密钥对的一个类。
            keyPairGenerator.initialize(1024); //设置密钥对的大小
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();//获取私钥
            PublicKey publicKey = keyPair.getPublic();//获取公钥
            prvateKtyByte = privateKey.getEncoded();//私钥对应的字节数组
            publicKeyByte = publicKey.getEncoded(); //公钥对应的字节数组

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

当然上面这种生成密钥对的方式基本很少会在项目中使用使用用得比较多的还是第二中方式。

第二种是通过OpenSSl工具生成密钥对

这种生成密钥对的方式需要安装OpenSSl。这里就不说具体怎么安装了。这里简单的说一下生成密钥对所需要的一些命令

使用命令生成私钥:

genrsa -out rsa_private_key.pem 1024

这条命令是让openssl随机生成一份私钥长度为1024

使用命令生成公钥:

rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

命令成功以后就会在openSSL下的bin目录下生成公钥和私钥然后就可以进行加密和解密了。

加密

/**
     * 加密
     */


    @RequiresApi(api = Build.VERSION_CODES.O)
    public byte[] encryption(String content) {
        byte[] result = null;
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyByte);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            result = cipher.doFinal(content.getBytes());
            Log.i("huangjialin", "---->  " + Base64.getEncoder().encodeToString(result));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return result;
    }

解密

/**
     * 解密
     */

    @RequiresApi(api = Build.VERSION_CODES.O)

    public void decryption() {

        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA");
            //私钥需要通过PKCS8EncodedKeySpec来读取
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(prvateKtyByte);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            //生成私钥
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            //String content = "123456";
            byte[] input = encryption("123456");
            byte[] result = cipher.doFinal(input);
            Log.i("huangjialin", "--解密-->  " + new String(result));
            //Assert.assertTrue(content.equals(new String(result)));


        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }


    }

当然上面的代码是我写测试用的真正项目中还得封装好把它弄成工具类进行调用。

AES

AES是一个对称加密也就是说使用AES进行加密和解密他们使用的密钥都是一样的。AES加密算法是密码学中的高级加密标准又称Rijndael加密法是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES已经被多方分析并使用。同时AES他的算法加密强度大执行效率很高。

AES使用场景

1、由于AES是对称加密加解密都是使用同一个密钥所以说在项目中一些敏感的数据需要保存到本地。可以先同AES的密钥进行加密需要用的使用将数据取出来再进行解密。

2、可以进行对一些敏感数据进行加密然后在传递给服务器。

AES使用

在Android7.0之前可以这样获取到密钥

private SecretKey generateKey(String seed) throws Exception {
        // 获取秘钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        // 通过种子初始化
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "Crypto");

        secureRandom.setSeed(seed.getBytes("UTF-8"));
        keyGenerator.init(128, secureRandom);
        // 生成秘钥并返回
        return keyGenerator.generateKey();
    }

但是在Android7.0之后就不支持了移除了Crypto。当然也这种获取密钥方式在7.0之后Google也给出了解决方案但是官方并不建议这样来获取。具体的可以看这里。https://android-developers.googleblog.com/2016/06/security-crypto-provider-deprecated-in.html

官方给出的是另一种方式并不需要获取密钥而是定义密码的形式。

package com.example.huangjialin.md5test;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class MainActivity extends AppCompatActivity {
    private EditText edittext;
    private Button button, jiami, jiemi;
    private TextView textView;
    private SecretKey secretKey;
    private byte[] bytes;
    private String content = "huangjialin,我是要加密的数据";
    String password = "huangji黄家磷";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        edittext = findViewById(R.id.edittext);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textview);
        jiami = findViewById(R.id.jiami);
        jiemi = findViewById(R.id.jiemi);

        Log.i("huagjialin", "--加密的数据-- > " + content);

        /**
         * 获取密钥
         */
       /* button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    secretKey = generateKey("huangjiain");
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });*/


        /**
         * 加密
         */

        jiami.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    bytes = encrypt(content, password);
                    String str = new String(bytes);
                    Log.i("huagjialin", "--加密后的数据-- > " + Base64.decode(str,Base64.DEFAULT));
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });

        /**
         * 解密
         */

        jiemi.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    byte[] by = decrypt(bytes, password);
                    String string = new String(by);
                    Log.i("huagjialin", "--解密后的数据-- > " + string);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });


    }

    /**
     * 另一种加密形式
     */
    private byte[] encrypt(String content, String password) throws Exception {
        // 创建AES秘钥
        SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES/CBC/PKCS5PADDING");
        // 创建密码器
        Cipher cipher = Cipher.getInstance("AES");
        // 初始化加密器
        cipher.init(Cipher.ENCRYPT_MODE, key);
        // 加密
        return cipher.doFinal(content.getBytes("UTF-8"));
    }


    /**
     * 解密
     */
    private byte[] decrypt(byte[] content, String password) throws Exception {
        // 创建AES秘钥
        SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES/CBC/PKCS5PADDING");
        // 创建密码器
        Cipher cipher = Cipher.getInstance("AES");
        // 初始化解密器
        cipher.init(Cipher.DECRYPT_MODE, key);
        // 解密
        return cipher.doFinal(content);
    }

}

09-20 21:12:36.394 15933-15933/com.example.huangjialin.md5test I/huagjialin: --加密的数据-- > huangjialin,我是要加密的数据

09-20 21:12:39.561 15933-15933/com.example.huangjialin.md5test I/huagjialin: --加密后的数据-- > [B@d62495e

09-20 21:12:41.829 15933-15933/com.example.huangjialin.md5test I/huagjialin: --解密后的数据-- > huangjialin,我是要加密的数据


相关文章

猜您喜欢

  • vue引入iconfont vue引入iconfont图标库的优雅实战记录

    想了解vue引入iconfont图标库的优雅实战记录的相关内容吗Kay_在本文为您仔细讲解vue引入iconfont的相关知识和一些Code实例欢迎阅读和指正我们先划重点:vue引入iconfont,vue引入iconfont.js,vue引入第三方js文件下面大家一起来学习吧。..
  • go处理表单输入 go web 处理表单的输入的说明

    想了解go web 处理表单的输入的说明的相关内容吗chengqiuming在本文为您仔细讲解go处理表单输入的相关知识和一些Code实例欢迎阅读和指正我们先划重点:go处理表单输入,go表单输入下面大家一起来学习吧。..

网友评论

Copyright 2020 www.Shellfishsoft.com 【贝软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式