>>分享数据结构和算法相关的知识和技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 19529 个阅读者 刷新本主题
 * 贴子主题:  基于JavaScript的Base64编码、解码算法 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-03-15 13:05:54     消息  查看  搜索  好友  邮件  复制  引用

       Base64编码是一种很常用的编码,在RSA、AES等加密算法中,密钥对的表示通常使用Base64,UTF-7也是在Base64的基础上变化而来,当然所有仅支持ASCII码传输的网关在传输非ASCII码时,都可以使用Base64编码。

      Base64编码的方法非常简单,将3个Byte共24Bit从高到低重新拆分成4部分每部分6Bit,分别为0x0~0x3f,对应字符为A~Z和a~z和0-9和+/,共64个。如果最后剩余1个Byte,则将其编码为2个6Bit的Base64编码(第二个Base64编码仅2Bit,需在其后面添加4Bit的0),再在末尾添加2个=字符;如果最后剩余2个Byte,则将其编码为3个6Bit的Base64编码(第三个Base64编码仅4Bit,需在其后面添加2Bit的0),再在末尾添加1个=字符。

       Base64解码的方法与编码相反,将4个Base64编码字符转换为对应的0x0~0x3f,共24Bit,然后重新拆分成3部分,每部分8Bit,即1Byte,若末尾有=字符,则按编码方法中描述的规则反向处理。

       网上有很多现成的算法,但似乎没有使用JavaScript实现的,实际上使用JavaScript实现也不是太复杂。去年我就写了这个程序,只是忘记放在这里了,前天给学生讲课(放假前的最后一课,开学就大四了,可编程的能力尚需锤炼),讲到了这个,特意加了很多注释,放在这里,以飨读者。

          一共写了两个版本,其编码、解码的时间复杂度均为O(n),但版本二使用了一些技巧,使得其效率更高,编码效率约是版本一的3倍,解码效率约是版本一的4倍,同时编码、解码循环内少了一个判断。

             版本一:
  1.    < html   xmlns = "http://www.w3.org/1999/xhtml" >  
  2.   < head >  
  3.   < meta   http-equiv = "Content-Type"   content = "text/html; charset=utf-8"   />  
  4.   < title > Base64编码、解码算法 - 梦辽软件工作室 </ title >  
  5.   < style   type = "text/css" >  
  6.       body,table {  
  7.           font-family:宋体;  
  8.           font-size:9pt;  
  9.       }  
  10.       input {  
  11.           width:200px;  
  12.           height:25px;  
  13.       }  
  14.   </ style >  
  15.   </ head >  
  16.   < body >  
  17.   < script   type = "text/javascript" >  
  18.   /*  
  19.   Base64编码规则:  
  20.   1、将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位;  
  21.   2、数据不足3byte的话,缓冲区中剩下的bit用0补足;  
  22.   3、然后,每次取出6个bit(因为2^ 6 = 64 ,即0到63),按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出;  
  23.   4、不断进行,直到全部输入数据转换完成;  
  24.   5、如果最后剩下两个输入数据,在编码结果后加1个=;如果最后剩下一个输入数据,编码结果后加2个=;如果没有剩下任何数据,则什么都不加,这样可以保证数据还原的正确性。  
  25.   注1:先对输入字符串进行单字节编码,否则,因为charCodeAt()对汉字等符号返回Unicode编码,其长度为16bit;因此,可将所有字符当做双字节处理,虽然增加了字节数量,但简化了双字节字符和单字节字符的识别  
  26.   注2:在JavaScript中,CJK ExtB(扩展字符平面2)中的字符均被当做两个字符,用4Byte编码,即字符"&#131072;"~"&#173782;",其编码0xD840,0xDC00~0xD869~0xDED6,  
  27.       例:语句:alert("&#173782;".charCodeAt(0).toString(16)+" "+"&#173782;".charCodeAt(1).toString(16));将显示:d869 ded6  
  28.   */  
  29.   function unicodeToByte(str) //将Unicode字符串转换为UCS-16编码的字节数组  
  30.   {  
  31.       var  result =[];  
  32.       for(var  i = 0 ;i < str.length ;i++)  
  33.           result.push(str.charCodeAt(i) > > 8,str.charCodeAt(i)&0xff);  
  34.       return result;  
  35.   }  
  36.   function byteToUnicode(arr) //将UCS-16编码的字节数组转换为Unicode字符串  
  37.   {  
  38.       var  result = "" ;  
  39.       for(var  i = 0 ;i < arr.length ;i+=2)  
  40.           result+=String.fromCharCode((arr[i] < < 8 )+arr[i+1]);  
  41.       return result;  
  42.   }  
  43.   var  map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; //Base64从0到63的对应编码字符集  
  44.   function encodeBase64(str)  
  45.   {  
  46.       var  buffer = 0 , result = "" ;  
  47.       var  arr = unicodeToByte (str);  
  48.       for(var  i = 0 ;i < arr.length ;i++)  
  49.       {  
  50.            buffer =(buffer < < 8 )+arr[i];  
  51.           if(i% 3 ==2) //每3个字节处理1次  
  52.           {  
  53.               result+=map.charAt(buffer > > 18)+map.charAt(buffer > > 12&0x3f)+map.charAt(buffer > > 6&0x3f)+map.charAt(buffer&0x3f);  
  54.                buffer = 0 ;  
  55.           }  
  56.       } //3的整数倍的字节已处理完成,剩余的字节仍存放于buffer中  
  57.       if(arr.length% 3 ==1) //剩余1个字节  
  58.           result+=map.charAt(buffer > > 2)+map.charAt(buffer < < 4 &0x3f)+"==";  
  59.       else if(arr.length% 3 ==2) //剩余2个字节  
  60.           result+=map.charAt(buffer > > 10)+map.charAt(buffer > > 4&0x3f)+map.charAt(buffer < < 2 &0x3f)+"=";  
  61.       return result;  
  62.   }  
  63.   function decodeBase64(str)  
  64.   {  
  65.       //逆向映射数字索引和Base64编码字符集(简单Hash)  
  66.       var  s = "var base64={" ;  
  67.       for(var  i = 0 ;i < 64 ;i++)  
  68.           s+="\""+map.charAt(i)+"\":"+i+",";  
  69.       s+="\"=\":0};"; //将"="字符对应的编码定义为0,免除额外的处理  
  70.       eval(s);  
  71.       var  buffer = 0 , result =[];  
  72.       for( i = 0 ;i < str.length ;i++)  
  73.       {  
  74.            buffer =(buffer < < 6 )+base64[str.charAt(i)];  
  75.           if(i% 4 ==3) //每3个Base64字符处理一次  
  76.           {  
  77.               result.push(buffer > > 16,buffer > > 8&0xff,buffer&0xff);  
  78.                buffer = 0 ;  
  79.           }  
  80.       } //4的整数倍的Base64字符已处理完成,剩余的Base64字符仍存放于buffer中  
  81.       if(/==$/g.test(str)) //剩余2个Base64字符  
  82.           result.push(buffer > > 4);  
  83.       else if(/=$/g.test(str)) //剩余3个Base64字符,不可能剩余1个Base64字符  
  84.           result.push(buffer > > 10,buffer > > 2&0xff);  
  85.       return byteToUnicode(result);  
  86.   }  
  87.   </ script >  
  88.   < p > Base64编码、解码算法 < br   /> < br   />  
  89.   白宇 - 梦辽软件工作室 - 博讯网络有限责任公司 < br   />  
  90.   2011.05.30 </ p >  
  91.   < table   border = "0" >  
  92.        < tr >  
  93.            < td > 输入: </ td >  
  94.            < td > Base64编码: </ td >  
  95.            < td > Base64解码: </ td >  
  96.        </ tr >  
  97.        < tr >  
  98.            < td >  
  99.                < textarea   wrap = "soft"   id = "input"   cols = "40"   rows = "30" > </ textarea >  
  100.            </ td >  
  101.            < td >  
  102.                < textarea   wrap = "soft"   id = "encode"   cols = "40"   rows = "30" > </ textarea >  
  103.            </ td >  
  104.            < td >  
  105.                < textarea   wrap = "soft"   id = "decode"   cols = "40"   rows = "30" > </ textarea >  
  106.            </ td >  
  107.        </ tr >  
  108.        < tr >  
  109.            < td   align = "center" >  
  110.                < input   type = "button"   value = "编码 →"   onClick = "encode.value=encodeBase64(input.value)"   />  
  111.            </ td >  
  112.            < td   align = "center" >  
  113.                < input   type = "button"   value = "解码 →"   onClick = "decode.value=decodeBase64(encode.value);"   />  
  114.            </ td >  
  115.            < td   align = "center" >  
  116.                < input   type = "button"   value = "校验 √"   onClick = "alert(input.value==decode.value?'校验正确!':'校验错误!');"   />  
  117.            </ td >  
  118.        </ tr >  
  119.   </ table >  
  120.   </ body >  
  121.   </ html >  

     版本二:

  1.    < html   xmlns = "http://www.w3.org/1999/xhtml" >  
  2.   < head >  
  3.   < meta   http-equiv = "Content-Type"   content = "text/html; charset=utf-8"   />  
  4.   < title > Base64编码、解码算法(版本2) - 梦辽软件工作室 </ title >  
  5.   < style   type = "text/css" >  
  6.       body,table {  
  7.           font-family:宋体;  
  8.           font-size:9pt;  
  9.       }  
  10.       input {  
  11.           width:200px;  
  12.           height:25px;  
  13.       }  
  14.   </ style >  
  15.   </ head >  
  16.   < body >  
  17.   < script   type = "text/javascript" >  
  18.   /*  
  19.   Base64编码规则:  
  20.   1、将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位;  
  21.   2、数据不足3byte的话,缓冲区中剩下的bit用0补足;  
  22.   3、然后,每次取出6个bit(因为2^ 6 = 64 ,即0到63),按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出;  
  23.   4、不断进行,直到全部输入数据转换完成;  
  24.   5、如果最后剩下两个输入数据,在编码结果后加1个=;如果最后剩下一个输入数据,编码结果后加2个=;如果没有剩下任何数据,则什么都不加,这样可以保证数据还原的正确性。  
  25.   注1:先对输入字符串进行单字节编码,否则,因为charCodeAt()对汉字等符号返回Unicode编码,其长度为16bit;因此,可将所有字符当做双字节处理,虽然增加了字节数量,但简化了双字节字符和单字节字符的识别  
  26.   注2:在JavaScript中,CJK ExtB(扩展字符平面2)中的字符均被当做两个字符,用4Byte编码,即字符"&#131072;"~"&#173782;",其编码0xD840,0xDC00~0xD869~0xDED6,  
  27.       例:语句:alert("&#173782;".charCodeAt(0).toString(16)+" "+"&#173782;".charCodeAt(1).toString(16));将显示:d869 ded6  
  28.   技巧:编码时处理源字节,如果字节总数模3余1,则可现在其后面添加2个为0的字节,如果模3余2,则添加1个为0的字节,然后在编码完成后将末尾的2个或1个A字符均替换为=字符;  
  29.        解码时同样可以将末尾的=字符替换为A字符,由于A字符对应0,而0解码为空字符,故可不做任何处理(编码非字符类型的其它字节流,如图片、音视频等,则必须将末尾的0字节去除)。  
  30.   */  
  31.   function unicodeToByte(str) //将Unicode字符串转换为UCS-16编码的字节数组  
  32.   {  
  33.       var  result =[];  
  34.       for(var  i = 0 ;i < str.length ;i++)  
  35.           result.push(str.charCodeAt(i) > > 8,str.charCodeAt(i)&0xff);  
  36.       return result;  
  37.   }  
  38.   function byteToUnicode(arr) //将UCS-16编码的字节数组转换为Unicode字符串  
  39.   {  
  40.       var  result = "" ;  
  41.       for(var  i = 0 ;i < arr.length ;i+=2)  
  42.           result+=String.fromCharCode((arr[i] < < 8 )+arr[i+1]);  
  43.       return result;  
  44.   }  
  45.   var  map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; //Base64从0到63的对应编码字符集  
  46.   function encodeBase64(str)  
  47.   {  
  48.       var buffer, result = "" , flag = 0 ; //flag表示在字节数组剩余的个数  
  49.       var  arr = unicodeToByte (str);  
  50.        flag = arr .length%3;  
  51.       if( flag ==1)  
  52.           arr.push(0,0);  
  53.       else if( flag ==2)  
  54.           arr.push(0);  
  55.       for(var  i = 0 ;i < arr.length ;i+=3) //此时arr.length一定能被3整除  
  56.       {  
  57.            buffer =(arr[i] < < 16 )+(arr[i+1] < < 8 )+arr[i+2];  
  58.           result+=map.charAt(buffer > > 18)+map.charAt(buffer > > 12&0x3f)+map.charAt(buffer > > 6&0x3f)+map.charAt(buffer&0x3f);  
  59.       }  
  60.       if( flag ==1)  
  61.            result result =result.replace(/AA$/g,"==");  
  62.       else if( flag ==2)  
  63.            result result =result.replace(/A$/g,"=");  
  64.       return result;  
  65.   }  
  66.   function decodeBase64(str)  
  67.   {  
  68.       //逆向映射数字索引和Base64编码字符集(简单Hash)  
  69.       var  s = "var base64={" ;  
  70.       for(var  i = 0 ;i < 64 ;i++)  
  71.           s+="\""+map.charAt(i)+"\":"+i+",";  
  72.       s+="\"=\":0};"; //将"="字符对应的编码定义为0,相当于将=字符转换为A字符  
  73.       eval(s);  
  74.       var buffer, result =[];  
  75.       for( i = 0 ;i < str.length ;i+=4) //由于包含Base64末尾包含1个或2个=字符,故str.length一定能被4整除  
  76.       {  
  77.            buffer =(base64[str.charAt(i)] < < 18 )+(base64[str.charAt(i+1)] < < 12 )+(base64[str.charAt(i+2)] < < 6 )+base64[str.charAt(i+3)];  
  78.           result.push(buffer > > 16,buffer > > 8&0xff,buffer&0xff);  
  79.       }  
  80.       if(/==$/g.test(str)) //如解码为字符串可不做该处理  
  81.       {  
  82.           result.pop();  
  83.           result.pop();  
  84.       }  
  85.       else if(/=$/g.test(str))  
  86.           result.pop();  
  87.       return byteToUnicode(result);  
  88.   }  
  89.   </ script >  
  90.   < p > Base64编码、解码算法(版本2) < br   /> < br   />  
  91.   白宇 - 梦辽软件工作室 - 博讯网络有限责任公司 < br   />  
  92.   2011.05.31 </ p >  
  93.   < table   border = "0" >  
  94.        < tr >  
  95.            < td > 输入: </ td >  
  96.            < td > Base64编码: </ td >  
  97.            < td > Base64解码: </ td >  
  98.        </ tr >  
  99.        < tr >  
  100.            < td >  
  101.                < textarea   wrap = "soft"   id = "input"   cols = "40"   rows = "30" > </ textarea >  
  102.            </ td >  
  103.            < td >  
  104.                < textarea   wrap = "soft"   id = "encode"   cols = "40"   rows = "30" > </ textarea >  
  105.            </ td >  
  106.            < td >  
  107.                < textarea   wrap = "soft"   id = "decode"   cols = "40"   rows = "30" > </ textarea >  
  108.            </ td >  
  109.        </ tr >  
  110.        < tr >  
  111.            < td   align = "center" >  
  112.                < input   type = "button"   value = "编码 →"   onClick = "encode.value=encodeBase64(input.value)"   />  
  113.            </ td >  
  114.            < td   align = "center" >  
  115.                < input   type = "button"   value = "解码 →"   onClick = "decode.value=decodeBase64(encode.value);"   />  
  116.            </ td >  
  117.            < td   align = "center" >  
  118.                < input   type = "button"   value = "校验 √"   onClick = "alert(input.value==decode.value?'校验正确!':'校验错误!');"   />  
  119.            </ td >  
  120.        </ tr >  
  121.   </ table >  
  122.   </ body >  
  123.   </ html >  

         这是完整的HTML文件(单文件),直接保存后就可以运行了。



----------------------------
原文链接:https://blog.51cto.com/mengliao/898745

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-03-20 11:48:34 重新编辑]
  Java面向对象编程-->输入与输出(上)
  JavaWeb开发-->Servlet技术详解(Ⅲ)
  JSP与Hibernate开发-->Java对象持久化技术概述
  Java网络编程-->Java网络编程入门
  精通Spring-->Vue CLI脚手架工具
  Vue3开发-->Vue Router路由管理器
  64匹马,8个赛道,找出跑得最快的4匹马
  无向图的最短路径求解算法之——Dijkstra算法
  深度学习之图片压缩算法
  haproxy调度算法
  PageRank算法
  用Java写算法:快速排序
  ipvsadm及lvs的调度算法
  面试官问我:什么是消息队列?什么场景需要他?用了会出现什...
  RSA 非对称加密原理(小白也能看懂哦~)
  谷歌面试算法题:两个排序数组的中位数
  小米面试算法题:搜索旋转排序数组
  Java数据结构与算法 - 栈和队列
  数据结构中的数组
  技术和算法的抉择
  RSA算法的数学原理
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。