·您当前的位置:首页 > 技术教程 > AS2与AS3技术 >

[AS3]基于zip加密与解密as3算法

时间:2014-09-25 14:21酷播
在EncryptZip的开发中, 前端Flex要能够对加密的zip的文件进行解密, 当时网上没有这个功能的现有的代码. 由于我使用的是纯AS代码, 经过比较几个网上现有的zip文件压缩的开源代码

     在EncryptZip的开发中,  前端Flex要能够对加密的zip的文件进行解密, 当时网上没有这个功能的现有的代码. 由于我使用的是纯AS代码, 经过比较几个网上现有的zip文件压缩的开源代码, 我采用了nochump, 并尝试在此基础上进行扩展.

     zip的开发需要了解zip文件的压缩格式, 每个数据标志位的意义, 好在nochump的代码给出了详细的注释,在此对David Chang (dchang@nochump.com)表示由衷的感谢! 通过结合zip结构文档和nochump源代码,我一边调试,一边注释,这让我快速掌握zip的格式省了不少的时间.

    为了验证我对了解zip文件格式是否正确, 用AS编写了一个的zip解压格式测试类, 代码如下:

  1. /** 
  2.  * Copyright (c) 2009 David Yao (xiang.okay@gmail.com) 
  3.  * description: This class is supposed to test the information of the format of the encrypt-zip file. 
  4.  * author: David Yao 
  5.  * mail: xiang.okay@gmail.com  
  6.  */ 
  7. package nochump.util.test 
  8.         import flash.utils.ByteArray; 
  9.         import flash.utils.Endian; 
  10.          
  11.         import mx.controls.Alert; 
  12.          
  13.         import nochump.util.extend.ZipCrypto; 
  14.         import nochump.util.zip.Inflater; 
  15.         import nochump.util.zip.ZipEntry; 
  16.          
  17.         public class TestUpzip 
  18.         { 
  19.                 public function TestUpzip() 
  20.                 { 
  21.                 } 
  22.                  
  23.                 public static function traceInfo(zipByte:ByteArray):void{ 
  24.                              var byteInfo:ByteArray = new ByteArray(); 
  25.                              byteInfo.endian = Endian.LITTLE_ENDIAN; 
  26.                              zipByte.readBytes(byteInfo); 
  27.                                  
  28.                              byteInfo.position = 0
  29.                              //文件标头区             
  30.                              var e:ZipEntry = new ZipEntry("yx"); 
  31.                              trace("  位置 文件标头 :" +byteInfo.position);                        
  32.                              trace("  文件标头签名:"+byteInfo.readUnsignedInt().toString(16)); 
  33.                              trace("  所需版本 :"+byteInfo.readUnsignedShort()); 
  34.                              var flag:int =  byteInfo.readUnsignedShort();                 
  35.                              trace("  一般用途位标记:"+flag); 
  36.                              e.method = byteInfo.readUnsignedShort();                         
  37.                              trace("  压缩方法:"+e.method); 
  38.                              var time:uint =    byteInfo.readUnsignedInt(); 
  39.                              trace("  文件的最后修改时间 :"+ time ); 
  40.                              //trace("  文件的最后修改日期 :"+ time ); 
  41.                              e.crc =  byteInfo.readUnsignedInt();                                                  
  42.                              trace("  crc-32 :"+ e.crc); 
  43.                              e.compressedSize = byteInfo.readUnsignedInt(); 
  44.                              trace("  压缩后的大小 :"+ e.compressedSize); 
  45.                              e.size = byteInfo.readUnsignedInt(); 
  46.                              trace("  解压缩后的大小 :"+e.size); 
  47.                              var nal:int = byteInfo.readUnsignedShort(); 
  48.                              trace("  文件名长度 :"+nal); 
  49.                              var extL:int = byteInfo.readUnsignedShort(); 
  50.                              trace("  额外字段长度 :"+ extL); 
  51.                              e.name = byteInfo.readUTFBytes(nal); 
  52.                              trace("  文件名 :"+ e.name); 
  53.                              if(extL >0) 
  54.                              byteInfo.readBytes(e.extra,0,extL); 
  55.                              trace("  额外字段 :"+ e.extra); 
  56.                               
  57.                              var plainText:ByteArray = new ByteArray();         
  58.                               if(flag == 9){ 
  59.                                 //数据区 
  60.                                 var ex12Data:ByteArray = new ByteArray(); 
  61.                                 var byteData:ByteArray = new ByteArray(); 
  62.                                    
  63.                                      ZipCrypto.InitCipher("123456");                          
  64.                                      byteInfo.readBytes(ex12Data,0,12);                       
  65.                                      var DecryptedHeader:ByteArray  =ZipCrypto.DecryptMessage(ex12Data,12);   
  66.                                      //判断密码的正确性 
  67.                                      trace(DecryptedHeader[11]);                                      
  68.                                      trace((time >> 8) & 0xff);  
  69.          
  70.                                      if (DecryptedHeader[11] != ((e.crc >> 24) & 0xff)){ 
  71.                                  
  72.                                                 if ((9 & 0x0008) != 0x0008){ 
  73.                                                         throw new Error("The password did not match."); 
  74.                                                 } 
  75.                                                 else if (DecryptedHeader[11] != ((time >> 8) & 0xff))   { 
  76.                                                         throw new Error("The password did not match."); 
  77.                                                 }        
  78.                                                  
  79.                                                } 
  80.                                                 
  81.                                 byteInfo.readBytes(byteData,0,e.compressedSize-12); 
  82.                                 plainText = ZipCrypto.DecryptMessage(byteData,e.compressedSize-12); 
  83.                               } 
  84.                               else{ 
  85.                                  
  86.                                 byteInfo.readBytes(plainText,0,655); 
  87.                               } 
  88.                              trace("  读完数据区位置  :" +byteInfo.position);                           
  89.                              var b2:ByteArray = new ByteArray(); 
  90.                                                  var inflater:Inflater = new Inflater(); 
  91.                                                  inflater.setInput(plainText); 
  92.                                                  inflater.inflate(b2); 
  93.                              Alert.show(String(b2)); 
  94.                               
  95.                              //数据描述符记录 
  96.                              if(flag == 8 || flag ==9 ){ 
  97.                                 trace(" ----------------"); 
  98.                                 trace("  位置 数据描述符记录 :" +byteInfo.position);      
  99.                                 trace("  数据标签 :" +byteInfo.readUnsignedInt().toString(16)); 
  100.                                 trace("  crc-32 :" +byteInfo.readUnsignedInt()); 
  101.                                 trace("  压缩后的大小 :" +byteInfo.readUnsignedInt()); 
  102.                                 trace("  解压缩后的大小 :" +byteInfo.readUnsignedInt()); 
  103.                              } 
  104.                               
  105.                               
  106.                              //进入中央目录结构->文件标头 
  107.                              trace(" ----------------"); 
  108.                              trace("  位置 进入中央目录结构->文件标头:" +byteInfo.position);                        
  109.                              trace(" 中央文件标头签名:"+ byteInfo.readUnsignedInt().toString(16)); 
  110.                              trace(" version made by :"+ byteInfo.readUnsignedShort());  
  111.                              trace(" 所需版本       :"+ byteInfo.readUnsignedShort());  
  112.                              trace(" 一般用途位标记 :"+ byteInfo.readUnsignedShort()); 
  113.                              trace(" 压缩方法       :"+ byteInfo.readUnsignedShort()); 
  114.                              trace(" 文件的最后修改时间  :"+ byteInfo.readUnsignedInt()); 
  115.                              trace(" crc-3        :"+ byteInfo.readUnsignedInt());       
  116.                              trace(" 压缩后的大小 :"+ byteInfo.readUnsignedInt());       
  117.                              trace(" 解压缩后的大小 :"+ byteInfo.readUnsignedInt()); 
  118.                              var cname:int =   byteInfo.readUnsignedShort();   
  119.                              trace(" 文件名长度   :"+ cname);    
  120.                              var celength:int =   byteInfo.readUnsignedShort();    
  121.                              trace(" 额外字段长度 :"+ celength);   
  122.                              var cfplain:int =   byteInfo.readUnsignedShort();     
  123.                              trace(" 文件注释长度 :"+ cfplain);       
  124.                              trace(" 磁盘开始号   :"+ byteInfo.readUnsignedShort());       
  125.                              trace(" 内部文件属性 :"+ byteInfo.readUnsignedShort());        
  126.                              trace(" 外部文件属性 :"+ byteInfo.readUnsignedInt());        
  127.                              trace(" 相关的标头偏移量 :"+ byteInfo.readUnsignedInt());                                                
  128.                              trace("  文件名 :"+ byteInfo.readUTFBytes(cname));                          
  129.                              trace("  额外字段 :"+ byteInfo.readUTFBytes(celength));                                  
  130.                              trace("  文件注释 :"+ byteInfo.readUTFBytes(cfplain)); 
  131.                              ////进入中央目录结构->结尾 
  132.                              trace(" ----------------"); 
  133.                              trace("  位置 进入中央目录结构->结尾:" +byteInfo.position); 
  134.                              trace(" 中央目录记录签名               :"  + byteInfo.readUnsignedInt().toString(16)); 
  135.                              trace(" 磁盘编号                       :" + byteInfo.readUnsignedShort());  
  136.                              trace(" 中央目录开始磁盘编号           :"  + byteInfo.readUnsignedShort());  
  137.                              trace(" 本磁盘上在中央目录里的入口总数 :"   + byteInfo.readUnsignedShort());  
  138.                              trace(" 中央目录里的入口总数           :"  + byteInfo.readUnsignedShort());  
  139.                              trace(" 中央目录的大小                 :" + byteInfo.readUnsignedInt());  
  140.                              trace(" 中央目录对第一张磁盘的偏移量   :" + byteInfo.readUnsignedInt()); 
  141.                              var cLeng:int = byteInfo.readUnsignedShort();  
  142.                              trace(" .ZIP 文件注释长度              :" + cLeng);                                            
  143.                              trace(" .ZIP 文件注释                  :" + byteInfo.readUTFBytes(cLeng)); 
  144.                              trace("  结束位置 :" +byteInfo.position);                        
  145.                               
  146.                 } 
  147.         } 

     在此时我用ActionScript3 做zip的加密解密算法验证, 发现zip解密文件时总不能正确解密, 默认解密密码为"123456" (此时后台Java没有实现zip的加密/解密功能,只负责将加密的文件传递给Flex, Flex 尝试解密), 经过跟踪调试发现问题出在_Keys[1], _Keys[1]乘以0x08088405后得到的值和计算器得到的值不一致, 即AS3出现 两个大数相乘得到的值不正确.

              _Keys[0] = uint(CRC32.update(int(_Keys[0]), byteValue));                         
              _Keys[1] = _Keys[1] + (_Keys[0] & 0xff);                        
              _Keys[1] = _Keys[1] * 0x08088405; //the value of _Keys[1] afte it mutiplys by 0x08088405 is not correct.

              _Keys[2] = uint(CRC32.update(int(_Keys[2]), (_Keys[1] >> 24) & 0xff));

    这应该是Flex Sdks或Flash Player 造成的, 我当时的用到的版本Flex Sdks3.3, Flash Player 10.0. 不知道现在这个问题有没有解决.

    两个大数相乘得到的值不正确这个问题无法逾越, 当时使EncryptZip的开发陷入的停滞.  好在此时已经对zip文件的格式很了解,也知道了zip加密/解密的相关算法, 因此我暂时停止了前端AS开发, 转向了对后台Java对zip加密/解密的开发, 开发进行的很顺利.  (未完, 请阅读AS zip加密解密算法二)

    (转贴请注明出处)Author:David

    Mail:xiang.okay@gmail.com

热门文章推荐

请稍候...

保利威视云平台-轻松实现点播直播视频应用

酷播云数据统计分析跨平台播放器