IBOutlet和IBAction

Categories: Objective C
Tags: No Tags
Comments: Comments Off
Published on: 2012 年 05 月 22 日

IBOutlet和IBAction 是为了你在interface building 设计交互界面的时候告诉它这些是你要用到的,其他的没标明的都是不需要直接和界面交互的。

 

简单理解:

 

假设有两个黑盒子:
盒子A里放着代码 ,盒子B里放着盒子A要用到的ui组件
要想让A里的代码访问到B里的组件,比如想要修改label的文字 ,那些就要从A处打个洞连到B处,这时就用IBOutlet
B中的组件如一个按钮被用户点击了 ,要给A发个通知,那么也要事先在A处安个接受装置,这时就用IBAcion

 

看字面意思就知道了啊,OUTLET,就是插座,对外放电的,插头就是ACTION,把插座里的电引到电器上

 

IBOutlet是控件的引用,比如我想在程序中对控件进行操作,那么就需要将控件声明为IBOutlet。IBAction是控件要执行的动作或事件。

 

IBOutlet关键字的定义如下所示:

#ifndef IBOutlet
#define IBOutlet
#endif

#ifndef IBAction
#define IBAction void
#endif

感到困惑了吗?就编译器而言,IBOutlet并未执行任何操作。它的唯一作用是告诉Interface Builder,此实例变量将被连接到nib中的对象。你创建的任何需要连接到nib文件中的对象的实例变量都必须以IBOutlet关键字开头。打开 Interface Builder时,它会在项目头文件中扫描此关键字,你可以根据这些(且只能根据这些)变量将代码连接到nib。

http://eyecm.com/iboutlet-and-ibaction-that/

 

内存管理

如果一个变量在类中被定义为了 IBOutlet 那么你无需对其进行实例化,xib载入器会对其初始化。
如果一个变量在类中被定义为了 IBOutlet 那么你必须负责将其释放。xib载入器不会帮忙的… …
*切不要初始化两回,内存会溢出,而且对象锁定也会出错。

 

需要注意的是,任何一个被声明为IBOutlet并且在Interface Builder里被连接到一个UI组件的成员变量,会被额外retain一次。
常见的情形如: IBOutlet UILabel *label;
这个label在Interface Builder里被连接到一个UILabel。此时,这个label的retainCount为2。
所以,只要使用了IBOutlet变量,一定需要在dealloc或者viewDidUnload里release这个变量。

Objective C 属性

Categories: iOS, iPAD, Objective C, XCode
Tags: No Tags
Comments: Comments Off
Published on: 2012 年 05 月 22 日

为每一个变量实现其访问器,繁琐,@property 可以替我们减轻工作。

是否暴露读写接口

readonly 将只生成getter方法而不生成setter方法(getter方法没有get前缀)。
readwrite 默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数)。

线程安全

atomic 对于对象的默认属性,就是setter/getter生成的方法是一个原子操作。如果有多个线程同时调用setter的话,不会出现某一个线程执行setter全部语句之前,另一个线程开始执行setter的情况,相关于方法头尾加了锁一样。

(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所 以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)

nonatomic 不保证setter/getter的原子性,多线程情况下数据可能会有问题。iPhone只能用nonatomic。

赋值(setter)的工作机制

assign

指定setter方法用简单的赋值,这是默认操作。你可以对基础数据类型(如int)使用这个属性。

你可以想象一个float,它不是一个对象,所以它不能retain、copy。

对基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等) 适用简单数据类型或对指针的弱引用

典型的适用数据类型:NSInterger,CGFloat和C数据类型(int,float,double,char等等)。

如果使用对象类型的参数,需要开启garbage collector
[现在的版本叫引用计数器 不同的版本不同的叫法 在mac编程和在iphone编程中的叫法也不同 谅解 谅解 ]

retain 指定retain应该在后面的对象上调用,前一个值发送一条release消息。
你可以想象一个NSString实例,它是一个对象,而且你可能想要retain它。
典型的数据类型:针对NSObject及其子类 如果启用了garbage collector 和assign 的作用一样
  1. - (void)setName:(NSString *)newName {
  2. if (name != newName) {
  3. [name release];
  4. name = [newName retain];
  5. // name’s retain count has been bumped up by 1
  6. }
  7. }
copy 指定应该使用对象的副本(深度复制),前一个值发送一条release消息。
基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。
典型的数据类型:NSString

比如一个NSString 对象,地址为0×1111 ,内容为@”STR”

Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同,新的对象retain为1 ,旧有对象没有变化

retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1

retain 是指针拷贝,copy 是内容拷贝

@synthesize

在 *.h 文件中,使用 @property 设置好属性的值后,在 *.m 文件中还要用 @synthesize 来定义实现的。

@synthesize xxx; 为前面定义的属性xxx自动生成读写函数;

@synthesize是objective-c 2.0的新特性,它的作用就是自动为你定义的成员变量生成get和set方法。
比如你定义了bear属性,
CCSprite *_bear;
你需要同时定义
@property (nonatomic, retain) CCSprite *bear;
和 @synthesize bear = _bear;
这样,编译器才能为你生成get和set方法。
本例中就会为你生成下列两个方法:

-(CCSprite*) getBear{
return _bear;
}
-(void) setBear:(CCSprite*)bear{
if(_bear != bear){
[_bear release];
_bear = [bear retain]; //这里会是retain 跟你在@property(nonatomic,retain)中申明了retain有关。
}
}

为什么会是bear = _bear呢?

这是固定用法。如果你的成员变量的名字也是bear,那么就不要这个等于号。直接可以写成 @synthesize bear;这也是你看到的比较多的写法。

http://www.haogongju.net/art/1307400

属性用的成员变量

如上面写的, 可以在 @synthesize 时指定用那个成员变量。

成员变量 在之前版本需要自己书写,最新版本可以编译器帮我们产生。

image_thumb[1]

http://www.2cto.com/kf/201202/120763.html

http://unmi.cc/objective-c-proerty-synthsiz

参看:

Objective-C中类属性的 copy, tetain, assign , readonly , readwrite, nonatomic区别

http://spring-studio.net/?p=219

nonatimic,retain,assign,copy,readonly,readwrite

http://southking.iteye.com/blog/1487793

分析yum安装的tomcat

Categories: tomcat
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 10 月 14 日

问题:

centos 5.5 上用 yum 安装了 tomcat, 启动正常,但是访问 8080 端口的网页,是空白的。

 

 

查看linux版本

[root@inside ~]# lsb_release -a
LSB Version:    :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:graphics-3.1-ia32:graphics-3.1-noarch
Distributor ID: CentOS
Description:    CentOS release 5.5 (Final)
Release:        5.5
Codename:       Final

 

http://www.51testing.com/?uid-89868-action-viewspace-itemid-11978

 

查看Tomcat安装目录

先查看使用 yum 安装了那些 名字包含tomcat的软件

[root@inside ~]# rpm -qa|grep tomcat
tomcat5-servlet-2.4-api-5.5.23-0jpp.19.el5_6
tomcat5-jasper-5.5.23-0jpp.19.el5_6
tomcat5-jsp-2.0-api-5.5.23-0jpp.19.el5_6
tomcat5-server-lib-5.5.23-0jpp.19.el5_6
tomcat5-common-lib-5.5.23-0jpp.19.el5_6
tomcat5-5.5.23-0jpp.19.el5_6

查看安装目录
[root@inside ~]# rpm -ql tomcat5
/etc/logrotate.d/tomcat5
/etc/rc.d/init.d/tomcat5
/etc/sysconfig/tomcat5
/etc/tomcat5
/etc/tomcat5/Catalina
/etc/tomcat5/Catalina/localhost
/etc/tomcat5/catalina.policy

 

从上面可以分析出 tomcat5 的 配置目录 /etc/tomcat5

 

 

查看 tomcat 5 的配置:

[root@inside bin]# tomcat5
Found JAVA_HOME: /usr/lib/java
Please complete your /etc/tomcat5/tomcat5.conf so we won’t have to look for it next time
Using CATALINA_BASE:   /usr
Using CATALINA_HOME:   /usr
Using CATALINA_TMPDIR: /usr/temp
Using JRE_HOME:
Usage: dtomcat5 ( commands … )
commands:
  debug             Start Catalina in a debugger
  debug -security   Debug Catalina with a security manager
  jpda start        Start Catalina under JPDA debugger
  run               Start Catalina in the current window
  run -security     Start in the current window with security manager
  start             Start Catalina in a separate window
  start -security   Start in a separate window with security manager
  stop              Stop Catalina
  stop -force       Stop Catalina (followed by kill -KILL)
  version           What version of tomcat are you running?

http://tenhlf.blog.163.com/blog/static/5363158120094285224660/

 

启动 Tomcat

[root@inside ~]# service tomcat5 restart
Stopping tomcat5:                                          [  OK  ]
Starting tomcat5:                                          [  OK  ]
从上面可以看到,启动正常

 

检查端口开放状况

netstat –nat

可以看到 8080 端口是处于监听状态的。

 

CentOS下Tomcat5.5安装(附带jdk1.6安装)
http://blog.csdn.net/txg703003659/article/details/6620212

 

分析了好久没找到原因,卸掉重装。

 

http://confluence.atlassian.com/display/JIRA041/Installing+JIRA+on+Tomcat+5.5

 

参考资料:

CentOS5.5下安装JDK和Tomcat

http://blog.csdn.net/ppzlyg/article/details/6077794

CentOS yum安装Apache + PHP + MySQL + Tomcat
http://geniux.net/glog/431

Native APP 和 WEB APP 在用户体验上的差别

Categories: android
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 10 月 06 日
WEB APP的跨平台特性确实很吸引人,但是大家普遍都认为WEB APP在用户体验上,目前软硬件环境下,还是不如Native APP。 具体是那些方面不如呢?下面是我的总结:
一、进程切换的体验差异
不考虑机器性能和网速,WEB APP 最大的不足在于进程切换。
比如:Native APP 中,我能在Mail里面直接拖入图片作为附件,GMail就只能attach a file。
又比如: Gmail WebAPP for iPad 的手感不如Mail,虽然功能很好,但是手指滑动时,感觉非常滞涩,远远不如Mail的滑动体验。
WEB APP的滑动效果必须通过 CSS3 和 JS 写出来。相对来说 CSS3 的效果要比 JS 流程些。
但是浏览器支持不支持,支持多少,性能优化的如何,都还需要慢慢演化。
一个用户操作,500毫秒的响应时间 和250 毫秒的响应时间,在开发者来说其实差别不大,要让用户来描述两个的具体差别页很难说清楚,但是潜意识里这样的差距就会慢慢累计起来,成为影响用户体验的重要原因。
 
二、WEB APP 无法访问本地的外设
比如:USB 接口,通讯录,录音设备等 一些数据采集设备等等。WEB APP 是无法使用的。
本机存储的文件也是无法读取的。
通过语音操作,通过复杂一些手势操作,在WEB APP 上都是比较困难的。
又比如 WEB APP 暂时还没办法充分利用手机的特性,比如陀螺仪。
所以如果你是开发游戏APP的话,大部分时候,几乎只能选择 Natvie APP
 
三、网页的快捷方式
不借助Native APP,无法把打开指定网页的快捷方式放入启动栏或者桌面。
Android 实现把特定网页打开的快捷方式放入桌面的请参看这篇文章。它其实是借用了 Native APP 才实现这个功能。
 
四、盈利模式
试想一下,如果没有 Native APP,全部是 WEB APP, 那盈利模式就会变成一个大问题。如何收到钱呢?
而且用户在手机上往往不愿意在多个网站上去登录自己的网银账户。
 
五、网络状况

如果不用Html5的离线存储。网络状况是非常大的问题。
比如用 Google Docs 写稿,如果网络状况不佳,可能会导致反复存盘失败,本地文字编辑器当然没有这个问题。
虽说 HTML 5 的本地存储 (Local Storage)可以搞定这个问题。但是你很难想象把整个Gmail 都通过浏览器拖到本地–它太大了。而且就算全部存下来,JavaScript的执行效率还是没法和本地代码相提并论。
用 Google Gears 实现的离线 Gmail 到现在都很步好用,因为有些重要的功能必须要在服务器端实现,比如搜索。
如果是展示类应用,视频文件的本地存储会是一个很大的数据量,同理上面的道理。
 
六、进程间互动(进程间通讯)
比如:我们可以在iPhone里面拖拽几张照片到Mail里面发送,Gmail就无法做到。
比如我们可以通过点击连接调用手机的地图功能,或者调用打电话功能。
网页方式就无法。
 
七、信任
上面提到的都是技术问题,随着时间的推移,是可以解决的。但是时间会很久。
我信任Google,所以重要的邮件,甚至密码我都敢放在Google的服务里面。比如Gmail。
但是随便一个第三方的线上软件,我可能就会比较小心。
针对企业的应用为何要做局域网的应用,希望离开了企业无法使用。
也是基于这个信任的考虑。
而相对来说 Native APP,这方面的信任度要高于WEB APP。
当然国内会有被墙掉的问题,Native APP优势更大。
这种信任也是人心里认知上的一个壁垒。
对于用户来说,真正的软件就是那种自己单独一个窗口(而不是一个标签页),单独一个图标(而不是诸如Firefox图标中的一个)的东西。这是始于1984年的麦金塔GUI多年以来给大家装下的观念。
虽然 WEB APP 是趋势, Native APP 是现在,其实对现在来说,WEB APP 和 Native APP的融合才是现在最好的解决方案。现在一般情况是:Native APP 为主,WEB APP为辅(一定程度上减小工作量),这可以同时借用这两个的优点。避免他们的缺陷。
 
参考资料:
web app vs. native app
 
Web App 和 Native App,哪个是趋势?
 
跨平台手机应用开发
 
[讨论] 线上软件 vs. 桌面软件

UUID(GUID)

Categories: android, MySQL, php
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 09 月 21 日

UUID 和 GUID 的区别

UUID是一个由4个连字号(-)将32个字节长的字符串分隔后生成的字符串,总共36个字节长。比如:550e8400-e29b-41d4-a716-446655440000

http://gohands.blogbus.com/logs/147479174.html

GUID 是微软对UUID这个标准的实现。UUID是由开放软件基金会(OSF)定义的。UUID还有其它各种实现,不止GUID一种。比如我们这里在Java中用到的。

http://baike.baidu.com/view/1052579.htm

COMB(combine)型是数据库特有的一种设计思想,可以理解为一种改进的GUID,它通过组合GUID和系统时间,以使其在索引和检索事有更优的性能。
http://blog.csdn.net/happyflystone/article/details/1903854

数据库中没有COMB类型,它是Jimmy Nilsson在他的“The Cost of GUIDs as Primary Keys”一文中设计出来的。

COMB数据类型的基本设计思路是这样的:既然UniqueIdentifier数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么我们能不能通过组合的方式,保留UniqueIdentifier的前10个字节,用后6个字节表示GUID生成的时间(DateTime),这样我们将时间信息与UniqueIdentifier组合起来,在保留UniqueIdentifier的唯一性的同时增加了有序性,以此来提高索引效率。

http://hi.baidu.com/%CA%AB%D5%B9/blog/item/407fd23f77d5eacf7c1e7122.html

 

Android 使用代码:

JDK1.5开始支持UUID,Android也支持UUID http://developer.android.com/reference/java/util/UUID.html

那么生成UUID变成了一件简单的事,因为JDK实现了UUID: java.util.UUID,直接调用即可.
UUID uuid  =  UUID.randomUUID();
String s = UUID.randomUUID().toString();//用来生成数据库的主键id非常不错。 

import java.util.UUID;

UUID uid = UUID.randomUUID();

 

SQLIte 使用例子

// 插入数据
UUID locationID = UUID.randomUUID(); 
ContentValues initialValues = new ContentValues(); 
initialValues.put("rowid", locationID.toString()); 
//...other stuff...// 
db.insert(DATABASE_TABLE_LOCATIONS, null, initialValues);

// 搜索
Cursor c = 
db.query(true, DATABASE_TABLE, new String[] { 
                "rowid", "stuff", "things"}, "rowid='" + rowId + "'", 
null, null, null, null); 
 

以上代码出自: http://groups.google.com/group/android-developers/browse_thread/thread/4a6c40702107fa16

 

SQL 语句

CREATE TABLE Users 
( 
   UserGuid TEXT PRIMARY KEY NOT NULL,  
   FirstName TEXT,  
   LastName TEXT 
) 

INSERT INTO Users (UserGuid, FirstName, LastName)  
VALUES ('e7bf9773-8231-44af-8d53-e624f0433943', 'Bobby', 'Bobston') 

DELETE FROM Users WHERE UserGuid = 'e7bf9773-8231-44af-8d53-e624f0433943' 

以上语句来源: http://zh-cn.w3support.net/index.php?db=so&id=1055848

 

MYSQL

在mysql中有函数生成guid:SELECT UUID();

一般我们用CHAR(36)或者BINARY(36)类型来存储uuid。

 

PHP 使用 UUID

PHP下生成GUID

http://www.cnblogs.com/ovliverlin/archive/2008/08/27/932444.html

PHP function to generate v4 UUID

http://stackoverflow.com/questions/2040240/php-function-to-generate-v4-uuid

Android地图Key

Categories: android
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 07 月 18 日

由于Android内置的地图是google地图,它需要访问google服务器获取地图信息,所以首先你需要注册一个使用Google地图的API的Key,没有它Google地图不会为你提供服务。

地图API的Key是跟你程序的签名证书紧密相关的。所以你如何要申请地图API的Key,首先要明白你的签名证书文件,有关签名证书文件以及签名应用的知识请参看我前篇文章:《Android应用签名

整个Google地图API的Key申请和使用流程如下:

  1. 找到你的应用程序对应的签名文件(模拟器调试的签名文件是ADT替我们产生的,所以需要去找一下;发布生产版本的是我们自己产生的证书文件,我们直接就知道这个文件是在哪里。)
  2. 通过keytool工具,获得证书文件的MD5码。调试签名文件的alias,storepass,keypass都是固定的,直接使用即可,生产环境的这个是我们自己配置的,我们当然自己知道了。
  3. 在Google站点:http://code.google.com/intl/zh-CN/android/maps-api-signup.html 输入上述产生的MD5字符串,产生我们要使用的API的Key。
  4. 使用地图API的Key更新com.google.android.maps.MapView的android:apiKey属性,使用这个Key。

具体步骤如下:

步骤一:找到对应的签名文件。

如同上面说的,只有模拟器调试的应用才需要这一步,生产环境证书文件是我们自己产生的,我们知道如何做。

生产环境如何产生签名文件请参看我的前一篇文章:《Android应用签名

模拟器测试使用的证书文件可以在eclipse菜单的 Window -> Preferences -> Android –> Build 中找到,如下图:

image

 

步骤二:通过keytool工具,获得证书文件的MD5码

如果是模拟器调试证书文件,就很简单,下面就是它的演示。

E:\>keytool -list -alias androiddebugkey -keystore "C:\Users\1\.android\debug.keystore" -storepass android -keypass android
androiddebugkey, 2011-4-17, PrivateKeyEntry,
认证指纹 (MD5): 52:2A:38:E3:28:3E:0A:9C:61:B6:92:B7:3C:25:EF:61

E:\>

模拟器签名文件的 alias  固定是 androiddebugkey ,storepass 和 keypass 都是android。 所以上面命令中你只需要把第一步获得证书文件的目录替换就是你的场景。

生产环境则需要修改成你自己的 alias ,storepass 和 keypass,以及签名文件目录。

 

步骤三、在Google站点:http://code.google.com/intl/zh-CN/android/maps-api-signup.html 输入上述产生的MD5字符串,产生我们要使用的API的Key。

如下:

image

点击 Generate API Key 后,显示的信息如下:

image

 

步骤四,修改MapView

<com.google.android.maps.MapView 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:apiKey="0xu5YrgQ_w5LystSrOrOpj2aLmkZoVr6_mjE2mA" 
/>

 

其中的步骤一,二可能会根据你是模拟器测试还是生成环境不一样,步骤三,步骤四不论是那种情况,都是一样的。

 

参考资料

android开发中-使用MapView和MapActivity — 注册Google MAP API

http://www.android777.com/index.php/tutorial/android-view/using-the-mapview-and-mapactivity-up-google-map-api.html

Android应用签名

Categories: android
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 07 月 18 日

为了要签名?

    开发Android的人这么多,完全有可能大家都把类名,包名起成了一个同样的名字,这时候如何区分?签名这时候就是起区分作用的。

    由于开发商可能通过使用相同的Package Name来混淆替换已经安装的程序,签名可以保证相当名字,但是签名不同的包不被替换。

    APK如果使用一个key签名,发布时另一个key签名的文件将无法安装或覆盖老的版本,这样可以防止你已安装的应用被恶意的第三方覆盖或替换掉。

    这样签名其实也是开发者的身份标识。交易中抵赖等事情发生时,签名可以防止抵赖的发生。

 

签名的注意事项

  • 所有的Android应用都必须有数字签名,没有不存在数字签名的应用,包括模拟器上运行的。Android系统不会安装没有数字证书的应用。
  • 签名的数字证书不需要权威机构来认证,是开发者自己产生的数字证书,即所谓的自签名。
  • 模拟器开发环境,开发时通过ADB接口上传的程序会先自动被签有Debug权限,然后才传递到模拟器。如下图所示,Eclipse菜单的Window -> Preferences -> Android –> Build 下显示的是我们默认的调试用的签名数字证书。

image

  • 正式发布一个Android应用时,必须使用一个合适的私钥生成的数字证书来给程序签名,不能使用ADT插件或者ANT工具生成的调试证书来发布。
  • 数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。
  • 签名后需使用zipalign优化程序。
  • Android将数字证书用来标识应用程序的作者和在应用程序之间建立信任关系,而不是用来决定最终用户可以安装哪些应用程序。

签名的方法

方法一、使用Eclipse工具

此方法适用于Android1.5及以上版本。

步骤一:打开Eclipse->选择你要签名的项目->右击->android tools->Export signed Application package

image

步骤二,在出现的窗口确认是不是这个项目要签名,然后选择下一步:

image

步骤三:在Export Android Application 这一步,如果我们之前已有有了 keystore, 选择我们之前已有的,否则我们新建一个。

如下,选择需要保存这个证书文件的目录,以及这个证书文件的一个密码。

image

步骤四,点击下一步后,我们需要填写keystore的基本信息,如,别名,密码,有效期,姓名,组织,组织名称,所在城市,所在省份,国家等,点击Next

image

步骤五、选择被签名后的APK保存位置。点击finish。注意是选择最终将产生的文件。

image

之后我们在刚才选择的目录下就可以看到生成的签名后的APK文件。

方法二:使用命令行方式签名。

这种方式比起前面要复杂很多了,但是却对我们理解APK文件有很多帮助。这里我们是使用Keytool和Jarsigner给程序签名。

keytool 是个密钥和证书管理工具。jarsigner 工具利用密钥仓库中的信息来产生或校验 Java 存档 (JAR) 文件的数字签名 (JAR 文件将类文件、图象、声音和/或其它数字化数据打包在一个文件中)。

这两个工具都是JDK自带的,所以你当前需要先确保JDK安装正确。并且环境变量设置正确,以便可以以命令行的方式进行处理。

 

步骤一:用 KeyTool 产生证书文件

下面是我随便生成的一个证书文件:

E:\Projects\cybercare.cn\trunk\android\ks2>keytool -genkey -keystore ks2.keystor
e -keyalg RSA -validity 10000 -alias ks2.keystore
输入keystore密码:
您的名字与姓氏是什么?
  [Unknown]:  www.cybercare.cn
您的组织单位名称是什么?
  [Unknown]:  Cybercare
您的组织名称是什么?
  [Unknown]:  津驰速信
您所在的城市或区域名称是什么?
  [Unknown]:  北京
您所在的州或省份名称是什么?
  [Unknown]:  北京
该单位的两字母国家代码是什么
  [Unknown]:  CN
CN=www.cybercare.cn, OU=Cybercare, O=津驰速信, L=北京, ST=北京, C=CN 正确吗?
  [否]:  y

输入<ks2.keystore>的主密码
        (如果和 keystore 密码相同,按回车):
再次输入新密码:

E:\Projects\cybercare.cn\trunk\android\ks2>

命令参数说明:

-genkey    产生证书文件
-keystore  指定密钥库的.keystore文件中

-keyalg     指定密钥的算法

-validity    为证书有效天数,这里我们写的是10000天。
-alias       产生别名

在输入密码时没有回显,只管输入就可以了,一般位数建议使用20位,切忌需要记下来后面还要用,

注意:

1、CN(Common Name – 名字与姓氏):其实这个“名字与姓氏”应该是域名,比如说localhost或是blog.devep.net之类的。输成了姓名,和真正运行的时候域名不符,会出问题。浏览器访问时,弹出一个对话框,提示“安全证书上的名称无效,或者与站点名称不匹配”,用户选择继续还是可以浏览网页。但是用http client写程序访问的时候,会抛出类似于“javax.servlet.ServletException: HTTPS hostname wrong: should be ”的异常。

2、在用keytool生成数字证书时必须保证:-keystore androidapp.keystore -alias androidapp.keystore 两者名称必须相同。否则下一步签名时会出现错误:jarsigner: 找不到 androidapp.keystore 的证书链。androidapp.keystore 必须引用包含专用密钥和相应的公共密钥证书链的有效密钥库密钥条目。

 

 

KeyTool的更多参数说明可以看这篇文章:

http://www.cnblogs.com/kungfupanda/archive/2010/09/01/1815047.html

 

步骤二:导出未签名的APK文件

 

方法一:使用Eclipse

打开Eclipse->选择你要导出的项目->右击->android tools->Export Unsigned Application package

image

然后在选择保存文件目录和文件名对话框中输入你想保存的地址,确认后导出后提示信息类似如下:

image

方法二:

使用Eclipse,在Package Explorer中选择Androidmanifest.xml文件,找到overview项中,单击Export the unsigned apk,如图

image

注意:

http://www.android123.com.cn/kaifafaq/175.html 提供的方法二:

直接进入工程文件夹的bin目录,比如我们的为C:\Documents and Settings\Administrator\workspace\android123\bin\android123.apk,直接复制出来就是未签名的APK文件。

这个方法并不可取,这个方法取出来的是加了Debug签名的APK文件,而不是未签名的APK文件。

 

 

步骤三,使用产生证书文件签名

下面是我签名我一个之前写的演示程序的执行效果:

E:\Projects\cybercare.cn\trunk\android\ks2>jarsigner -verbose -keystore ks2.keystore -signedjar GasBuddy_signed_00.apk GasBuddy002.apk ks2.keystore
输入密钥库的口令短语:
输入 ks2.keystore 的密钥口令:
   正在添加: META-INF/MANIFEST.MF
   正在添加: META-INF/KS2_KEYS.SF
   正在添加: META-INF/KS2_KEYS.RSA
  正在签名: res/layout/active.xml
  正在签名: res/layout/businessmeninfo_activitylayout.xml
  正在签名: res/layout/businessmeninfo_commentinfo_layout.xml
  正在签名: res/layout/businessmeninfo_commentlist_layout.xml
  正在签名: res/layout/businessmeninfo_information_layout.xml
  正在签名: res/layout/businessmeninfo_pointcardinfo_layout.xml
  正在签名: res/layout/businessmeninfo_pointcardlist_layout.xml
  正在签名: res/layout/commen_publish.xml
  正在签名: res/layout/discount_gasstation_foot_layout.xml
  正在签名: res/layout/discount_gasstation_head_layout.xml
  正在签名: res/layout/discount_gasstation_layout.xml
  正在签名: res/layout/discount_gasstation_list_activitylayout.xml
  正在签名: res/layout/discount_gasstation_title_layout.xml
  正在签名: res/layout/login.xml
  正在签名: res/layout/main.xml
  正在签名: res/layout/menu_activitylayout.xml
  正在签名: res/layout/my_point_gasstation.xml
  正在签名: res/layout/my_point_gasstation_view.xml
  正在签名: res/layout/nearby_gasstation.xml
  正在签名: res/layout/overlay_pop.xml
  正在签名: res/layout/register.xml
  正在签名: res/layout/splash_layout.xml
  正在签名: AndroidManifest.xml
  正在签名: resources.arsc
  正在签名: res/drawable-hdpi/bubble_background.9.png
  正在签名: res/drawable-hdpi/icon.png
  正在签名: res/drawable-hdpi/marker.png
  正在签名: res/drawable-hdpi/u25.png
  正在签名: res/drawable-hdpi/u30.png
  正在签名: res/drawable-ldpi/icon.png
  正在签名: res/drawable-mdpi/icon.png
  正在签名: classes.dex

E:\Projects\cybercare.cn\trunk\android\ks2>

 

有关 jarsigner 参数的详细信息可以参看
http://www.android123.com.cn/androidkaifa/173.html

 

解决对android APK 项目进行签名过程中遇到的问题
http://zhangkun716717-126-com.iteye.com/blog/774382

参考资料

Android签名用keytool和jarsigner制作apk文件
http://www.android123.com.cn/androidkaifa/173.html

如何导出一个未签名的APK文件?
http://www.android123.com.cn/kaifafaq/175.html

无法对jar进行签名,Android jarsigner问题
http://www.android123.com.cn/kaifafaq/183.html

有关Android签名问题总结
http://www.android123.com.cn/androidkaifa/272.html

Android 签名详解
http://yangguangfu.iteye.com/blog/723182

android签名apk批处理文件
http://phenix.blogbus.com/logs/60336413.html

android签名与release
http://my.chinaunix.net/space.php?uid=20665441&do=blog&id=377220

QQ阅读模板分析

Categories: QQ阅读
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 07 月 05 日

模板的定义

QQ 阅读预先定义了一些模板,有哪些模板可以在下面数组中可见:
其中 tmp后面的第一个数据标识这个模板分几块,第二个数字标识这是分几块模板的第几套模板

这个模板在下面文件的  15004 行可见
http://rescdn.qqmail.com/rss/zh_CN/htmledition/js/reader/reader069eec.js

var 
adw=
{
1:['tmp1_1'],
2:['tmp2_1'],
3:['tmp3_1'],
4:['tmp4_1','tmp4_2','tmp4_3'],
5:['tmp5_1','tmp5_2','tmp5_3','tmp5_4','tmp5_5','tmp5_6'],
6:['tmp6_1'],
7:['tmp7_1']
}, 

这个js的文件加载比较特殊,在QQ阅读的页面

http://reader.qq.com/cgi-bin/rss_index?t=r_index&source=login&r=9c8508017c08456f036657e3e539#mag,10005/0/6 

是通过下面代码加载的:

<script>	
function loadJsFile(_aoFiles)
{
	var _oHead = document.getElementsByTagName("head")[0];
	for (var i=0, _len=_aoFiles.length; i<_len; i++)
	{
		var s = document.createElement("script");
		s.src = _aoFiles[i];
		s.charset = "GB18030";
		_oHead.appendChild(s);	
	}
}

if (top == self)
{
	loadJsFile([
		"/cgi-bin/rss_main?sid=MTOtOYx56MMzN9&t=reader_data.js&s=mag&r=388&init=true&update=1", 
		"http://rescdn.qqmail.com/rss/zh_CN/htmledition/js/reader/reader069eec.js"	
	]);
}
else
{
	//for webqq2
	document.write('<script src="/cgi-bin/rss_main?sid=MTOtOYx56MMzN9&t=reader_data.js&s=mag&r=464&init=true&update=1"></scr'+'ipt>');
	document.write('<script src="http://rescdn.qqmail.com/rss/zh_CN/htmledition/js/reader/reader069eec.js"></scr'+'ipt>');
}
</script>

每套模板的样式文件我们可以在对应的 qboard 开头的CSS中定义,不同宽度的屏幕是不同的css:

<script>
	gbISbigScreen = false;
	if(screen.width>1279&&screen.height>899){
		document.write('<link rel="stylesheet" type="text/css" href="http://rescdn.qqmail.com/rss/zh_CN/htmledition/style/reader/r_bigscreen02aad7.css" />');
		document.write('<link rel="stylesheet" type="text/css" href="http://rescdn.qqmail.com/rss/zh_CN/htmledition/style/reader/qboard_bigscreen02aad7.css" />');
		gbISbigScreen = true;
	}
	else
	{
		document.write('<link rel="stylesheet" type="text/css" href="http://rescdn.qqmail.com/rss/zh_CN/htmledition/style/reader/qboard02aad7.css" />');
	}
	if (top != self) {document.write('<link rel="stylesheet" type="text/css" href="http://rescdn.qqmail.com/rss/zh_CN/htmledition/style/reader/r_webqq02aad7.css" />')} 
</script>

以模板3_1 为例,,它的样式如下: tmp3 这里的三标识他内部有三个区块, box0,box1,box2 分别就是这三个区块:

每个区块都可能有 图(articleimg )也可能有内容(singlecontent )。

/* 模板3_1 b */
.tmp3_1 .box0 {width:600px; border-right:1px solid #D9D9D9; height:535px; overflow:hidden; float:left;}
.tmp3_1 .box0 .singlecontent {margin:0 10px 0 0; height:530px; overflow:hidden;}
.tmp3_1 .box0 .articleimg {width:590px; height:330px; overflow:hidden;}
.tmp3_1 .box0 .articleimg img {width:590px}

.tmp3_1 .box1 {width:469px; height:265px; border-bottom:1px solid #D9D9D9; overflow:hidden;  float:left;}
.tmp3_1 .box1 .singlecontent {margin:0 0 10px 10px; height:235px; overflow:hidden;}
.tmp3_1 .box1 .articleimg {width:250px; height:180px; overflow:hidden; margin-right:10px; float:left;}
.tmp3_1 .box1 .articleimg img {width:250px}

.tmp3_1 .box2 {width:469px; height:269px; overflow:hidden;  float:left;}
.tmp3_1 .box2 .singlecontent {margin:10px 0 0 10px;  height:235px; overflow:hidden;}
.tmp3_1 .box2 .articleimg {width:250px; height:180px; overflow:hidden; margin-right:10px; float:left;}
.tmp3_1 .box2 .articleimg img {width:250px}

获取数据

image

这个入口页的数据是通过下面的网址获得的。它返回的是一个 json 数据

http://reader.qq.com/cgi-bin/rss_main?sid=MTOtOYwpx56MMzN9&t=reader_data.js&s=mag&r=222&init=true&update=1

 

image

这个页面的数据是通过下面网址获得的数据,返回的数据也是 json 格式的,注意这里一次性取了30篇文章的摘要等列表信息。

30篇文章最终会被分成7页

这些数据中包含文章的标题、摘要,包含的图片(数量地址尺寸等), 视频,音乐,评论分享等。

http://reader.qq.com/cgi-bin/rss_list?r=13098493385&pagetype=mag&page=0&perpage=30&mode=digest&cache=save&id=10005&sid=MTOtOYwpxMMzN9&t=reader_data.js&s=art&resp_charset=UTF8

image

最终内容页,是通过下面网址获得的数据,注意,这里一次性获得了30篇文章。

http://reader.qq.com/cgi-bin/rss_list?r=13098433171&pagetype=mag&page=0&perpage=30&mode=detail&cache=load&id=10005&sid=MTOOYwpx56MMzN9&t=reader_data.js&s=art&resp_charset=UTF8

模板匹配算法

前面提到, 从服务器端下载30篇文章的信息, 然后分成7页。

那么第一页一共几篇文章,第二页一共几篇文章是如何算的呢?

 

  • 先假设我们取的数据可以分7页。混淆后代码的 bac 这个变量记录这个信息
  • 我们开始遍历下载下来的文章(应该是在30篇以内的,含30).我们根据一定算法计算累计文章的权重,一旦权重合计超过270,就分页。这样,我们就可以知道每一页应该放几篇文章,分别是哪几篇文章。这个算法的代码如下:代码我增加了一下注释,标明权重的算法。
while(gF<aQ&&gV<bac)
{
   var bsV=Number(ve[gF].split("_").join("").substring(ve[gF].length-5),10);
   var dF=aOO[gF];

   if(dF.unread==1)
   {
      alS=true;
   }

   var aKc=0;
   if(dF.images&&dF.images.width>qg)
   {
     // 有图片,且图片宽度大于 150, 则权重加50
     // qg 是常量, 150 ,在外部定义
     bYg=true;
     aKc+=50;
   }
   else
   {
      // 没有图,权重 20
      aKc+=20;
   }
   RR+=aKc;

   // 标题,正文最大长度
   var aex=Math.max(
      dF.title.length+dF.content.length,
      dF.root?(dF.root.title.length+dF.root.content.length):0,
      dF.webpage?(dF.webpage.title.length+dF.webpage.content.length):0
   );

   var aPl;
   if(aex>1000)
   {
      // 如果总内容长度超过 1000 ,权重 加 30 
      aPl=30;
   }
   else
   {
      // 如果总内容长度没有超过 1000, 权重加 10
      aPl=10;
   }
   RR+=aPl;

   gV=gF+1-Np;

   var bGl=adw[gV].length;

   // 初始权重
   !aby[gV]&&(aby[gV]=0);
   var bkx=(bGl-aby[gV])*70;
   RR+=bkx;

   // 从 文章编号字符串中提取的数字,限定40以内 加在权重上
   // 编号的最后下划线部分
   bsV%=40;
   RR+=bsV;



   gF++;

   // 累计权重超过 270, 需要分页
   if(RR>270)
        break;

   // 初始权重只应该被加一次
   RR-=bkx;
}
  • 我们把分页逻辑存入 OV 这个混淆过的变量中。后面的显示,以及实际是分了几页,都是基于这个对象。
  • 一页显示几篇文章,就限定了该页可用的模板数。然后我们根据一个简单的算法,就可以算出该用哪个模板。如下代码:
// 我们使用服务器端返回的文章编号的最后三位数字跟这个区块的模板数的模来确定我们要用的模板
acm=OV[i].articles[0].split("_").join("");
EZ=adw[eQ][Number(acm.substring(acm.length-3),10)%adw[eQ].length];

参考文章:

flipboard简单分析

http://weiye.info/blog/2010/09/flipboard-implement-research/

Jira数据备份

Categories: jira
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 06 月 17 日

Jira系统管理中自带备份和导入功能,如下图:

image

但是你使用时会报错误:

You have not named a safe backup directory and hence you are not allowed to make backups for security reasons. You must edit jira-application.properties and explicitly set ‘jira.paths.safe.backup.path=/to/some/safe/path’. Restart JIRA and then you will be able to make arbitrary backups. NOTE : If you are using Windows, you will need to use double \ characters, for example d:\\some\\safe\\path

解决方法:

我之前安装方法是采用下面方法:

http://www.cnblogs.com/ghj1976/archive/2010/09/27/1837008.html

一、编辑并修改 \edit-webapp\WEB-INF\classes\jira-application.properties 文件

主要是 jira.paths.safe.backup.path 属性设置上。

注意看对应的注释, Window和Linux的写法有差异。

 

二、编译

执行 sudo ./build.sh war

 

三、部署并修改配置文件

我装的是 Tomcat 6 所以我的 war 文件应该是:

/home/jira/dist-tomcat/tomcat-6/  目录下的

copy jira.xml 文件到 tomcat 目录下:

sudo cp /home/jira/dist-tomcat/tomcat-6/jira.xml /opt/apache-tomcat-6.0.29/conf/Catalina/localhost/

并修改这个文件如下:

<Context path="/jira" docBase="path/to/atlassian-jira-4.0.war">
  <Resource name="jdbc/JiraDS" auth="Container" type="javax.sql.DataSource"
    username="jirauser"
    password="mypassword"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost/jiradb?useUnicode=true&amp;characterEncoding=UTF8&amp;autoReconnect=true&amp;mysqlEncoding=utf8"
    maxActive="20"
    validationQuery="select 1"/>
  <Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction"
    factory="org.objectweb.jotm.UserTransactionFactory"
    jotm.timeout="60"/>
  <Manager pathname=""/>
</Context>

 

四、重启 jira

启动 Tomcat

通过  bin/startup.sh 启动 tomcat

 

之后这里就可以正常备份了。

 

 

参考资料:

http://hi.baidu.com/iis7/blog/item/3e9dfddaf850e2d7b7fd4866.html

http://www.fangwai.net/bbs/redirect.php?fid=1&tid=5288&goto=nextoldset

http://www.cnblogs.com/ghj1976/archive/2010/09/27/1837008.html

http://hi.baidu.com/tianlu_0_0/blog/item/c20cad341726861991ef3917.html

DES加密和解密PHP,Java,ObjectC统一的方法

Categories: android, php
Tags: No Tags
Comments: Comments Off
Published on: 2011 年 05 月 26 日

PHP的加解密函数

<?php

class DesComponent {
	var $key = '12345678';

	function encrypt($string) {

		$ivArray=array(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
		$iv=null;
		foreach ($ivArray as $element)
			$iv.=CHR($element);


 		$size = mcrypt_get_block_size ( MCRYPT_DES, MCRYPT_MODE_CBC );  
       $string = $this->pkcs5Pad ( $string, $size );  

		$data =  mcrypt_encrypt(MCRYPT_DES, $this->key, $string, MCRYPT_MODE_CBC, $iv);

		$data = base64_encode($data);
		return $data;
	}

	function decrypt($string) {

		$ivArray=array(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
		$iv=null;
		foreach ($ivArray as $element)
			$iv.=CHR($element);

		$string = base64_decode($string);
		//echo("****");
		//echo($string);
		//echo("****");
		$result =  mcrypt_decrypt(MCRYPT_DES, $this->key, $string, MCRYPT_MODE_CBC, $iv);
   $result = $this->pkcs5Unpad( $result );  

		return $result;
	}
	
	
	 function pkcs5Pad($text, $blocksize)  
    {  
        $pad = $blocksize - (strlen ( $text ) % $blocksize);  
        return $text . str_repeat ( chr ( $pad ), $pad );  
    }  
  
    function pkcs5Unpad($text)  
    {  
        $pad = ord ( $text {strlen ( $text ) - 1} );  
        if ($pad > strlen ( $text ))  
            return false;  
        if (strspn ( $text, chr ( $pad ), strlen ( $text ) - $pad ) != $pad)  
            return false;  
        return substr ( $text, 0, - 1 * $pad );  
    }  
	
}


$des = new DesComponent();
echo ($des->encrypt("19760519"));
echo "<br />";

//die($des->decrypt("zLVdpYUM0qw="));
//die($des->decrypt("zLVdpYUM0qzEsNshEEI6Cg=="));

$t2 =$des->decrypt("zLVdpYUM0qw="); 
echo $t2;
echo "--";
echo strlen($t2);
echo is_utf8($t2);


echo "<br />";
$t3 = mb_convert_encoding($t2,"GB2312", "utf-8");
echo $t3;
echo "--";
echo strlen($t3);
echo is_utf8($t3);


echo "<br />";


$t1 =$des->decrypt("zLVdpYUM0qzEsNshEEI6Cg=="); 
echo $t1;
echo "--";
echo strlen($t1);
echo is_utf8($t1);

echo "<br />";
$t3 = mb_convert_encoding($t1, "utf-8","GB2312");
echo $t3;
echo "--";
echo strlen($t3);
echo is_utf8($t3);

function is_utf8($string) { 
return preg_match('%^(?: 
[\x09\x0A\x0D\x20-\x7E] # ASCII 
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte 
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs 
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates 
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 
)*$%xs', $string); 
}
?>

Java的加解密函数

package ghj1976.Demo;


/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import java.io.UnsupportedEncodingException;
 
/**
 * Utilities for encoding and decoding the Base64 representation of
 * binary data.  See RFCs <a
 * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
 * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
 */
public class Base64 {
    /**
     * Default values for encoder/decoder flags.
     */
    public static final int DEFAULT = 0;
 
    /**
     * Encoder flag bit to omit the padding '=' characters at the end
     * of the output (if any).
     */
    public static final int NO_PADDING = 1;
 
    /**
     * Encoder flag bit to omit all line terminators (i.e., the output
     * will be on one long line).
     */
    public static final int NO_WRAP = 2;
 
    /**
     * Encoder flag bit to indicate lines should be terminated with a
     * CRLF pair instead of just an LF.  Has no effect if {@code
     * NO_WRAP} is specified as well.
     */
    public static final int CRLF = 4;
 
    /**
     * Encoder/decoder flag bit to indicate using the "URL and
     * filename safe" variant of Base64 (see RFC 3548 section 4) where
     * {@code -} and {@code _} are used in place of {@code +} and
     * {@code /}.
     */
    public static final int URL_SAFE = 8;
 
    /**
     * Flag to pass to {@link Base64OutputStream} to indicate that it
     * should not close the output stream it is wrapping when it
     * itself is closed.
     */
    public static final int NO_CLOSE = 16;
 
    //  --------------------------------------------------------
    //  shared code
    //  --------------------------------------------------------
 
    /* package */ static abstract class Coder {
        public byte[] output;
        public int op;
 
        /**
         * Encode/decode another block of input data.  this.output is
         * provided by the caller, and must be big enough to hold all
         * the coded data.  On exit, this.opwill be set to the length
         * of the coded data.
         *
         * @param finish true if this is the final call to process for
         *        this object.  Will finalize the coder state and
         *        include any final bytes in the output.
         *
         * @return true if the input so far is good; false if some
         *         error has been detected in the input stream..
         */
        public abstract boolean process(byte[] input, int offset, int len, boolean finish);
 
        /**
         * @return the maximum number of bytes a call to process()
         * could produce for the given number of input bytes.  This may
         * be an overestimate.
         */
        public abstract int maxOutputSize(int len);
    }
 
    //  --------------------------------------------------------
    //  decoding
    //  --------------------------------------------------------
 
    /**
     * Decode the Base64-encoded data in input and return the data in
     * a new byte array.
     *
     * <p>The padding '=' characters at the end are considered optional, but
     * if any are present, there must be the correct number of them.
     *
     * @param str    the input String to decode, which is converted to
     *               bytes using the default charset
     * @param flags  controls certain features of the decoded output.
     *               Pass {@code DEFAULT} to decode standard Base64.
     *
     * @throws IllegalArgumentException if the input contains
     * incorrect padding
     */
    public static byte[] decode(String str, int flags) {
        return decode(str.getBytes(), flags);
    }
 
    /**
     * Decode the Base64-encoded data in input and return the data in
     * a new byte array.
     *
     * <p>The padding '=' characters at the end are considered optional, but
     * if any are present, there must be the correct number of them.
     *
     * @param input the input array to decode
     * @param flags  controls certain features of the decoded output.
     *               Pass {@code DEFAULT} to decode standard Base64.
     *
     * @throws IllegalArgumentException if the input contains
     * incorrect padding
     */
    public static byte[] decode(byte[] input, int flags) {
        return decode(input, 0, input.length, flags);
    }
 
    /**
     * Decode the Base64-encoded data in input and return the data in
     * a new byte array.
     *
     * <p>The padding '=' characters at the end are considered optional, but
     * if any are present, there must be the correct number of them.
     *
     * @param input  the data to decode
     * @param offset the position within the input array at which to start
     * @param len    the number of bytes of input to decode
     * @param flags  controls certain features of the decoded output.
     *               Pass {@code DEFAULT} to decode standard Base64.
     *
     * @throws IllegalArgumentException if the input contains
     * incorrect padding
     */
    public static byte[] decode(byte[] input, int offset, int len, int flags) {
        // Allocate space for the most data the input could represent.
        // (It could contain less if it contains whitespace, etc.)
        Decoder decoder = new Decoder(flags, new byte[len*3/4]);
 
        if (!decoder.process(input, offset, len, true)) {
            throw new IllegalArgumentException("bad base-64");
        }
 
        // Maybe we got lucky and allocated exactly enough output space.
        if (decoder.op == decoder.output.length) {
            return decoder.output;
        }
 
        // Need to shorten the array, so allocate a new one of the
        // right size and copy.
        byte[] temp = new byte[decoder.op];
        System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
        return temp;
    }
 
    /* package */ static class Decoder extends Coder {
        /**
         * Lookup table for turning bytes into their position in the
         * Base64 alphabet.
         */
        private static final int DECODE[] = {
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        };
 
        /**
         * Decode lookup table for the "web safe" variant (RFC 3548
         * sec. 4) where - and _ replace + and /.
         */
        private static final int DECODE_WEBSAFE[] = {
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        };
 
        /** Non-data values in the DECODE arrays. */
        private static final int SKIP = -1;
        private static final int EQUALS = -2;
 
        /**
         * States 0-3 are reading through the next input tuple.
         * State 4 is having read one '=' and expecting exactly
         * one more.
         * State 5 is expecting no more data or padding characters
         * in the input.
         * State 6 is the error state; an error has been detected
         * in the input and no future input can "fix" it.
         */
        private int state;   // state number (0 to 6)
        private int value;
 
        final private int[] alphabet;
 
        public Decoder(int flags, byte[] output) {
            this.output = output;
 
            alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
            state = 0;
            value = 0;
        }
 
        /**
         * @return an overestimate for the number of bytes {@code
         * len} bytes could decode to.
         */
        public int maxOutputSize(int len) {
            return len * 3/4 + 10;
        }
 
        /**
         * Decode another block of input data.
         *
         * @return true if the state machine is still healthy.  false if
         *         bad base-64 data has been detected in the input stream.
         */
        public boolean process(byte[] input, int offset, int len, boolean finish) {
            if (this.state == 6) return false;
 
            int p = offset;
            len += offset;
 
            // Using local variables makes the decoder about 12%
            // faster than if we manipulate the member variables in
            // the loop.  (Even alphabet makes a measurable
            // difference, which is somewhat surprising to me since
            // the member variable is final.)
            int state = this.state;
            int value = this.value;
            int op = 0;
            final byte[] output = this.output;
            final int[] alphabet = this.alphabet;
 
            while (p < len) {
                // Try the fast path:  we're starting a new tuple and the
                // next four bytes of the input stream are all data
                // bytes.  This corresponds to going through states
                // 0-1-2-3-0.  We expect to use this method for most of
                // the data.
                //
                // If any of the next four bytes of input are non-data
                // (whitespace, etc.), value will end up negative.  (All
                // the non-data values in decode are small negative
                // numbers, so shifting any of them up and or'ing them
                // together will result in a value with its top bit set.)
                //
                // You can remove this whole block and the output should
                // be the same, just slower.
                if (state == 0) {
                    while (p+4 <= len &&
                           (value = ((alphabet[input[p] & 0xff] << 18) |
                                     (alphabet[input[p+1] & 0xff] << 12) |
                                     (alphabet[input[p+2] & 0xff] << 6) |
                                     (alphabet[input[p+3] & 0xff]))) >= 0) {
                        output[op+2] = (byte) value;
                        output[op+1] = (byte) (value >> 8);
                        output[op] = (byte) (value >> 16);
                        op += 3;
                        p += 4;
                    }
                    if (p >= len) break;
                }
 
                // The fast path isn't available -- either we've read a
                // partial tuple, or the next four input bytes aren't all
                // data, or whatever.  Fall back to the slower state
                // machine implementation.
 
                int d = alphabet[input[p++] & 0xff];
 
                switch (state) {
                case 0:
                    if (d >= 0) {
                        value = d;
                        ++state;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
 
                case 1:
                    if (d >= 0) {
                        value = (value << 6) | d;
                        ++state;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
 
                case 2:
                    if (d >= 0) {
                        value = (value << 6) | d;
                        ++state;
                    } else if (d == EQUALS) {
                        // Emit the last (partial) output tuple;
                        // expect exactly one more padding character.
                        output[op++] = (byte) (value >> 4);
                        state = 4;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
 
                case 3:
                    if (d >= 0) {
                        // Emit the output triple and return to state 0.
                        value = (value << 6) | d;
                        output[op+2] = (byte) value;
                        output[op+1] = (byte) (value >> 8);
                        output[op] = (byte) (value >> 16);
                        op += 3;
                        state = 0;
                    } else if (d == EQUALS) {
                        // Emit the last (partial) output tuple;
                        // expect no further data or padding characters.
                        output[op+1] = (byte) (value >> 2);
                        output[op] = (byte) (value >> 10);
                        op += 2;
                        state = 5;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
 
                case 4:
                    if (d == EQUALS) {
                        ++state;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
 
                case 5:
                    if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
                }
            }
 
            if (!finish) {
                // We're out of input, but a future call could provide
                // more.
                this.state = state;
                this.value = value;
                this.op = op;
                return true;
            }
 
            // Done reading input.  Now figure out where we are left in
            // the state machine and finish up.
 
            switch (state) {
            case 0:
                // Output length is a multiple of three.  Fine.
                break;
            case 1:
                // Read one extra input byte, which isn't enough to
                // make another output byte.  Illegal.
                this.state = 6;
                return false;
            case 2:
                // Read two extra input bytes, enough to emit 1 more
                // output byte.  Fine.
                output[op++] = (byte) (value >> 4);
                break;
            case 3:
                // Read three extra input bytes, enough to emit 2 more
                // output bytes.  Fine.
                output[op++] = (byte) (value >> 10);
                output[op++] = (byte) (value >> 2);
                break;
            case 4:
                // Read one padding '=' when we expected 2.  Illegal.
                this.state = 6;
                return false;
            case 5:
                // Read all the padding '='s we expected and no more.
                // Fine.
                break;
            }
 
            this.state = state;
            this.op = op;
            return true;
        }
    }
 
    //  --------------------------------------------------------
    //  encoding
    //  --------------------------------------------------------
 
    /**
     * Base64-encode the given data and return a newly allocated
     * String with the result.
     *
     * @param input  the data to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static String encodeToString(byte[] input, int flags) {
        try {
            return new String(encode(input, flags), "US-ASCII");
        } catch (UnsupportedEncodingException e) {
            // US-ASCII is guaranteed to be available.
            throw new AssertionError(e);
        }
    }
 
    /**
     * Base64-encode the given data and return a newly allocated
     * String with the result.
     *
     * @param input  the data to encode
     * @param offset the position within the input array at which to
     *               start
     * @param len    the number of bytes of input to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static String encodeToString(byte[] input, int offset, int len, int flags) {
        try {
            return new String(encode(input, offset, len, flags), "US-ASCII");
        } catch (UnsupportedEncodingException e) {
            // US-ASCII is guaranteed to be available.
            throw new AssertionError(e);
        }
    }
 
    /**
     * Base64-encode the given data and return a newly allocated
     * byte[] with the result.
     *
     * @param input  the data to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static byte[] encode(byte[] input, int flags) {
        return encode(input, 0, input.length, flags);
    }
 
    /**
     * Base64-encode the given data and return a newly allocated
     * byte[] with the result.
     *
     * @param input  the data to encode
     * @param offset the position within the input array at which to
     *               start
     * @param len    the number of bytes of input to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static byte[] encode(byte[] input, int offset, int len, int flags) {
        Encoder encoder = new Encoder(flags, null);
 
        // Compute the exact length of the array we will produce.
        int output_len = len / 3 * 4;
 
        // Account for the tail of the data and the padding bytes, if any.
        if (encoder.do_padding) {
            if (len % 3 > 0) {
                output_len += 4;
            }
        } else {
            switch (len % 3) {
                case 0: break;
                case 1: output_len += 2; break;
                case 2: output_len += 3; break;
            }
        }
 
        // Account for the newlines, if any.
        if (encoder.do_newline && len > 0) {
            output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
                (encoder.do_cr ? 2 : 1);
        }
 
        encoder.output = new byte[output_len];
        encoder.process(input, offset, len, true);
 
        assert encoder.op == output_len;
 
        return encoder.output;
    }
 
    /* package */ static class Encoder extends Coder {
        /**
         * Emit a new line every this many output tuples.  Corresponds to
         * a 76-character line length (the maximum allowable according to
         * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
         */
        public static final int LINE_GROUPS = 19;
 
        /**
         * Lookup table for turning Base64 alphabet positions (6 bits)
         * into output bytes.
         */
        private static final byte ENCODE[] = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
        };
 
        /**
         * Lookup table for turning Base64 alphabet positions (6 bits)
         * into output bytes.
         */
        private static final byte ENCODE_WEBSAFE[] = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
        };
 
        final private byte[] tail;
        /* package */ int tailLen;
        private int count;
 
        final public boolean do_padding;
        final public boolean do_newline;
        final public boolean do_cr;
        final private byte[] alphabet;
 
        public Encoder(int flags, byte[] output) {
            this.output = output;
 
            do_padding = (flags & NO_PADDING) == 0;
            do_newline = (flags & NO_WRAP) == 0;
            do_cr = (flags & CRLF) != 0;
            alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
 
            tail = new byte[2];
            tailLen = 0;
 
            count = do_newline ? LINE_GROUPS : -1;
        }
 
        /**
         * @return an overestimate for the number of bytes {@code
         * len} bytes could encode to.
         */
        public int maxOutputSize(int len) {
            return len * 8/5 + 10;
        }
 
        public boolean process(byte[] input, int offset, int len, boolean finish) {
            // Using local variables makes the encoder about 9% faster.
            final byte[] alphabet = this.alphabet;
            final byte[] output = this.output;
            int op = 0;
            int count = this.count;
 
            int p = offset;
            len += offset;
            int v = -1;
 
            // First we need to concatenate the tail of the previous call
            // with any input bytes available now and see if we can empty
            // the tail.
 
            switch (tailLen) {
                case 0:
                    // There was no tail.
                    break;
 
                case 1:
                    if (p+2 <= len) {
                        // A 1-byte tail with at least 2 bytes of
                        // input available now.
                        v = ((tail[0] & 0xff) << 16) |
                            ((input[p++] & 0xff) << 8) |
                            (input[p++] & 0xff);
                        tailLen = 0;
                    };
                    break;
 
                case 2:
                    if (p+1 <= len) {
                        // A 2-byte tail with at least 1 byte of input.
                        v = ((tail[0] & 0xff) << 16) |
                            ((tail[1] & 0xff) << 8) |
                            (input[p++] & 0xff);
                        tailLen = 0;
                    }
                    break;
            }
 
            if (v != -1) {
                output[op++] = alphabet[(v >> 18) & 0x3f];
                output[op++] = alphabet[(v >> 12) & 0x3f];
                output[op++] = alphabet[(v >> 6) & 0x3f];
                output[op++] = alphabet[v & 0x3f];
                if (--count == 0) {
                    if (do_cr) output[op++] = '\r';
                    output[op++] = '\n';
                    count = LINE_GROUPS;
                }
            }
 
            // At this point either there is no tail, or there are fewer
            // than 3 bytes of input available.
 
            // The main loop, turning 3 input bytes into 4 output bytes on
            // each iteration.
            while (p+3 <= len) {
                v = ((input[p] & 0xff) << 16) |
                    ((input[p+1] & 0xff) << 8) |
                    (input[p+2] & 0xff);
                output[op] = alphabet[(v >> 18) & 0x3f];
                output[op+1] = alphabet[(v >> 12) & 0x3f];
                output[op+2] = alphabet[(v >> 6) & 0x3f];
                output[op+3] = alphabet[v & 0x3f];
                p += 3;
                op += 4;
                if (--count == 0) {
                    if (do_cr) output[op++] = '\r';
                    output[op++] = '\n';
                    count = LINE_GROUPS;
                }
            }
 
            if (finish) {
                // Finish up the tail of the input.  Note that we need to
                // consume any bytes in tail before any bytes
                // remaining in input; there should be at most two bytes
                // total.
 
                if (p-tailLen == len-1) {
                    int t = 0;
                    v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
                    tailLen -= t;
                    output[op++] = alphabet[(v >> 6) & 0x3f];
                    output[op++] = alphabet[v & 0x3f];
                    if (do_padding) {
                        output[op++] = '=';
                        output[op++] = '=';
                    }
                    if (do_newline) {
                        if (do_cr) output[op++] = '\r';
                        output[op++] = '\n';
                    }
                } else if (p-tailLen == len-2) {
                    int t = 0;
                    v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
                        (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
                    tailLen -= t;
                    output[op++] = alphabet[(v >> 12) & 0x3f];
                    output[op++] = alphabet[(v >> 6) & 0x3f];
                    output[op++] = alphabet[v & 0x3f];
                    if (do_padding) {
                        output[op++] = '=';
                    }
                    if (do_newline) {
                        if (do_cr) output[op++] = '\r';
                        output[op++] = '\n';
                    }
                } else if (do_newline && op > 0 && count != LINE_GROUPS) {
                    if (do_cr) output[op++] = '\r';
                    output[op++] = '\n';
                }
 
                assert tailLen == 0;
                assert p == len;
            } else {
                // Save the leftovers in tail to be consumed on the next
                // call to encodeInternal.
 
                if (p == len-1) {
                    tail[tailLen++] = input[p];
                } else if (p == len-2) {
                    tail[tailLen++] = input[p];
                    tail[tailLen++] = input[p+1];
                }
            }
 
            this.op = op;
            this.count = count;
 
            return true;
        }
    }
 
    private Base64() { }   // don't instantiate
}

package ghj1976.Demo;




import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;


public class DES {
	 private static String DESKey = "12345678"; // 字节数必须是8的倍数  
	 private static byte[] iv1 = {(byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78, (byte)0x90, (byte)0xAB, (byte)0xCD, (byte)0xEF};
	 public static void main(String[] args) {
		 System.out.print("xyz");
		DES des = new DES();
		System.out.print(des.encrypt("19760519"));
	} 
	 public byte[] desEncrypt(byte[] plainText) throws Exception  
	    {  
//	        SecureRandom sr = new SecureRandom();  	        
//	        sr.setSeed(iv);
	        
//	    	 IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));  
	    	IvParameterSpec iv = new IvParameterSpec(iv1);
	    	 
	        DESKeySpec dks = new DESKeySpec(DESKey.getBytes());  
	        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");  
	        SecretKey key = keyFactory.generateSecret(dks);  
	        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");  
	        cipher.init(Cipher.ENCRYPT_MODE, key, iv);  
	        byte data[] = plainText;  
	        byte encryptedData[] = cipher.doFinal(data);  
	        return encryptedData;  
	    }  
	      
	    public String encrypt(String input)   
	    {  
	    	String result = "input";
	        try {
				result = base64Encode(desEncrypt(input.getBytes()));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}  
			return result;
	    }  
	      
	    public  String base64Encode(byte[] s)   
	    {  
	        if (s == null)  
	            return null;  
	        return Base64.encodeToString(s, Base64.DEFAULT);

	    }  
}

 

Object c 的加解密函数

//
//  Utility.h
//  TheDealersForum
//
//  Created by Hailong Zhang on 5/3/11.
//  Copyright 2011 Personal. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>


@interface Utility : NSObject {

}
+ (NSString *) udid;
+ (NSString *) md5:(NSString *)str;
+ (NSString *) doCipher:(NSString *)sTextIn key:(NSString *)sKey context:(CCOperation)encryptOrDecrypt;
+ (NSString *) encryptStr:(NSString *) str;
+ (NSString *) decryptStr:(NSString	*) str;

#pragma mark Based64
+ (NSString *) encodeBase64WithString:(NSString *)strData;
+ (NSString *) encodeBase64WithData:(NSData *)objData;
+ (NSData *) decodeBase64WithString:(NSString *)strBase64;

@end

//
//  Utility.m
//  TheDealersForum
//
//  Created by Hailong Zhang on 5/3/11.
//  Copyright 2011 Personal. All rights reserved.
//



#import "Utility.h"
static NSString *_key = @"12345678";

static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const short _base64DecodingTable[256] = {
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
	-2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
	-2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
	-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};

@implementation Utility
+ (NSString *) udid
{
	return [Utility encryptStr:[[UIDevice currentDevice] uniqueIdentifier]];
}
+ (NSString *) md5:(NSString *)str

{
	
	const char *cStr = [str UTF8String];
	
	unsigned char result[CC_MD5_DIGEST_LENGTH];
	
	CC_MD5( cStr, strlen(cStr), result );
	
	return [NSString 
			
			stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
			
			result[0], result[1],
			
			result[2], result[3],
			
			result[4], result[5],
			
			result[6], result[7],
			
			result[8], result[9],
			
			result[10], result[11],
			
			result[12], result[13],
			
			result[14], result[15]
			
			];
	
}
+ (NSString *) encryptStr:(NSString *) str
{
	return [Utility doCipher:str key:_key context:kCCEncrypt];
}
+ (NSString *) decryptStr:(NSString	*) str
{
	return [Utility doCipher:str key:_key context:kCCDecrypt];
}
+ (NSString *)doCipher:(NSString *)sTextIn key:(NSString *)sKey
			   context:(CCOperation)encryptOrDecrypt {
	NSStringEncoding EnC = NSUTF8StringEncoding;
	
    NSMutableData * dTextIn;
    if (encryptOrDecrypt == kCCDecrypt) {    
        dTextIn = [[Utility decodeBase64WithString:sTextIn] mutableCopy];    
    }    
    else{    
        dTextIn = [[sTextIn dataUsingEncoding: EnC] mutableCopy];    
    }           
    NSMutableData * dKey = [[sKey dataUsingEncoding:EnC] mutableCopy];            
    [dKey setLength:kCCBlockSizeDES];        
    uint8_t *bufferPtr1 = NULL;    
    size_t bufferPtrSize1 = 0;    
    size_t movedBytes1 = 0;
    //uint8_t iv[kCCBlockSizeDES];
	//memset((void *) iv, 0x0, (size_t) sizeof(iv));
	Byte iv[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
    bufferPtrSize1 = ([sTextIn length] + kCCKeySizeDES) & ~(kCCKeySizeDES -1);    
    bufferPtr1 = malloc(bufferPtrSize1 * sizeof(uint8_t));    
    memset((void *)bufferPtr1, 0x00, bufferPtrSize1);    
	CCCrypt(encryptOrDecrypt, // CCOperation op    
			kCCAlgorithmDES, // CCAlgorithm alg    
			kCCOptionPKCS7Padding, // CCOptions options    
			[dKey bytes], // const void *key    
			[dKey length], // size_t keyLength    
			iv, // const void *iv    
			[dTextIn bytes], // const void *dataIn
			[dTextIn length],  // size_t dataInLength    
			(void *)bufferPtr1, // void *dataOut    
			bufferPtrSize1,     // size_t dataOutAvailable 
			&movedBytes1);      // size_t *dataOutMoved    

	
    NSString * sResult;    
    if (encryptOrDecrypt == kCCDecrypt){    
        sResult = [[[ NSString alloc] initWithData:[NSData dataWithBytes:bufferPtr1     
																  length:movedBytes1] encoding:EnC] autorelease];    
    }    
    else {    
        NSData *dResult = [NSData dataWithBytes:bufferPtr1 length:movedBytes1]; 
        sResult = [Utility encodeBase64WithData:dResult];    
    }           
    return sResult;
}



+ (NSString *)encodeBase64WithString:(NSString *)strData {
	return [Utility encodeBase64WithData:[strData dataUsingEncoding:NSUTF8StringEncoding]];
}

+ (NSString *)encodeBase64WithData:(NSData *)objData {
	const unsigned char * objRawData = [objData bytes];
	char * objPointer;
	char * strResult;
	
	// Get the Raw Data length and ensure we actually have data
	int intLength = [objData length];
	if (intLength == 0) return nil;
	
	// Setup the String-based Result placeholder and pointer within that placeholder
	strResult = (char *)calloc(((intLength + 2) / 3) * 4, sizeof(char));
	objPointer = strResult;
	
	// Iterate through everything
	while (intLength > 2) { // keep going until we have less than 24 bits
		*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
		*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
		*objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
		*objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f];
		
		// we just handled 3 octets (24 bits) of data
		objRawData += 3;
		intLength -= 3; 
	}
	
	// now deal with the tail end of things
	if (intLength != 0) {
		*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
		if (intLength > 1) {
			*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
			*objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2];
			*objPointer++ = '=';
		} else {
			*objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4];
			*objPointer++ = '=';
			*objPointer++ = '=';
		}
	}
	
	// Terminate the string-based result
	*objPointer = '';
	
	// Return the results as an NSString object
	return [NSString stringWithCString:strResult encoding:NSASCIIStringEncoding];
}

+ (NSData *)decodeBase64WithString:(NSString *)strBase64 {
	const char * objPointer = [strBase64 cStringUsingEncoding:NSASCIIStringEncoding];
	int intLength = strlen(objPointer);
	int intCurrent;
	int i = 0, j = 0, k;
	
	unsigned char * objResult;
	objResult = calloc(intLength, sizeof(char));
	
	// Run through the whole string, converting as we go
	while ( ((intCurrent = *objPointer++) != '') && (intLength-- > 0) ) {
		if (intCurrent == '=') {
			if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
				// the padding character is invalid at this point -- so this entire string is invalid
				free(objResult);
				return nil;
			}
			continue;
		}
		
		intCurrent = _base64DecodingTable[intCurrent];
		if (intCurrent == -1) {
			// we're at a whitespace -- simply skip over
			continue;
		} else if (intCurrent == -2) {
			// we're at an invalid character
			free(objResult);
			return nil;
		}
		
		switch (i % 4) {
			case 0:
				objResult[j] = intCurrent << 2;
				break;
				
			case 1:
				objResult[j++] |= intCurrent >> 4;
				objResult[j] = (intCurrent & 0x0f) << 4;
				break;
				
			case 2:
				objResult[j++] |= intCurrent >>2;
				objResult[j] = (intCurrent & 0x03) << 6;
				break;
				
			case 3:
				objResult[j++] |= intCurrent;
				break;
		}
		i++;
	}
	
	// mop things up if we ended on a boundary
	k = j;
	if (intCurrent == '=') {
		switch (i % 4) {
			case 1:
				// Invalid state
				free(objResult);
				return nil;
				
			case 2:
				k++;
				// flow through
			case 3:
				objResult[k] = 0;
		}
	}
	
	// Cleanup and setup the return NSData
	NSData * objData = [[[NSData alloc] initWithBytes:objResult length:j] autorelease];
	free(objResult);
	return objData;
}
@end

参考资料:

国政通DES加密Java和PHP互通

http://toptulip.iteye.com/blog/780309

«page 1 of 76


Welcome , today is 星期六, 2017 年 06 月 24 日