重拾Android之路(二十二)算法和加密

主要整理了Android中所使用的算法和加密,包括MD5、SHA、DES、AES、RSA等

数字签名

数字签名主要用到了非对称密钥加密技术与数字摘要技术。数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。 如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过.

因此数字签名能够验证信息的完整性。 数字签名是个加密的过程,数字签名验证是个解密的过程。

常见的消息数字摘要算法

MD5

MD5消息摘要算法是一种广泛使用的密码散列函数,可以产生一个128位的散列值,用于确保信息完整一致。
MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式 (也就是把一个任意长度的字节串变换成一定长的十六进制数字串)
特点:

  • 压缩性: 任意长度的数据,算出的MD5值长度都是固定的。
  • 容易计算: 从原数据计算出MD5值很容易。
  • 抗修改性: 对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 强抗碰撞: 已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

实现:
利用JDK提供的java.security.MessageDiges类即可实现MD5的计算

package com.paulniu.demo4java;

import java.security.MessageDigest;

public class Demo4Java4MD5 {

    public static void main(String[] args) {
        System.out.println(getMD5Code("hello world!"));
    }


    public static String getMD5Code(String ss) {
        String md5Str = "";
        try {
            // 创建MD5消息方法摘要
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] bytes = digest.digest(ss.getBytes());
            md5Str = byte2Hex(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5Str;
    }

    /**
     * 将2进制改为16进制
     *
     * @param bytes
     * @return
     */
    public static String byte2Hex(byte[] bytes) {
        StringBuffer str = new StringBuffer();
        int temp;
        try {
            for (int i = 0; i < bytes.length; i++) {
                temp = bytes[i];
                if (temp < 0) {
                    temp += 256;
                }
                if (temp < 16) {
                    str.append("0");
                }
                str.append(Integer.toHexString(temp));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str.toString();
    }

}

运算结果如下
在这里插入图片描述
注意:

static MessageDigest getInstance(String algorithm)//返回实现指定摘要算法的MessageDigest对象

byte[] digest(byte[] input)//使用指定的字节数组对摘要执行最终更新,然后完成摘要计算。

同时还存在一种不使用JDK提供的类,自己实现,可能会比较麻烦

package com.paulniu.demo4java;

/**
 * 不适用JDK提供的方法
 */
public class MD5 {

    /*
     *四个链接变量
     */
    private final int A=0x67452301;
    private final int B=0xefcdab89;
    private final int C=0x98badcfe;
    private final int D=0x10325476;
    /*
     *ABCD的临时变量
     */
    private int Atemp,Btemp,Ctemp,Dtemp;

    /*
     *常量ti
     *公式:floor(abs(sin(i+1))×(2pow32)
     */
    private final int K[]={
            0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
            0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
            0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
            0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
            0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
            0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
            0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
            0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
            0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
            0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
            0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
            0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
            0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};
    /*
     *向左位移数,计算方法未知
     */
    private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
            12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
            4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
            15,21,6,10,15,21,6,10,15,21,6,10,15,21};


    /*
     *初始化函数
     */
    private void init(){
        Atemp=A;
        Btemp=B;
        Ctemp=C;
        Dtemp=D;
    }
    /*
     *移动一定位数
     */
    private    int    shift(int a,int s){
        return(a<<s)|(a>>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位
    }
    /*
     *主循环
     */
    private void MainLoop(int M[]){
        int F,g;
        int a=Atemp;
        int b=Btemp;
        int c=Ctemp;
        int d=Dtemp;
        for(int i = 0; i < 64; i ++){
            if(i<16){
                F=(b&c)|((~b)&d);
                g=i;
            }else if(i<32){
                F=(d&b)|((~d)&c);
                g=(5*i+1)%16;
            }else if(i<48){
                F=b^c^d;
                g=(3*i+5)%16;
            }else{
                F=c^(b|(~d));
                g=(7*i)%16;
            }
            int tmp=d;
            d=c;
            c=b;
            b=b+shift(a+F+K[i]+M[g],s[i]);
            a=tmp;
        }
        Atemp=a+Atemp;
        Btemp=b+Btemp;
        Ctemp=c+Ctemp;
        Dtemp=d+Dtemp;

    }
    /*
     *填充函数
     *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64)
     *填充方式为先加一个0,其它位补零
     *最后加上64位的原来长度
     */
    private int[] add(String str){
        int num=((str.length()+8)/64)+1;//以512位,64个字节为一组
        int strByte[]=new int[num*16];//64/4=16,所以有16个整数
        for(int i=0;i<num*16;i++){//全部初始化0
            strByte[i]=0;
        }
        int    i;
        for(i=0;i<str.length();i++){
            strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序
        }
        strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1
        /*
         *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位
         */
        strByte[num*16-2]=str.length()*8;
        return strByte;
    }
    /*
     *调用函数
     */
    public String getMD5(String source){
        init();
        int strByte[]=add(source);
        for(int i=0;i<strByte.length/16;i++){
            int num[]=new int[16];
            for(int j=0;j<16;j++){
                num[j]=strByte[i*16+j];
            }
            MainLoop(num);
        }
        return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp);

    }
    /*
     *整数变成16进制字符串
     */
    private String changeHex(int a){
        String str="";
        for(int i=0;i<4;i++){
            str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(' ', '0');

        }
        return str;
    }
    /*
     *单例
     */
    private static MD5 instance;
    public static MD5 getInstance(){
        if(instance==null){
            instance=new MD5();
        }
        return instance;
    }

    private MD5(){};

    public static void main(String[] args){
        String str=MD5.getInstance().getMD5("hello world!");
        System.out.println(str);
    }

}

运算结果如下
在这里插入图片描述

SHA1

SHA1是一种被广泛使用的密码散列函数,可以产生一个128位的散列值,确保传输信息的一致性。
对于长度小于2^64位的消息,SHA1会产生一个160位(40个字符)的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。

特性:

  • 不可以从消息摘要中复原信息;
  • 两个不同的消息不会产生同样的消息摘要,(但会有1x10 ^ 48分之一的机率出现相同的消息摘要,一般使用时忽略)。

实现:
通过JDK提供的类java.security.MessageDigest实现SHA1算法

package com.paulniu.demo4java.sha1;

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

public class Demo4Java4SHA1 {

    public static void main(String[] args) {

        System.out.println();

    }

    public static String getSHA1(String str) {
        if (str == null || str.length() == 0) {
            return "";
        }
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            //创建SHA1算法消息摘要对象
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            //使用指定的字节数组更新摘要。
            mdTemp.update(str.getBytes("UTF-8"));
            //生成的哈希值的字节数组
            byte[] md = mdTemp.digest();
            //SHA1算法生成信息摘要关键过程
            int j = md.length;
            char[] buf = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "0";
    }

}

运算结果如下:
在这里插入图片描述

加密算法

加密技术包含两个元素:加密算法和密钥
加密算法是将普通的文本(或者可以理解的信息)与一串数字(密钥)的结合,产生不可理解的密文的步骤。
密钥是用来对数据进行编码和解码的一种算法。
在安全保密中,可通过适当的密钥加密技术和管理机制来保证网络的信息通讯安全。

密钥加密技术的密码体制分为对称密钥体制和非对称密钥体制两种。相应地,对数据加密的技术分为两类,即对称加密(私人密钥加密)和非对称加密(公开密钥加密)。

对称加密以数据加密标准(DES,Data Encryption Standard)算法为典型代表,非对称加密通常以RSA(Rivest Shamir Adleman)算法为代表。

对称加密的加密密钥和解密密钥相同。非对称加密的加密密钥和解密密钥不同,加密密钥可以公开而解密密钥需要保密

对称加密

加密密钥和解密密钥相同的加密算法
对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据加密标准(DES), 另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,而且对计算机功能要求也没有那么高。IDEA加密标准由PGP(Pretty Good Privacy)系统使用。

DES

DES即数据加密标准,是一种使用密钥加密的块算法

package com.paulniu.demo4java.des;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
/**
 * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
 * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
 * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。
 * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数
 */
public class Demo4Java4DES {

    public static void main(String[] args) {
        // 待加密内容
        String str = "hello world!";
        // 密码,长度要是8的倍数
        String password = "12345678";

        byte[] result;
        try {
            result = encrypt(str.getBytes(), password);
            System.out.println("加密后:" + result);
            byte[] decryResult = decrypt(result, password);
            System.out.println("解密后:" + new String(decryResult));
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    // 直接将如上内容解密

    /**
     * 加密
     *
     * @param datasource byte[]
     * @param password   String
     * @return byte[]
     */
    public static byte[] encrypt(byte[] datasource, String password) {
        try {
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创建一个密匙工厂,然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            // Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES");
            // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            // 现在,获取数据并加密
            // 正式执行加密操作
            return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param src      byte[]
     * @param password String
     * @return byte[]
     * @throws Exception
     */
    public static byte[] decrypt(byte[] src, String password) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(password.getBytes());
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的
        // Cipher
        // 对象
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, random);
        // 真正开始解密操作
        return cipher.doFinal(src);
    }

}

运行结果:
在这里插入图片描述

IDEA

IDEA是上海交通大学教授来学嘉与瑞士学者James Massey联合提出的。它在1990年正式公布并在以后得到增强。这种算法是在DES算法的基础上发展出来的,类似于三重DES。发展IDEA也是因为感到DES具有密钥太短等缺点。IDEA的密钥为128位,这么长的密钥在今后若干年内应该是安全的。

特点:

  • 这种算法是在DES算法的基础上发展出来的,类似于三重DES。
  • 发展IDEA也是因为感到DES具有密钥太短等缺点。
  • DEA的密钥为128位,这么长的密钥在今后若干年内应该是安全的。
  • 在实际项目中用到的很少了解即可。

实现:

package com.paulniu.demo4java.idea;

import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.Security;

public class Demo4Java4IDEA {

    public static void main(String[] args){

    }

    public static void bcIDEA() {
        String src = "www.xttblog.com security idea";
        try {
            Security.addProvider(new BouncyCastleProvider());

            //生成key
            KeyGenerator keyGenerator = KeyGenerator.getInstance("IDEA");
            keyGenerator.init(128);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            //转换密钥
            Key key = new SecretKeySpec(keyBytes, "IDEA");

            //加密
            Cipher cipher = Cipher.getInstance("IDEA/ECB/ISO10126Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc idea encrypt : " + Base64.encodeBase64String(result));

            //解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            result = cipher.doFinal(result);
            System.out.println("bc idea decrypt : " + new String(result));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

这个在使用的时候需要引入BouncyCastle的jar包

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值