個(gè)人博客:haichenyi.com。感謝關(guān)注
補(bǔ)充知識點(diǎn):
字節(jié):也就是 byte 是一種統(tǒng)計(jì)單位,表示數(shù)量的多少
字符:是指計(jì)算機(jī)中使用的文字和符號,比如:1、2、3、A、S、D、$、%等等符號
字節(jié)與字符的對應(yīng)關(guān)系:它們完全不是一個(gè)概念,所以,沒有什么有沒有區(qū)別這個(gè)說法。不同的編碼,兩者的對應(yīng)關(guān)系是不相同的,我這里就說常用的兩種編碼:
- ASCII碼中,一個(gè)英文字母(不區(qū)分大小寫)占一個(gè)字節(jié),一個(gè)中文漢字占兩個(gè)字節(jié)
- UTF-8中,一個(gè)英文字母占一個(gè)字節(jié),一個(gè)中文漢字占三個(gè)字節(jié)
??我們加密最終常常操作的是bit,而我們加密首先得到的是byte數(shù)組的,byte的取值范圍-128~127,中間包括0,剛好256個(gè)。也就是2^8=256。并且,1 byte = 8 bit(1kb = 1024 byte = 8^1024 bit等等)
??我們獲得了byte之后,要把byte數(shù)組轉(zhuǎn)成String字符串,String其實(shí)就是char數(shù)組,我們java有一個(gè)new String(char[] chars),應(yīng)該都用過。我們轉(zhuǎn)成字符串的前提是轉(zhuǎn)成char數(shù)組,由于,1 char = 2 byte,所以,我們byte轉(zhuǎn)成char長度擴(kuò)大了1倍。
四種分類
- MD5加密
- Base64加密
- 對稱加密
- 非對稱加密
MD5加密——不可逆
概念
??MD5加密是我們常見的加密算法,是不可逆的,也就是說加密完成之后,無法解密轉(zhuǎn)成原來的內(nèi)容。MD5加密算法其實(shí)是一種散列函數(shù),使用的是hash算法。MD5的原文是無線多個(gè),但是MD5的值是有限的。所以一個(gè)MD5的值可能對應(yīng)多個(gè)原文。SHA算法跟MD5是差不多的,只是MD5是128位,SHA是160位,多32位
??為什么MD5的值是有限多個(gè)呢?主流的MD5使用的是將任意長度的字節(jié)串映射為一個(gè)128bit的大整數(shù)。也就是一共有2^128種可能,所以說這個(gè)數(shù)字是有限的,而,我們的原文則是無限多個(gè)。發(fā)現(xiàn)兩段原文對應(yīng)同一個(gè)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,得到的是一個(gè)byte數(shù)組(這個(gè)byte數(shù)組的長度跟我們的1byte=8bit沒有直接關(guān)系),我們需要做的就是對這個(gè)byte數(shù)組進(jìn)行操作,我們習(xí)慣上就是把這個(gè)btye轉(zhuǎn)成16進(jìn)制數(shù)存進(jìn)數(shù)據(jù)庫,當(dāng)然,你也可以轉(zhuǎn)成其他的類型存到數(shù)據(jù)庫。這里給出幾個(gè)byte數(shù)組轉(zhuǎn)16進(jìn)制字符串的方法,親測可用:
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) {
// 一個(gè)byte為8位,可用兩個(gè)十六進(jìn)制位標(biāo)識
char[] buf = new char[bytes.length * 2];
int a = 0;
int index = 0;
for (byte b : bytes) { // 使用除與取余進(jìn)行轉(zhuǎn)換
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) { // 利用位運(yùn)算進(jìn)行轉(zhuǎn)換,可以看作方法一的變種
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方法進(jìn)行轉(zhuǎn)換
buf.append(String.format("%02x", new Integer(b & 0xff)));
}
return buf.toString();
}
/**
* 將16進(jìn)制字符串轉(zhuǎn)換為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加密——可逆
流程
- 要知道的是有一個(gè)64個(gè)數(shù)的表,也稱Base64編碼表??梢宰止?jié)定義,不過都是用的一樣的。
- Base64是按照字符長度,以3個(gè)字符為一組
- 接著增對每組的每個(gè)字符,取ASCII編碼
- 然后將獲得的編碼轉(zhuǎn)換成8bit的二進(jìn)制,就會得到3*8=24bit的字節(jié)
- 然后將這24bit的字節(jié)以6個(gè)bit為一組,分成4組
- 接著在每組前面填兩個(gè)高位0,湊成每組8bit
- 最后將這每組8bit的二進(jìn)制轉(zhuǎn)成十進(jìn)制,對應(yīng)下面的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"這個(gè)字符串,根據(jù)上面的流程:
| 待加密字符串 | h | a | i |
|---|---|---|---|
| ASCII編碼 | 104 | 97 | 105 |
| 二進(jìn)制 | 01101000 | 01100001 | 01101001 |
下面,上面的表不好表示,我再換一個(gè)表,下一步,該6位分一組了
現(xiàn)在的字符串:01101000 01100001 01101001
| 六位分一組 | 011010 | 000110 | 000101 | 101001 |
|---|---|---|---|---|
| 每組前面補(bǔ)0 | 00011010 | 00000110 | 00000101 | 00101001 |
| 轉(zhuǎn)成10進(jìn)制 | 26 | 6 | 5 | 41 |
| Base64編碼 | a | G | F | p |
結(jié)果圖:
PS:
- Base64.encodeToString()方法直接轉(zhuǎn)成加密后的字符串
- Base64.encode()方法返回的byte數(shù)組是16進(jìn)制的,不用手動在去轉(zhuǎn)一遍16進(jìn)制