Java 加密算法(一)

个人博客:haichenyi.com。感谢关注

补充知识点:

字节:也就是 byte 是一种统计单位,表示数量的多少

字符:是指计算机中使用的文字和符号,比如:1、2、3、A、S、D、$、%等等符号

字节与字符的对应关系:它们完全不是一个概念,所以,没有什么有没有区别这个说法。不同的编码,两者的对应关系是不相同的,我这里就说常用的两种编码:

  1. ASCII码中,一个英文字母(不区分大小写)占一个字节,一个中文汉字占两个字节
  2. UTF-8中,一个英文字母占一个字节,一个中文汉字占三个字节

  我们加密最终常常操作的是bit,而我们加密首先得到的是byte数组的,byte的取值范围-128~127,中间包括0,刚好256个。也就是2^8=256。并且,1 byte = 8 bit(1kb = 1024 byte = 8^1024 bit等等)

  我们获得了byte之后,要把byte数组转成String字符串,String其实就是char数组,我们java有一个new String(char[] chars),应该都用过。我们转成字符串的前提是转成char数组,由于,1 char = 2 byte,所以,我们byte转成char长度扩大了1倍。

四种分类

  1. MD5加密
  2. Base64加密
  3. 对称加密
  4. 非对称加密

MD5加密——不可逆

概念

  MD5加密是我们常见的加密算法,是不可逆的,也就是说加密完成之后,无法解密转成原来的内容。MD5加密算法其实是一种散列函数,使用的是hash算法。MD5的原文是无线多个,但是MD5的值是有限的。所以一个MD5的值可能对应多个原文。SHA算法跟MD5是差不多的,只是MD5是128位,SHA是160位,多32位

  为什么MD5的值是有限多个呢?主流的MD5使用的是将任意长度的字节串映射为一个128bit的大整数。也就是一共有2^128种可能,所以说这个数字是有限的,而,我们的原文则是无限多个。发现两段原文对应同一个MD5的值概率非常小,也就忽略不记了。

使用

String name1 = "haichenyi";
   String name2 = "海晨忆";
    try {
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      byte[] digest1 = md5.digest(name1.getBytes("UTF-8"));
      Log.v("WZ","length1:"+digest1.length);

      byte[] digest2 = md5.digest(name2.getBytes("UTF-8"));
      Log.v("WZ","length1:"+digest2.length);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }

  我们通过MD5,得到的是一个byte数组(这个byte数组的长度跟我们的1byte=8bit没有直接关系),我们需要做的就是对这个byte数组进行操作,我们习惯上就是把这个btye转成16进制数存进数据库,当然,你也可以转成其他的类型存到数据库。这里给出几个byte数组转16进制字符串的方法,亲测可用:

private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5',
      '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

  /**
   * 方法一:
   * byte[] to hex string
   *
   * @param bytes
   * @return
   */
  public String bytesToHexFun1(byte[] bytes) {
    // 一个byte为8位,可用两个十六进制位标识
    char[] buf = new char[bytes.length * 2];
    int a = 0;
    int index = 0;
    for (byte b : bytes) { // 使用除与取余进行转换
      if (b < 0) {
        a = 256 + b;
      } else {
        a = b;
      }
      buf[index++] = HEX_CHAR[a / 16];
      buf[index++] = HEX_CHAR[a % 16];
    }
    return new String(buf);
  }

  /**
   * 方法二:
   * byte[] to hex string
   *
   * @param bytes
   * @return
   */
  public String bytesToHexFun2(byte[] bytes) {
    char[] buf = new char[bytes.length * 2];
    int index = 0;
    for(byte b : bytes) { // 利用位运算进行转换,可以看作方法一的变种
      buf[index++] = HEX_CHAR[b >>> 4 & 0xf];
      buf[index++] = HEX_CHAR[b & 0xf];
    }

    return new String(buf);
  }

  /**
   * 方法三:
   * byte[] to hex string
   *
   * @param bytes
   * @return
   */
  public String bytesToHexFun3(byte[] bytes) {
    StringBuilder buf = new StringBuilder(bytes.length * 2);
    for(byte b : bytes) { // 使用String的format方法进行转换
      buf.append(String.format("%02x", new Integer(b & 0xff)));
    }

    return buf.toString();
  }

  /**
   * 将16进制字符串转换为byte[]
   *
   * @param str
   * @return
   */
  public byte[] toBytes(String str) {
    if(str == null || str.trim().equals("")) {
      return new byte[0];
    }

    byte[] bytes = new byte[str.length() / 2];
    for(int i = 0; i < str.length() / 2; i++) {
      String subStr = str.substring(i * 2, i * 2 + 2);
      bytes[i] = (byte) Integer.parseInt(subStr, 16);
    }

    return bytes;
  }

Base64加密——可逆

流程

  1. 要知道的是有一个64个数的表,也称Base64编码表。可以字节定义,不过都是用的一样的。
  2. Base64是按照字符长度,以3个字符为一组
  3. 接着增对每组的每个字符,取ASCII编码
  4. 然后将获得的编码转换成8bit的二进制,就会得到3*8=24bit的字节
  5. 然后将这24bit的字节以6个bit为一组,分成4组
  6. 接着在每组前面填两个高位0,凑成每组8bit
  7. 最后将这每组8bit的二进制转成十进制,对应下面的Base64编码表

Base64 编码表

value char value char value char value char
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 U 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

使用

String str = "hai";
    byte[] encode = Base64.encode(str.getBytes(), Base64.NO_WRAP);
    try {
      String a = new String(encode,"UTF-8");
      String a1 = new String(encode,"US-ASCII");
      Log.v("wz",a);
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    String after = Base64.encodeToString(str.getBytes(), Base64.NO_WRAP);
    Log.v("wz","after-->"+after);

解析

  这里,我要使用Base64加密”hai”这个字符串,根据上面的流程:

扫描二维码关注公众号,回复: 942425 查看本文章
待加密字符串 h a i
ASCII编码 104 97 105
二进制 01101000 01100001 01101001

下面,上面的表不好表示,我再换一个表,下一步,该6位分一组了

现在的字符串:01101000 01100001 01101001

六位分一组 011010 000110 000101 101001
每组前面补0 00011010 00000110 00000101 00101001
转成10进制 26 6 5 41
Base64编码 a G F p

结果图:

PS:

  1. Base64.encodeToString()方法直接转成加密后的字符串
  2. Base64.encode()方法返回的byte数组是16进制的,不用手动在去转一遍16进制

猜你喜欢

转载自blog.csdn.net/qq_27634797/article/details/79486430