Android 加密算法

主要内容

1.加密算法分类
2.常用的加密算法实现

今天主要讲些加密算法的事。
相关代码:https://github.com/GrassQing/AlgorithmUtils
代码的相关内容,就是以下的所有内容。

加密算法分类

加密算法通常有3种分类。
分别是:
1.国际算法,国内加密算法(简称国密)。
2.对称算法,和非对称算法。
3.摘要算法。

1.国际算法

简单的讲就是国际算法由美国的安全局发布,是现今最通用的商用算法,常用的国际算法有DES,3DES,AES,RSA等。这些算法用的地方可就多了,网上的资源也很多。

2.国密

简单的讲就是由国家密码局发布,包含SM1\ SM2\ SM3\ SM4\ SSF33算法。
通常在大部分开发过程中很少会用到国密算法,那是因为时下国密算法大多数用在金融领域,硬件加密方面。

3.对称算法

加密和解密都使用同一把秘钥,这种加密方法称为对称加密,也称为单密钥加密。
如下图所示,简单的讲就是加密方和解密方都持有相同的秘钥,持有相同的加密方式。一旦二者中有一个泄密,加密如同虚设。

Paste_Image.png

常用的对称算法有:DES,3DES,SM4

4.非对称算法

非对称密钥算法是指一个加密算法的加密密钥和解密密钥是不一样的,或者说不能由其中一个密钥推导出另一个密钥。
和对称算法相反,简单的讲就是加密方持有 私钥 对数据进行加密。然后 解密方持有 加密方提供的 公钥进行解密。
对于非对称算法而言:
算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。但是重在安全。

Paste_Image.png

常用的非对称算法有,RSA,SM2

4.摘要算法

摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。
当然,这边有点要注意的是摘要算法是****不可逆的****。而且信息摘要是****随机的****,也就是说某种程度上可能不一样的数据会算出一样的密文,当然这种概率是非常小的。

举个栗子:
A,B通讯:
规定 报文是这样子的:

发送方:json字符串+TOKEN令牌+时间戳的形式+除时间戳外的数据 进行Md5加密后传输过来。
接收方:截取json字符串,进行TOKEN令牌校验,校验服务器时间和传输方时间不超过30分钟,超过无效,不进行处理,同时校验md5值的是否一致。

这个栗子就是我职业生涯过程中经历过的一种校验方式,当时看起来感觉在一定程度上可以避免一些数据被截取利用,现在想想,这种摘要加密,协商的形式还不是较为安全的一种方式(因为你懂的,容易被泄密,也可以称的上是对称的一种加密方式)。
回归正题,上面的MD5加密其实就是摘要算法的一种。常用的还有****SHA,CRC****等。

常用的加密算法实现

常用的加密算法实现,这边主要讲解的是国际加密算法,为啥不讲国密算法?

Paste_Image.png

好吧,今天国密不是主题,反正

Paste_Image.png

好吧,实际上不想拿出来坑你们,自己搞了些,反正一堆问题,我就不拿出来献丑了。
那问题来了,我们讲讲今天的主题。

常用的国际算法如何实现
MD5(摘要算法)

代码如下:

  public static byte[] encryptMD5(byte[] data) throws Exception {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(data);
        return md5.digest();

    }

就这么简单,把数据放进去就可以了。

SHA(摘要算法)

SHA和Md5的代码类似

 /**
     *
     * @param data to be encrypted
     * @param shaN encrypt method,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512
     * @return 已加密的数据
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data, String shaN) throws Exception {

        MessageDigest sha = MessageDigest.getInstance(shaN);
        sha.update(data);
        return sha.digest();

    }

填坑即可。

DES/3DES(对称算法)

简单了解下DES/3DES算法

DES

全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1976 年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),随后在国际上广泛流传开来。

3DES

也叫Triple DES,是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。
它相当于是对每个数据块应用三次DES 加密算法。由于计算机运算能力的增强,原版DES 密码的密钥长度变得容易被暴力破解;3DES 即是设计用来提供一种相对简单的方法,即通过增加DES 的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。

DES 算法代码实现
    public static final String ALGORITHM = "DES";
    public static byte[] decrypt(byte[] data, String key) throws Exception {
        Key k = toKey(decryptBASE64(key));

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, k);

        return cipher.doFinal(data);
    }

    public static byte[] encrypt(byte[] data, String key) throws Exception {
        Key k = toKey(decryptBASE64(key));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, k);

        return cipher.doFinal(data);
    }
    public static byte[] decryptBASE64(String key) throws Exception {
        return Base64.decode(key, Base64.DEFAULT);
    }

    public static String encryptBASE64(byte[] key) throws Exception {
           return Base64.encodeToString(key, Base64.DEFAULT);
    }
3DES 算法代码实现

3Des的算法有很多种,然后现在开发中很少用到这个加密方式,用到最多的基本是金融方面,例如银联,pos机等,主要是用来加密那些交易的联机密码等。
所以,还是有必要认真的说下这方面的东西。
****首先****
3des加密有分为普通的,单倍长加密,双倍长加密
这边由于篇幅有限,我就上些普通的加密方式
加密


    /**
     * 3des加密
     *
     * @param key  密钥
     * @param data 明文数据 16进制且长度为16的整数倍
     * @return 密文数据
     */
    public static byte[] Union3DesEncrypt(byte key[], byte data[]) {
        try {
            byte[] k = new byte[24];

            int len = data.length;
            if (data.length % 8 != 0) {
                len = data.length - data.length % 8 + 8;
            }
            byte[] needData = null;
            if (len != 0)
                needData = new byte[len];

            for (int i = 0; i < len; i++) {
                needData[i] = 0x00;
            }
            System.arraycopy(data, 0, needData, 0, data.length);
            if (key.length == 16) {
                System.arraycopy(key, 0, k, 0, key.length);
                System.arraycopy(key, 0, k, 16, 8);
            } else {
                System.arraycopy(key, 0, k, 0, 24);
            }
            KeySpec ks = new DESedeKeySpec(k);
            SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
            SecretKey ky = kf.generateSecret(ks);
            Cipher c = Cipher.getInstance(TriDes);
            c.init(Cipher.ENCRYPT_MODE, ky);
            return c.doFinal(needData);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 3des解密
     *
     * @param key  密钥
     * @param data 密文数据 16进制且长度为16的整数倍
     * @return 明文数据
     */
    public static byte[] Union3DesDecrypt(byte key[], byte data[]) {
        try {
            byte[] k = new byte[24];

            int len = data.length;
            if (data.length % 8 != 0) {
                len = data.length - data.length % 8 + 8;
            }
            byte[] needData = null;
            if (len != 0)
                needData = new byte[len];

            for (int i = 0; i < len; i++) {
                needData[i] = 0x00;
            }

            System.arraycopy(data, 0, needData, 0, data.length);

            if (key.length == 16) {
                System.arraycopy(key, 0, k, 0, key.length);
                System.arraycopy(key, 0, k, 16, 8);
            } else {
                System.arraycopy(key, 0, k, 0, 24);
            }
            KeySpec ks = new DESedeKeySpec(k);
            SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
            SecretKey ky = kf.generateSecret(ks);

            Cipher c = Cipher.getInstance(TriDes);
            c.init(Cipher.DECRYPT_MODE, ky);
            return c.doFinal(needData);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

****最后****
剩下的单倍长和双倍长加密,放到我的github上的工程,有需要着请自行前往下载。

AES(对称算法)

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael 加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001 年11 月26 日发布于FIPS PUB 197,并在2002 年5 月26 日成为有效的标准。2006 年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

代码也比较的简单。

    public static final String ALGORITHM = "AES";
   //解密
    public static byte[] decrypt(byte[] data, String key) throws Exception {
        Key k = toKey(decryptBASE64(key));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, k);
        return cipher.doFinal(data);
    }
    //加密
    public static byte[] encrypt(byte[] data, String key) throws Exception {
        Key k = toKey(decryptBASE64(key));
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, k);
        return cipher.doFinal(data);
    }

RSA(非对称算法)

RSA 是目前非常安全的一种算法,主要是由于其算法的特性导致的。
具体rsa如何如何的安全,请自行百度脑补。
rsa代码实现关键是如何进行分段加密或者解密,rsa加密或者解密的数据长度和秘钥的位数有直接的联系,所以经常会在开发过程中遇到这些解密数据过长的问题。

首选是rsa秘钥的长度,目前主流可选值:1024、2048、3072、4096...
秘钥越长解密和加密效率越低,加密长度越来越长。
加密长度规则:长度/8-11
例如:128字节(1024bits)-减去11字节正好是117字节。

以下是,rsa的加密流程:
(1) 实现者寻找出两个大素数p和q
(2) 实现者计算出n=pq 和φ(n)=(p-1)(q-1)
(3) 实现者选择一个随机数e (0<e<></e<>
(4) 实现者使用辗转相除法计算d=e-1(modφ(n))
(5) 实现者在目录中公开n和e作为公钥
有兴趣的可以自行了解下其原理。

****不正常版的加密,解密方式****

 /**
     * 解密<br>
     * 用公钥解密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String key)
            throws Exception {
        // 对密钥解密
        byte[] keyBytes = Base64.decryptBASE64(key);

        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }

    /**
     * 加密<br>
     * 用公钥加密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String key)
            throws Exception {
        // 对公钥解密
        byte[] keyBytes = Base64.decryptBASE64(key);

        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }

一般来说,rsa的加解密方式是这样的,如果是私钥加密,那么必须是公钥解密,相反公钥加密,私钥就是用来解密的。
****以上的示例代码是有缺陷的。****
上面的代码针对加密数据不长的情况才有效果,如果加密的数据超过规则,则会发生错误,必须要进行分段加密,分段解密。
合理的代码如下:

/** *//**
     * RSA最大加密明文大小,1024的秘钥对
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** *//**
     * RSA最大解密密文大小,根据实际秘钥对进行替换
     */
    private static final int MAX_DECRYPT_BLOCK = 256;

 /** *//**
     * <p>
     * 公钥解密
     * </p>
     *
     * @param
     * @param publicKey 公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKeySort(byte[] encryptedData1, String publicKey)
            throws Exception {
        byte[] encryptedData=Base64.decode(encryptedData1,Base64.DEFAULT);
        byte[] keyBytes =publicKey.trim().getBytes();
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decode(keyBytes, Base64.DEFAULT));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
        //
        LoggerUtil.loge("TAG",keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        byte[] temp = new byte[MAX_DECRYPT_BLOCK];
       // cache = cipher.doFinal(encryptedData);
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                System.arraycopy(encryptedData, offSet, temp, 0, MAX_DECRYPT_BLOCK);
//                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                cache = cipher.doFinal(temp);
            } else {
                byte[] temp1 = new byte[inputLen - offSet];
                System.arraycopy(encryptedData, offSet, temp1, 0, inputLen - offSet);
//                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                cache = cipher.doFinal(temp1);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

 /** *//**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKeySort(byte[] data, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

此处省略一大坨代码,详细去我的github工程下载。

最后

附上地址:
https://github.com/GrassQing/AlgorithmUtils

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 本文主要介绍移动端的加解密算法的分类、其优缺点特性及应用,帮助读者由浅入深地了解和选择加解密算法。文中会包含算法的...
    苹果粉阅读 11,459评论 5 29
  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 3,005评论 0 14
  • 这篇文章主要讲述在Mobile BI(移动商务智能)开发过程中,在网络通信、数据存储、登录验证这几个方面涉及的加密...
    雨_树阅读 2,331评论 0 6
  • 随着对于安全度的不断要求,对于数据加解密与破解之间的斗争,加解密的方式也在不断发生着变化,来看看现在流行的一些加解...
    zhouhao_180阅读 2,063评论 1 12
  • 关于《跃迁》的读书笔记 第一点就是关于局与破局,我们很多人都活在一个又一个局里,古典老师举了个非洲草原的例子,这个...
    Ruth李阅读 380评论 0 0