base64编码原理和解码,加密案例

博文转自: 

http://blog.csdn.net/zdqdj1/article/details/51760412点击打开链接

 Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后binhex的版本使用不同的64字符集来代表6个二进制数字,但是它们不叫Base64。

       Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括MIME的email、在XML中存储复杂数据。

原理:

在MIME格式的电子邮件中,base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定base64。使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。

        完整的base64定义可见RFC1421和RFC2045。编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。

        转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲器中剩下的bit用0补足。然后,每次取出6(因为2^6=64)个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。

        当原数据长度不是3的整数倍时,如果最后剩下一个输入数据,在编码结果后加2个“=”;如果最后剩下两个输入数据,编码结果后加1个“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证数据还原的正确性。

原理理解:

上面提到编码后的数据长度约为原长的135.1%,算式为:1*(4/3)*((76+1)/76)≈1.351

        鉴于很多朋友不爱看大片枯燥文字,在下以个人理解将之总结为以下3点:

        ①将原始数据以先后顺序每3个字节分成一组*。在每一组中,把3个8bit的字节(3*8=24)按高低位顺序分为每段6bit的4段(4*6=24),将每段转为十进制得到0~63之间的数,以之为索引在Base64编码表中对照得到4个密文。重复以上操作。
       *若最后一组不足3个字节,则在其二进制位的低位上用尽量少的“0”补位,使二进制位的个数为6的倍数。

        ②密文每76个字符数据后加一个换行符*。
       *注意这里的换行符指CRLF(\r\n),而不是LF(\n),为什么?请看RFC2045下载完整PDF)。

        ③若原始数据字节长度除以3余1,则在输出数据末尾加2个“=”,若原始数据长度除以3余2,则在输出数据末尾加1个“=”。

 规则

        1.ASCII编码表:

  2.Base64编码表

图解:

    我们还是来看下面这3个例子比较直观(例子下载)。

        例子1、假设我们的明文为“Base64”(数据长度为6,正好是3的倍数),则其编码计算方式如下:

  例子2、假设我们的明文为“test”(数据长度为4,4%3=1),则其编码计算方式如下:

  例子3、假设我们的明文为“JiaMi”(数据长度为5,5%3=2),则其编码计算方式如下:

java案例1:


  
  
  1. package com.dokio.base64;
  2. public class Base64 {
  3. //Constructor
  4. public Base64() {
  5. }
  6. private static String base64Code= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  7. public static String encode(String srcStr) {
  8. //有效值检查
  9. if(srcStr == null || srcStr.length() == 0) {
  10. return srcStr;
  11. }
  12. //将明文的ASCII码转为二进制位字串
  13. char[] srcStrCh= srcStr.toCharArray();
  14. StringBuilder asciiBinStrB= new StringBuilder();
  15. String asciiBin= null;
  16. for(int i= 0; i < srcStrCh.length; i++) {
  17. asciiBin= Integer.toBinaryString((int)srcStrCh[i]);
  18. while(asciiBin.length()< 8) {
  19. asciiBin= "0"+ asciiBin;
  20. }
  21. asciiBinStrB.append(asciiBin);
  22. }
  23. //跟据明文长度在二进制位字串尾部补“0
  24. while(asciiBinStrB.length()% 6!= 0) {
  25. asciiBinStrB.append("0");
  26. }
  27. String asciiBinStr= String.valueOf(asciiBinStrB);
  28. //将上面得到的二进制位字串转为Value,再跟据Base64编码表将之转为Encoding
  29. char[] codeCh= new char[asciiBinStr.length()/ 6];
  30. int index= 0;
  31. for(int i= 0; i< codeCh.length; i++) {
  32. index= Integer.parseInt(asciiBinStr.substring(0, 6), 2);
  33. asciiBinStr= asciiBinStr.substring(6);
  34. codeCh[i]= base64Code.charAt(index);
  35. }
  36. StringBuilder code= new StringBuilder(String.valueOf(codeCh));
  37. //跟据需要在尾部添加“=
  38. if(srcStr.length()% 3 == 1) {
  39. code.append("==");
  40. } else if(srcStr.length()% 3 == 2) {
  41. code.append("= ");
  42. }
  43. //每76个字符加一个回车换行符(CRLF)
  44. int i= 76;
  45. while(i< code.length()) {
  46. code.insert(i, "\ r\ n");
  47. i+= 76;
  48. }
  49. code.append("\r\n");
  50. return String.valueOf(code);
  51. }
  52. public static String decode(String srcStr) {
  53. //有效值检查
  54. if(srcStr == null || srcStr.length() == 0) {
  55. return srcStr;
  56. }
  57. //检测密文中“=”的个数后将之删除,同时删除换行符
  58. int eqCounter= 0;
  59. if(srcStr.endsWith("==")) {
  60. eqCounter= 2;
  61. } else if(srcStr.endsWith("= ")) {
  62. eqCounter= 1;
  63. }
  64. srcStr= srcStr.replaceAll("= ", "");
  65. srcStr= srcStr.replaceAll("\r\n", "");
  66. //跟据Base64编码表将密文(Encoding)转为对应Value,然后转为二进制位字串
  67. char[] srcStrCh= srcStr.toCharArray();
  68. StringBuilder indexBinStr= new StringBuilder();
  69. String indexBin= null;
  70. for(int i= 0; i< srcStrCh.length; i++) {
  71. indexBin= Integer.toBinaryString(base64Code.indexOf((int)srcStrCh[i]));
  72. while(indexBin.length()< 6) {
  73. indexBin= "0"+ indexBin;
  74. }
  75. indexBinStr.append(indexBin);
  76. }
  77. //删除因编码而在尾部补位的“0”后得到明文的ASCII码的二进制位字串
  78. if(eqCounter == 1) {
  79. indexBinStr.delete(indexBinStr.length()- 2, indexBinStr.length());
  80. } else if(eqCounter == 2) {
  81. indexBinStr.delete(indexBinStr.length()- 4, indexBinStr.length());
  82. }
  83. String asciiBinStr= String.valueOf(indexBinStr);
  84. //将上面得到的二进制位字串分隔成字节后还原成明文
  85. String asciiBin= null;
  86. char[] ascii= new char[asciiBinStr.length()/ 8];
  87. for(int i= 0; i< ascii.length; i++) {
  88. asciiBin= asciiBinStr.substring(0, 8);
  89. asciiBinStr= asciiBinStr.substring(8);
  90. ascii[i]= (char)Integer.parseInt(asciiBin, 2);
  91. }
  92. return String.valueOf(ascii);
  93. }
  94. public static void main(String[] args) {
  95. System.out.print(encode("I like your long long shadow.It just seems you are unhappy to say goodbye to me."));
  96. System.out.print("\n------\n");
  97. System.out.print(decode("SSBsaWtlIHlvdXIgbG9uZyBsb25nIHNoYWRvdy5JdCBqdXN0IHNlZW1zIHlvdSBhcmUgdW5oYXBweSB0byBzYXkgZ29vZGJ5ZSB0byBtZS4="));
  98. System.out.print("\ n------\ n");
  99. System.out.print(decode(encode("I like your long long shadow.It just seems you are unhappy to say goodbye to me.")));
  100. }
  101. }

案例2:

加密 jquery代码:


 
 
  1. // base64加密
  2. function encode64(input) {
  3. var keyStr = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "=";
  4. var output = "";
  5. var chr1, chr2, chr3 = "";
  6. var enc1, enc2, enc3, enc4 = "";
  7. var i = 0;
  8. do {
  9. chr1 = input.charCodeAt(i++);
  10. chr2 = input.charCodeAt(i++);
  11. chr3 = input.charCodeAt(i++);
  12. enc1 = chr1 >> 2;
  13. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  14. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  15. enc4 = chr3 & 63;
  16. if (isNaN(chr2)) {
  17. enc3 = enc4 = 64;
  18. } else if (isNaN(chr3)) {
  19. enc4 = 64;
  20. }
  21. output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
  22. chr1 = chr2 = chr3 = "";
  23. enc1 = enc2 = enc3 = enc4 = "";
  24. } while (i < input.length);
  25. return output;
  26. }

解密 java代码:


 
 
  1. /**
  2. *
  3. */
  4. package com.allinfinance.aps.biz.util;
  5. import java.io.ByteArrayOutputStream;
  6. public class Base64Util {
  7. private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1,
  8. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  9. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  10. -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
  11. 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  12. 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
  13. -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
  14. 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
  15. -1, -1 };
  16. /**
  17. * 解密
  18. * @param str
  19. * @return
  20. */
  21. public static byte[] decode(String str) {
  22. byte[] data = str.getBytes();
  23. int len = data.length;
  24. ByteArrayOutputStream buf = new ByteArrayOutputStream(len);
  25. int i = 0;
  26. int b1, b2, b3, b4;
  27. while (i < len) {
  28. do {
  29. b1 = base64DecodeChars[data[i++]];
  30. } while (i < len && b1 == -1);
  31. if (b1 == -1) {
  32. break;
  33. }
  34. do {
  35. b2 = base64DecodeChars[data[i++]];
  36. } while (i < len && b2 == -1);
  37. if (b2 == -1) {
  38. break;
  39. }
  40. buf.write((int) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
  41. do {
  42. b3 = data[i++];
  43. if (b3 == 61) {
  44. return buf.toByteArray();
  45. }
  46. b3 = base64DecodeChars[b3];
  47. } while (i < len && b3 == -1);
  48. if (b3 == -1) {
  49. break;
  50. }
  51. buf.write((int) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
  52. do {
  53. b4 = data[i++];
  54. if (b4 == 61) {
  55. return buf.toByteArray();
  56. }
  57. b4 = base64DecodeChars[b4];
  58. } while (i < len && b4 == -1);
  59. if (b4 == -1) {
  60. break;
  61. }
  62. buf.write((int) (((b3 & 0x03) << 6) | b4));
  63. }
  64. return buf.toByteArray();
  65. }
  66. /**
  67. * 返回解密结果
  68. */
  69. public static String decodeToString(String param){
  70. return new String(decode(param));
  71. }
  72. }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值