[AS3]基于zip加密与解密as3算法
在EncryptZip的开发中, 前端Flex要能够对加密的zip的文件进行解密, 当时网上没有这个功能的现有的代码. 由于我使用的是纯AS代码, 经过比较几个网上现有的zip文件压缩的开源代码, 我采用了nochump, 并尝试在此基础上进行扩展.
zip的开发需要了解zip文件的压缩格式, 每个数据标志位的意义, 好在nochump的代码给出了详细的注释,在此对David Chang (dchang@nochump.com)表示由衷的感谢! 通过结合zip结构文档和nochump源代码,我一边调试,一边注释,这让我快速掌握zip的格式省了不少的时间.
为了验证我对了解zip文件格式是否正确, 用AS编写了一个的zip解压格式测试类, 代码如下:
- /**
- * Copyright (c) 2009 David Yao (xiang.okay@gmail.com)
- * description: This class is supposed to test the information of the format of the encrypt-zip file.
- * author: David Yao
- * mail: xiang.okay@gmail.com
- */
- package nochump.util.test
- {
- import flash.utils.ByteArray;
- import flash.utils.Endian;
- import mx.controls.Alert;
- import nochump.util.extend.ZipCrypto;
- import nochump.util.zip.Inflater;
- import nochump.util.zip.ZipEntry;
- public class TestUpzip
- {
- public function TestUpzip()
- {
- }
- public static function traceInfo(zipByte:ByteArray):void{
- var byteInfo:ByteArray = new ByteArray();
- byteInfo.endian = Endian.LITTLE_ENDIAN;
- zipByte.readBytes(byteInfo);
- byteInfo.position = 0;
- //文件标头区
- var e:ZipEntry = new ZipEntry("yx");
- trace(" 位置 文件标头 :" +byteInfo.position);
- trace(" 文件标头签名:"+byteInfo.readUnsignedInt().toString(16));
- trace(" 所需版本 :"+byteInfo.readUnsignedShort());
- var flag:int = byteInfo.readUnsignedShort();
- trace(" 一般用途位标记:"+flag);
- e.method = byteInfo.readUnsignedShort();
- trace(" 压缩方法:"+e.method);
- var time:uint = byteInfo.readUnsignedInt();
- trace(" 文件的最后修改时间 :"+ time );
- //trace(" 文件的最后修改日期 :"+ time );
- e.crc = byteInfo.readUnsignedInt();
- trace(" crc-32 :"+ e.crc);
- e.compressedSize = byteInfo.readUnsignedInt();
- trace(" 压缩后的大小 :"+ e.compressedSize);
- e.size = byteInfo.readUnsignedInt();
- trace(" 解压缩后的大小 :"+e.size);
- var nal:int = byteInfo.readUnsignedShort();
- trace(" 文件名长度 :"+nal);
- var extL:int = byteInfo.readUnsignedShort();
- trace(" 额外字段长度 :"+ extL);
- e.name = byteInfo.readUTFBytes(nal);
- trace(" 文件名 :"+ e.name);
- if(extL >0)
- byteInfo.readBytes(e.extra,0,extL);
- trace(" 额外字段 :"+ e.extra);
- var plainText:ByteArray = new ByteArray();
- if(flag == 9){
- //数据区
- var ex12Data:ByteArray = new ByteArray();
- var byteData:ByteArray = new ByteArray();
- ZipCrypto.InitCipher("123456");
- byteInfo.readBytes(ex12Data,0,12);
- var DecryptedHeader:ByteArray =ZipCrypto.DecryptMessage(ex12Data,12);
- //判断密码的正确性
- trace(DecryptedHeader[11]);
- trace((time >> 8) & 0xff);
- if (DecryptedHeader[11] != ((e.crc >> 24) & 0xff)){
- if ((9 & 0x0008) != 0x0008){
- throw new Error("The password did not match.");
- }
- else if (DecryptedHeader[11] != ((time >> 8) & 0xff)) {
- throw new Error("The password did not match.");
- }
- }
- byteInfo.readBytes(byteData,0,e.compressedSize-12);
- plainText = ZipCrypto.DecryptMessage(byteData,e.compressedSize-12);
- }
- else{
- byteInfo.readBytes(plainText,0,655);
- }
- trace(" 读完数据区位置 :" +byteInfo.position);
- var b2:ByteArray = new ByteArray();
- var inflater:Inflater = new Inflater();
- inflater.setInput(plainText);
- inflater.inflate(b2);
- Alert.show(String(b2));
- //数据描述符记录
- if(flag == 8 || flag ==9 ){
- trace(" ----------------");
- trace(" 位置 数据描述符记录 :" +byteInfo.position);
- trace(" 数据标签 :" +byteInfo.readUnsignedInt().toString(16));
- trace(" crc-32 :" +byteInfo.readUnsignedInt());
- trace(" 压缩后的大小 :" +byteInfo.readUnsignedInt());
- trace(" 解压缩后的大小 :" +byteInfo.readUnsignedInt());
- }
- //进入中央目录结构->文件标头
- trace(" ----------------");
- trace(" 位置 进入中央目录结构->文件标头:" +byteInfo.position);
- trace(" 中央文件标头签名:"+ byteInfo.readUnsignedInt().toString(16));
- trace(" version made by :"+ byteInfo.readUnsignedShort());
- trace(" 所需版本 :"+ byteInfo.readUnsignedShort());
- trace(" 一般用途位标记 :"+ byteInfo.readUnsignedShort());
- trace(" 压缩方法 :"+ byteInfo.readUnsignedShort());
- trace(" 文件的最后修改时间 :"+ byteInfo.readUnsignedInt());
- trace(" crc-3 :"+ byteInfo.readUnsignedInt());
- trace(" 压缩后的大小 :"+ byteInfo.readUnsignedInt());
- trace(" 解压缩后的大小 :"+ byteInfo.readUnsignedInt());
- var cname:int = byteInfo.readUnsignedShort();
- trace(" 文件名长度 :"+ cname);
- var celength:int = byteInfo.readUnsignedShort();
- trace(" 额外字段长度 :"+ celength);
- var cfplain:int = byteInfo.readUnsignedShort();
- trace(" 文件注释长度 :"+ cfplain);
- trace(" 磁盘开始号 :"+ byteInfo.readUnsignedShort());
- trace(" 内部文件属性 :"+ byteInfo.readUnsignedShort());
- trace(" 外部文件属性 :"+ byteInfo.readUnsignedInt());
- trace(" 相关的标头偏移量 :"+ byteInfo.readUnsignedInt());
- trace(" 文件名 :"+ byteInfo.readUTFBytes(cname));
- trace(" 额外字段 :"+ byteInfo.readUTFBytes(celength));
- trace(" 文件注释 :"+ byteInfo.readUTFBytes(cfplain));
- ////进入中央目录结构->结尾
- trace(" ----------------");
- trace(" 位置 进入中央目录结构->结尾:" +byteInfo.position);
- trace(" 中央目录记录签名 :" + byteInfo.readUnsignedInt().toString(16));
- trace(" 磁盘编号 :" + byteInfo.readUnsignedShort());
- trace(" 中央目录开始磁盘编号 :" + byteInfo.readUnsignedShort());
- trace(" 本磁盘上在中央目录里的入口总数 :" + byteInfo.readUnsignedShort());
- trace(" 中央目录里的入口总数 :" + byteInfo.readUnsignedShort());
- trace(" 中央目录的大小 :" + byteInfo.readUnsignedInt());
- trace(" 中央目录对第一张磁盘的偏移量 :" + byteInfo.readUnsignedInt());
- var cLeng:int = byteInfo.readUnsignedShort();
- trace(" .ZIP 文件注释长度 :" + cLeng);
- trace(" .ZIP 文件注释 :" + byteInfo.readUTFBytes(cLeng));
- trace(" 结束位置 :" +byteInfo.position);
- }
- }
- }
在此时我用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
热门文章推荐
- [HLS]做自己的m3u8点播系统使用HTTP Live Streaming(HLS技术)
- [FMS]FMS流媒体服务器配置与使用相关的介绍
- [AS3]什么是M3U8,与HTML5的区别是什么
- AS2.0 让flash自适应全屏,并且不自动缩放
- [AS3]as3.0的sound类常用技巧整理
- [AS3]as3与ByteArray详解、ByteArray介绍、ByteArray用法
- 关于RTMP,RTMPT,RTMPS,RTMPE,RTMPTE协议的介绍
- [JS]分享浏览器弹出窗口不被拦截JS示例