C# 多线程编程 ThreadStart ParameterizedThreadStart

在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。
不带参数的启动方式
如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码:


1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class Program
9 {
10 int interval = 200;
11 static void Main(string[] args)
12 {
13 Program p = new Program();
14 Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
15 nonParameterThread.Start();
16 }
17 ///

18 /// 不带参数的启动方法
19 ///

20 public void NonParameterRun()
21 {
22 for (int i = 0; i < 10; i++) 23 { 24 Console.WriteLine("系统当前时间毫秒值:"+DateTime.Now.Millisecond.ToString()); 25 Thread.Sleep(interval);//让线程暂停 26 } 27 } 28 }

程序的运行效果我们不用运行也会知道,那就是在循环中将系统当前时间的毫秒部分输出出来,在每次输出之后会将当前线程暂停一下,直到10次之后运行完毕,终止线程的执行。
在上面的代码中我们是通过定义全局变量的方法来指定线程暂停间隔,按照这种方法,假如要运行10个线程,每个线程的暂停间隔不一样的话,就需要定义10个全局变量,虽然最终不影响系统的运行效果,但是总觉得不是太爽。
有没有比较简单一点的办法呢?有!那就是使用带参数的启动方法。
带参数的启动方法
如果要在实例化线程时要带一些参数,就不能用ThreadStart委托作为构造函数的参数来实例化Thread了,而要 ParameterizedThreadStart委托,和ThreadStart一样的是它也是线程启动时要执行的方法,和ThreadStart不同的是,它在实例化时可以用一个带有一个Object参数的方法作为构造函数的参数,而实例化ThreadStart时所用到的方法是没有参数的。
为什么是Object这样的参数呢?很简单,因为在.net中Object是所有类型的基类,用它可以表示Array(数组)、Interface(接口)、ValueType(值类型,如bool,byte,char,short,int,float,long,double等)、class(类)等.net中的类型。当然,这也意味着如果你要启动一个线程,给它传递一个int类型参数时,必须在 启动方法中进行相应的类型转换。
下面就是一个例子,在启动线程时指定了线程的暂停间隔,代码如下:

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class Program
9 {
10 int interval = 200;
11 static void Main(string[] args)
12 {
13 Program p = new Program();
14
15 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
16 parameterThread.Name = "Thread A:";
17 parameterThread.Start(30);
18 }
19
20 ///

21 /// 带参数的启动方法
22 ///

23 ///让线程在运行过程中的休眠间隔 24 public void ParameterRun(object ms)
25 {
26 int j = 10;
27 int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
28 for (int i = 0; i < 10; i++) 29 { 30 Console.WriteLine(Thread.CurrentThread.Name+"系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 31 Thread.Sleep(j);//让线程暂停 32 } 33 } 34 } 35 }

在这个方法里,我们在启动线程时顺便指定了线程的暂停间隔,也就是这句:
parameterThread.Start(30);
线程启动时运行的方法是public void ParameterRun(object ms),这个值为30的int类型变量被装箱成object,所以在方法中还需要将它转换成int类型,这个可以通过拆箱或者其它办法解决。
假如我们要启动两个线程,每个线程的暂停间隔不一样,启动代码如下:

  


1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class Program
9 {
10 int interval = 200;
11 static void Main(string[] args)
12 {
13 Program p = new Program();
14
15 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
16 parameterThread.Name = "Thread A:";
17 parameterThread.Start(30);
18 //启动第二个线程
19 parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
20 parameterThread.Name = "Thread B:";
21 parameterThread.Start(60);
22 }
23
24 ///

25 /// 带参数的启动方法
26 ///

27 ///让线程在运行过程中的休眠间隔 28 public void ParameterRun(object ms)
29 {
30 int j = 10;
31 int.TryParse(ms.ToString(), out j);//这里采用了TryParse方法,避免不能转换时出现异常
32 for (int i = 0; i < 10; i++) 33 { 34 Console.WriteLine(Thread.CurrentThread.Name+"系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 35 Thread.Sleep(j);//让线程暂停 36 } 37 } 38 } 39 }

对上面的代码做一点说明,就是线程启动之后,线程的实例不必再存在,例如在上面的代码中我用的是同一个实例实例化了两个线程,并且这两个线程运行很正常。
继续探索
上面解决了一个问题,如果在启动线程时需要参数如何解决,如果针对上面的问题继续发掘,比如:在启动线程时不但要指定线程的暂停间隔,还需要指定循环次数(在上面的所有例子中都是执行10次的),这个问题该如何解决呢?
有两种办法可以解决:
首先可以继续在ParameterizedThreadStart这里做文章,因为这里可以使用一个Object类型的参数,那么可以通过数组或者一个类来解决(因为它们都是Object的子类)。我在做某个系统时确实采用数组处理过这种情况,这样就要求在线程启动方法中必须清楚知道数组中每个参数的用途,不是太方便。
这里说说重新定义一个实体类来解决的方法,代码如下。

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class MyThreadParameter
9 {
10 private int interval;
11 private int loopCount;
12 ///

13 /// 循环次数
14 ///

15 public int LoopCount
16 {
17 get { return loopCount; }
18 }
19
20 ///

21 /// 线程的暂停间隔
22 ///

23 public int Interval
24 {
25 get { return interval; }
26 }
27 ///

28 /// 构造函数
29 ///

30 ///线程的暂停间隔 31 ///循环次数 32 public MyThreadParameter(int interval,int loopCount)
33 {
34 this.interval = interval;
35 this.loopCount = loopCount;
36 }
37 }
38 class Program
39 {
40 int interval = 200;
41 static void Main(string[] args)
42 {
43 Program p = new Program();
44
45 Thread parameterThread = new Thread(new ParameterizedThreadStart(p.MyParameterRun));
46 parameterThread.Name = "Thread A:";
47 MyThreadParameter paramter = new MyThreadParameter(50, 20);
48 parameterThread.Start(paramter);
49 }
50
51
52 ///

53 /// 带多个参数的启动方法
54 ///

55 ///方法参数 56 public void MyParameterRun(object ms)
57 {
58 MyThreadParameter parameter = ms as MyThreadParameter;//类型转换
59 if (parameter != null)
60 {
61 for (int i = 0; i < parameter.LoopCount; i++) 62 { 63 Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 64 Thread.Sleep(parameter.Interval);//让线程暂停 65 } 66 } 67 } 68 } 69 }

第二种方法和上面方法有些相似,也是需要引入外部类,并且将Thread实例放在引入的类中,这种情况适合于在线程中处理的业务逻辑比较复杂的情况。在前不久处理的一个项目中我用过这种情况,它是用来实现双向数据传输的。
如果实现上面的效果,代码如下:

  

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace StartThread
7 {
8 class MyThreadParameter
9 {
10 private int interval;
11 private int loopCount;
12 private Thread thread;
13
14 ///

15 /// 构造函数
16 ///

17 ///线程的暂停间隔 18 ///循环次数 19 public MyThreadParameter(int interval,int loopCount)
20 {
21 this.interval = interval;
22 this.loopCount = loopCount;
23 thread = new Thread(new ThreadStart(Run));
24 }
25
26 public void Start()
27 {
28 if (thread != null)
29 {
30 thread.Start();
31 }
32 }
33
34 private void Run()
35 {
36 for (int i = 0; i < loopCount; i++) 37 { 38 Console.WriteLine("系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString()); 39 Thread.Sleep(interval);//让线程暂停 40 } 41 } 42 } 43 class Program 44 { 45 static void Main(string[] args) 46 { 47 MyThreadParameter parameterThread = new MyThreadParameter(30, 50); 48 parameterThread.Start(); 49 } 50 51 } 52 }

上面的代码的运行效果和前面的代码运行效果类似,只不过是将业务处理代码放在一个单独的类MyThreadParameter中,使得MyThreadParameter看起来也像一个Thread,实际上维护的还是其内部的Thread,在一些大型系统中这样做的好处是便于维护。
总结:在本篇主要讲述如何启动线程的问题,在启动时可能会遇到无需参数、需要多个参数的情况,在这里讲述了如何解决这些问题的思路。在.net类库中虽然存在着庞大的类库,但是并不是总会有合适的类来解决我们所遇到的问题,但是只要肯动脑筋总会想到合适的办法。

Android 关于数据库访问

Android 用的 数据库是Sqlite3,。

android 操作数据库和我们用其他语言操作数据库差不多。

首先取得数据库对象

SQLiteDatabase

db= SQLiteDatabase.openDatabase(MyApp.MAINACITVITY.getDatabasePath("数据库文件名").toString(),null,SQLiteDatabase.OPEN_READONLY);

然后通过db取得cursor对象 这个cursor相当于数据集 dataset

Cursor cursor=db.rawQuery("select id,name,x,y from locationInfo ", null);
MainActivity.ccsuMapAPP.startManagingCursor(cursor);//这句话要调用一次使得cursor生命周期和activity同步 但是最后要记得调用stopManagingCursor()
while(cursor.moveToNext()){
LocationTag tag=new LocationTag(MainActivity.ccsuMapAPP,this);
tag.setBaseInfo(cursor.getInt(0), cursor.getString(1), cursor.getInt(2), cursor.getInt(3));
tags.add(tag);
}

总结一下Activity.startManagingCursor方法: 转
我们将获得的Cursor对象交与Activity 来管理,这样Cursor对象的生命周期便能与当前的Activity自动同步,省去了自己管理Cursor。

1.这个方法使用的前提是:游标结果集里有很多的数据记录。
所以,在使用之前,先对Cursor是否为null进行判断,如果Cursor != null,再使用此方法

2.如果使用这个方法,最后也要用stopManagingCursor()来把它停止掉,以免出现错误。

3.使用这个方法的目的是把获取的Cursor对象交给Activity管理,这样Cursor的生命周期便能和Activity自动同步,
省去自己手动管理。

android中几个基础知识

1: 获取asset下面的文件 获得文件IO流。

( context).getResources().getAssets().open("文件名")

2: 通过流创建Bitmap对象:

BitmapFactory.decodeStream(is) 返回Bitma对象,获取后要记得关闭

3:通过流直接获取Drawab

Bitmap b=new BitmapDrawable(is)

Bitmap Config 参数


Bitmap.Config ALPHA_8
Bitmap.Config ARGB_4444
Bitmap.Config ARGB_8888
Bitmap.Config RGB_565
A  R  G  B
透明度 红色 绿色 蓝色
Bitmap.Config ARGB_4444 16 每个像素 占四位
Bitmap.Config ARGB_8888 32 每个像素 占八位
Bitmap.Config RGB_565 16 R占5位 G占6位 B占5位 没有透明度(A)
一般情况下我们都是用argb888 但是无可厚非 它也相对的很占内存
因为一个像素32位 8位一个字节 如果是800*480的图片的话自己算 估计有1M多了

4: 计算字体宽度 在canvas中

Paint p=new Paint();
p.setTextSize(24);
Rect bounds = new Rect();  
p.getTextBounds(str,0, str.length(), bounds);  
int width = bounds.width();

1.  什么是density

引用
1) density
density表示每英寸有多少个显示点(逻辑值),它的单位是dpi:dot per inch,通常屏幕大时,density就大,屏幕小时,density就小,通常
屏幕实际分辨率为240px*400px时,density=120
屏幕实际分辨率为320px*533px,density=160
屏幕实际分辨率为480px*800px,density=240

2)  分辨率
是整个屏是多少点,比如800×480,它是软件的显示单位

3) 从Android1.6版本开始支持density(对应API Level 4)
用于解决应用在屏幕大小不同的硬件上正常显示的问题

2. 相关代码及设置

引用
1)         AndroidManifest.xml

这个参数在API Level 4也就是SDK 1.6以后才启用的,而且1.6版本的API Level 4的应用默认值就是True

2) 资源目录名(android 2.0以后)
res/xxx-hdpi         当density为240时,使用此目录下的资源
res/xxx-mdpi        当density为160时,使用此目录下的资源
res/xxx-ldpi          当density为120时,使用此目录下的资源
res/xxx                 不常后缀,为默认设置,同xxx-mdpi

3) 资源单位(xml文件中定义大小的单位)

a)  dp=dip=dx (Density independent pixel)
基于屏幕密度的抽象单位,设备无关的点,用于说明与密度无关的尺寸和位置。这些单位是相对于一个160dpi的屏幕,所有一个dp是160dpi屏幕上的一个点。

b)  px
px指软件的单位点,设备相关的点

c)  具体使用

i.布局时尽量使用单位dip,少使用px
若使用px,如果设某控件大小400x400px,在800×480上显示正常,而在533×320的屏上就超出屏幕了
若使用dp,如果设某控件大小为160x160dp,就可以通过从系统中取density来算出真正的大小,比如在800×480屏的density设为240,而533×320屏的density设为160,借以下公式计算
pixels = dips * (density / 160)
在800×480在屏中显示240象素,而在533×320的屏中显示为160象素,控件在屏中显示的比例是一样的。

ii. 内部的处理过程分为三步:
取screen中其它元素,转为应用的值,计算应用各控件位置,然后再转成800×480以供真正显示
若res-xxx不存在,则读取res有的资源,然后对其做相应缩放

3. 实现density的关键源码

引用
1)         BitmapFactory.java(用于缩放图片)

2)         ComptibilityInfo.java(用于位置计算)

4、取得屏幕信息(宽高等)

Java代码  收藏代码
  1. public static String getDisplayMetrics(Context cx) {  

  2.  String str = "";  

  3.  DisplayMetrics dm = new DisplayMetrics();  

  4.  dm = cx.getApplicationContext().getResources().getDisplayMetrics();  

  5.  int screenWidth = dm.widthPixels;  

  6.  int screenHeight = dm.heightPixels;  

  7.  float density = dm.density;  

  8.  float xdpi = dm.xdpi;  

  9.  float ydpi = dm.ydpi;  

  10.  str += "The absolute width:" + String.valueOf(screenWidth) + "pixelsn";  

  11.  str += "The absolute heightin:" + String.valueOf(screenHeight)  

  12.      + "pixelsn";  

  13.  str += "The logical density of the display.:" + String.valueOf(density)  

  14.      + "n";  

  15.  str += "X dimension :" + String.valueOf(xdpi) + "pixels per inchn";  

  16.  str += "Y dimension :" + String.valueOf(ydpi) + "pixels per inchn";  

  17.  return str;  

  18. }  

5 取得状态栏和标题栏高度

Java代码  收藏代码
  1. TextView tv1;  

  2.  

  3. @Override  

  4. protected void onCreate(Bundle savedInstanceState) {  

  5.  super.onCreate(savedInstanceState);  

  6.  setContentView(R.layout.layout_test2);  

  7.  tv1 = (TextView) findViewById(R.id.TextView01);  

  8.  tv1.post(new Runnable(){  

  9.    public void run()  

  10.    {  

  11.      processLayout();  

  12.    }  

  13.  });  

  14. }  

  15.  

  16. private void processLayout(){  

  17.    

  18.  Rect rect= new Rect();  

  19.  Window window= getWindow();  

  20.  tv1.getWindowVisibleDisplayFrame(rect);  

  21.  //状态栏高度  

  22.  int statusBarHeight= rect.top;  

  23.  int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();  

  24.  //标题栏高度  

  25.  int titleBarHeight= contentViewTop – statusBarHeight;  

  26.  //测试结果:ok之后 100多 ms 才运行了  

  27.  Log.v("test", "=-init-= statusBarHeight="+statusBarHeight+  

  28.  " contentViewTop="+contentViewTop+  

  29.  " titleBarHeight="+titleBarHeight);      

  30.  

  31. }  

解决Visual Studio 2012 和SqlServer2008不兼容方法。。(报远程过程调用失败)

今天在装完VS2012 发现SqlServver2008不能用了  ,登录失败。

输入用户名密码,出现以下提示,无法连接数据库。(见图1)

 

图1

查看SQL Server配置管理工具,SQL Server服务中提示“远程过程调用失败”。(见图2)

 

图2

【解决办法】

首先,核查用户名密码是否正确。

其次,查看sql server 配置管理器中,第一项sql server服务能否远程过程连接。如果不能那是因为VS2012与sql server 2008不兼容情况,需要删除VS2012 express LocalDB即可。(见图3)

 

(见图3)

再次,将sql server 配置管理器=》sql server网络配置=》MSSQLSERVER协议=>VIA禁用。(见图4)

 

(见图4)

最后,重新启动“sql server服务”就可以连接上本地或远程服务器!(见图5)

(见图5)

重新使用用户名与密码登录即可连接数据库。

Eclipse设置配色方案

以前在网上看到很多程序猿华丽的编辑界面,很是羡慕,问他们那是什么编辑器时,它们简单回一句eclipse,为什么我的确没有这种界面呢??难道要我自己去慢慢调整?后来在网上找到了一个插件。这个是可以自己定义的。

第一步

     安装MPC(Eclipse Marketplace Client

Eclipse Marketplace是个插件应用商店,很实用的一个功能。

打开 eclipse,help–Eclipse Marketplace Client就能找到 如果没有的话你就要先安装啦!

help–install new software–add

添加name: Eclipse Marketplace Client  (随意起名)

Location:http://download.eclipse.org/mpc/indigo/

添加完成后,work with 选择Eclipse Marketplace Client

第二步 搜索主题

打开MarketPlace Client

 

 

输入Color Theme 查找主题;

 

OK安装插件完成

第三步 设置主题颜色

重启eclipse后再点击window -〉Preferences —> Appearance —> Color Theme

选个自己喜欢的颜色主题吧。。

JAVA 上加密算法的实现用例

1 章基础知识

1.1. 单钥密码体制

单钥密码体制是一种传统的加密算法,是指信息的发送方和接收方共同使用同一把密钥进行加解密。

通常 , 使用的加密算法 比较简便高效 , 密钥简短,加解密速度快,破译极其困难。但是加密的安全性依靠密钥保管的安全性 , 在公开的计算机网络上安全地传送和保管密钥是一个严峻的问题,并且如果在多用户的情况下密钥的保管安全性也是一个问题。

单钥密码体制的代表是美国的 DES

1.2. 消息摘要

一个消息摘要就是一个数据块的数字指纹。即对一个任意长度的一个数据块进行计算,产生一个唯一指印(对于 SHA1 是产生一个 20 字节的二进制数组)。

消息摘要有两个基本属性:

  • 两个不同的报文难以生成相同的摘要
  • 难以对指定的摘要生成一个报文,而由该报文反推算出该指定的摘要

代表:美国国家标准技术研究所的 SHA1 和麻省理工学院 Ronald Rivest 提出的 MD5

1.3. Diffie-Hellman 密钥一致协议

密钥一致协议是由公开密钥密码体制的奠基人 Diffie 和 Hellman 所提出的一种思想。

先决条件 , 允许两名用户在公开媒体上交换信息以生成”一致”的 , 可以共享的密钥

代表:指数密钥一致协议 (Exponential Key Agreement Protocol)

1.4. 非对称算法与公钥体系

1976 年,Dittie 和 Hellman 为解决密钥管理问题,在他们的奠基性的工作”密码学的新方向”一文中,提出一种密钥交换协议,允许在不安全的媒体上通过通讯双方交换信息,安全地传送秘密密钥。在此新思想的基础上,很快出现了非对称密钥密码体制,即公钥密码体制。在公钥体制中,加密密钥不同于解密密钥,加密密钥公之于众,谁都可以使用;解密密钥只有解密人自己知道。它们分别称为公开密钥(Public key)和秘密密钥(Private key)。

迄今为止的所有公钥密码体系中,RSA 系统是最著名、最多使用的一种。RSA 公开密钥密码系统是由 R.Rivest、A.Shamir 和 L.Adleman 俊教授于 1977 年提出的。RSA 的取名就是来自于这三位发明者的姓的第一个字母

1.5. 数字签名

所谓数字签名就是信息发送者用其私钥对从所传报文中提取出的特征数据(或称数字指纹)进行 RSA 算法操作,以保证发信人无法抵赖曾发过该信息(即不可抵赖性),同时也确保信息报文在经签名后末被篡改(即完整性)。当信息接收者收到报文后,就可以用发送者的公钥对数字签名进行验证。

在数字签名中有重要作用的数字指纹是通过一类特殊的散列函数(HASH 函数)生成的,对这些 HASH 函数的特殊要求是:

  1. 接受的输入报文数据没有长度限制;
  2. 对任何输入报文数据生成固定长度的摘要(数字指纹)输出
  3. 从报文能方便地算出摘要;
  4. 难以对指定的摘要生成一个报文,而由该报文反推算出该指定的摘要;
  5. 两个不同的报文难以生成相同的摘要

代表:DSA

2 章在 JAVA 中的实现

2.1. 相关

Diffie-Hellman 密钥一致协议和 DES 程序需要 JCE 工具库的支持 , 可以到 http://java.sun.com/security/index.html 下载 JCE, 并进行安装。简易安装把 jce1.2.1lib 下的所有内容复制到 %java_home%libext 下 , 如果没有 ext 目录自行建立 , 再把 jce1_2_1.jar 和 sunjce_provider.jar 添加到 CLASSPATH 内 , 更详细说明请看相应用户手册

2.2. 消息摘要 MD5 SHA 的使用

使用方法 :

首先用生成一个 MessageDigest 类 , 确定计算方法

java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");

添加要进行计算摘要的信息

alga.update(myinfo.getBytes());

计算出摘要

byte[] digesta=alga.digest();

发送给其他人你的信息和摘要

其他人用相同的方法初始化 , 添加信息 , 最后进行比较摘要是否相同

algb.isEqual(digesta,algb.digest())

相关 AIP

java.security.MessageDigest 类

static getInstance(String algorithm)

返回一个 MessageDigest 对象 , 它实现指定的算法

参数 : 算法名 , 如 SHA-1 或 MD5

void update (byte input)

void update (byte[] input)

void update(byte[] input, int offset, int len)

添加要进行计算摘要的信息

byte[] digest()

完成计算 , 返回计算得到的摘要 ( 对于 MD5 是 16 位 ,SHA 是 20 位 )

void reset()

复位

static boolean isEqual(byte[] digesta, byte[] digestb)

比效两个摘要是否相同

代码:

import java.security.*;

 public class myDigest {

  public static void main(String[] args)  {

    myDigest my=new myDigest();

    my.testDigest();

  }

  public void testDigest()

  {

   try {

     String myinfo=”我的测试信息”;

    //java.security.MessageDigest alg=java.security.MessageDigest.getInstance(“MD5”);

      java.security.MessageDigest alga=java.security.MessageDigest.getInstance(“SHA-1”);

      alga.update(myinfo.getBytes());

      byte[] digesta=alga.digest();

      System.out.println(“本信息摘要是 :”+byte2hex(digesta));

      // 通过某中方式传给其他人你的信息 (myinfo) 和摘要 (digesta) 对方可以判断是否更改或传输正常

      java.security.MessageDigest algb=java.security.MessageDigest.getInstance(“SHA-1”);

      algb.update(myinfo.getBytes());

      if (algb.isEqual(digesta,algb.digest())) {

         System.out.println(“信息检查正常”);

       }

       else

        {

          System.out.println(“摘要不相同”);

         }

   }

   catch (java.security.NoSuchAlgorithmException ex) {

     System.out.println(“非法摘要算法”);

   }

  }

  public String byte2hex(byte[] b) // 二行制转字符串

    {

     String hs=””;

     String stmp=””;

     for (int n=0;n<b.length;n++)

      {

       stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));

       if (stmp.length()==1) hs=hs+”0″+stmp;

       else hs=hs+stmp;

       if (n<b.length-1)  hs=hs+”:”;

      }

     return hs.toUpperCase();

    }

 }

2.3. 数字签名 DSA

  1. 对于一个用户来讲首先要生成他的密钥对 , 并且分别保存

生成一个 KeyPairGenerator 实例

java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance(“DSA”);

//如果设定随机产生器就用如相代码初始化

SecureRandom secrand=new SecureRandom();

secrand.setSeed(“tttt”.getBytes()); // 初始化随机产生器

keygen.initialize(512,secrand);     // 初始化密钥生成器

//否则

keygen.initialize(512);

//生成密钥公钥 pubkey 和私钥 prikey

KeyPair keys=keygen.generateKeyPair(); // 生成密钥组

PublicKey pubkey=keys.getPublic();

PrivateKey prikey=keys.getPrivate();

//分别保存在 myprikey.dat 和 mypubkey.dat 中 , 以便下次不在生成

//( 生成密钥对的时间比较长

java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(

    new java.io.FileOutputStream(“myprikey.dat”));

out.writeObject(prikey);

out.close();

out=new java.io.ObjectOutputStream(new java.io.FileOutputStream(“mypubkey.dat”));

out.writeObject(pubkey);

out.close();

  1. 用他私人密钥 (prikey) 对他所确认的信息 (info) 进行数字签名产生一个签名数组

从文件中读入私人密钥 (prikey)

java.io.ObjectInputStream in=new java.io.ObjectInputStream(

    new java.io.FileInputStream(“myprikey.dat”));

PrivateKey myprikey=(PrivateKey)in.readObject();

in.close();

初始一个 Signature 对象 , 并用私钥对信息签名

java.security.Signature signet=java.security.Signature.getInstance(“DSA”);

signet.initSign(myprikey);

signet.update(myinfo.getBytes());

byte[] signed=signet.sign();

把信息和签名保存在一个文件中 (myinfo.dat)

java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(

    new java.io.FileOutputStream(“myinfo.dat”));

out.writeObject(myinfo);

out.writeObject(signed);

out.close();

把他的公钥的信息及签名发给其它用户

  1. 其他用户用他的公共密钥 (pubkey) 和签名 (signed) 和信息 (info) 进行验证是否由他签名的信息

读入公钥
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream(“mypubkey.dat”));
PublicKey pubkey=(PublicKey)in.readObject();
in.close();

读入签名和信息
in=new java.io.ObjectInputStream(new java.io.FileInputStream(“myinfo.dat”));
String info=(String)in.readObject();
byte[] signed=(byte[])in.readObject();
in.close();

初始一个 Signature 对象 , 并用公钥和签名进行验证
java.security.Signature signetcheck=java.security.Signature.getInstance(“DSA”);
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
if (signetcheck.verify(signed)) { System.out.println(“签名正常”);}

对于密钥的保存本文是用对象流的方式保存和传送的 , 也可可以用编码的方式保存 . 注意要
import java.security.spec.*
import java.security.*

具休说明如下

  • public key 是用 X.509 编码的 , 例码如下 :

 byte[] bobEncodedPubKey=mypublic.getEncoded(); // 生成编码

   // 传送二进制编码

   // 以下代码转换编码为相应 key 对象

   X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);

   KeyFactory keyFactory = KeyFactory.getInstance(“DSA”);

   PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);

  • 对于 Private key 是用 PKCS#8 编码 , 例码如下 :

byte[] bPKCS=myprikey.getEncoded();

  // 传送二进制编码

  // 以下代码转换编码为相应 key 对象

  PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS);

  KeyFactory keyf=KeyFactory.getInstance(“DSA”);

  PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);

  1. 常用 API

java.security.KeyPairGenerator 密钥生成器类
public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException
以指定的算法返回一个 KeyPairGenerator 对象
参数 : algorithm 算法名 . 如:”DSA”,”RSA”

public void initialize(int keysize)

以指定的长度初始化 KeyPairGenerator 对象 , 如果没有初始化系统以 1024 长度默认设置

参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间,且必须为 64 的倍数

public void initialize(int keysize, SecureRandom random)
以指定的长度初始化和随机发生器初始化 KeyPairGenerator 对象
参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间,且必须为 64 的倍数
random 一个随机位的来源 ( 对于 initialize(int keysize) 使用了默认随机器

public abstract KeyPair generateKeyPair()
产生新密钥对

java.security.KeyPair 密钥对类
public PrivateKey getPrivate()
返回私钥

public PublicKey getPublic()
返回公钥

java.security.Signature 签名类
public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
返回一个指定算法的 Signature 对象
参数 algorithm 如 :”DSA”

public final void initSign(PrivateKey privateKey)
throws InvalidKeyException
用指定的私钥初始化
参数 :privateKey 所进行签名时用的私钥

public final void update(byte data)
throws SignatureException
public final void update(byte[] data)
throws SignatureException
public final void update(byte[] data, int off, int len)
throws SignatureException
添加要签名的信息

public final byte[] sign()
throws SignatureException
返回签名的数组 , 前提是 initSign 和 update

public final void initVerify(PublicKey publicKey)
throws InvalidKeyException
用指定的公钥初始化
参数 :publicKey 验证时用的公钥

public final boolean verify(byte[] signature)
throws SignatureException
验证签名是否有效 , 前提是已经 initVerify 初始化
参数 : signature 签名数组

 import java.security.*;

 import java.security.spec.*;

 public class testdsa {

  public static void main(String[] args) throws java.security.NoSuchAlgorithmException,

           java.lang.Exception {

        testdsa my=new testdsa();

        my.run();

  }

  public void run()

  {

  // 数字签名生成密钥

  // 第一步生成密钥对 , 如果已经生成过 , 本过程就可以跳过 ,

  // 对用户来讲 myprikey.dat 要保存在本地

  // 而 mypubkey.dat 给发布给其它用户

   if ((new java.io.File(“myprikey.dat”)).exists()==false) {

       if (generatekey()==false) {

           System.out.println(“生成密钥对败”);

           return;

          };

        }

 // 第二步 , 此用户

 // 从文件中读入私钥 , 对一个字符串进行签名后保存在一个文件 (myinfo.dat) 中

 // 并且再把 myinfo.dat 发送出去

 // 为了方便数字签名也放进了 myifno.dat 文件中 , 当然也可分别发送

  try {

  java.io.ObjectInputStream in=new java.io.ObjectInputStream(

           new java.io.FileInputStream(“myprikey.dat”));

  PrivateKey myprikey=(PrivateKey)in.readObject();

  in.close();

 // java.security.spec.X509EncodedKeySpec pubX509=

 //   new java.security.spec.X509EncodedKeySpec(bX509);

 //java.security.spec.X509EncodedKeySpec pubkeyEncode=

 //   java.security.spec.X509EncodedKeySpec

  String myinfo=”这是我的信息”;    // 要签名的信息

  // 用私钥对信息生成数字签名

  java.security.Signature signet=java.security.Signature.getInstance(“DSA”);

  signet.initSign(myprikey);

  signet.update(myinfo.getBytes());

  byte[] signed=signet.sign();  // 对信息的数字签名

  System.out.println(“signed( 签名内容 )=”+byte2hex(signed));

 // 把信息和数字签名保存在一个文件中

  java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(

           new java.io.FileOutputStream(“myinfo.dat”));

  out.writeObject(myinfo);

  out.writeObject(signed);

  out.close();

  System.out.println(“签名并生成文件成功”);

  }

  catch (java.lang.Exception e) {

    e.printStackTrace();

    System.out.println(“签名并生成文件失败”);

  };

  // 第三步

  // 其他人通过公共方式得到此户的公钥和文件

  // 其他人用此户的公钥 , 对文件进行检查 , 如果成功说明是此用户发布的信息 .

  //

  try {

   java.io.ObjectInputStream in=new java.io.ObjectInputStream(

            new java.io.FileInputStream(“mypubkey.dat”));

   PublicKey pubkey=(PublicKey)in.readObject();

   in.close();

   System.out.println(pubkey.getFormat());

   in=new java.io.ObjectInputStream(new java.io.FileInputStream(“myinfo.dat”));

   String info=(String)in.readObject();

   byte[] signed=(byte[])in.readObject();

   in.close();

  java.security.Signature signetcheck=java.security.Signature.getInstance(“DSA”);

  signetcheck.initVerify(pubkey);

  signetcheck.update(info.getBytes());

  if (signetcheck.verify(signed)) {

  System.out.println(“info=”+info);

   System.out.println(“签名正常”);

  }

  else  System.out.println(“非签名正常”);

  }

  catch (java.lang.Exception e) {e.printStackTrace();};

  }

  // 生成一对文件 myprikey.dat 和 mypubkey.dat— 私钥和公钥 ,

  // 公钥要用户发送 ( 文件 , 网络等方法 ) 给其它用户 , 私钥保存在本地

  public boolean generatekey()

  {

    try {

  java.security.KeyPairGenerator keygen =

           java.security.KeyPairGenerator.getInstance(“DSA”);

 // SecureRandom secrand=new SecureRandom();

 // secrand.setSeed(“tttt”.getBytes()); // 初始化随机产生器

 // keygen.initialize(576,secrand);     // 初始化密钥生成器

  keygen.initialize(512);

  KeyPair keys=keygen.genKeyPair();

 //  KeyPair keys=keygen.generateKeyPair(); // 生成密钥组

  PublicKey pubkey=keys.getPublic();

  PrivateKey prikey=keys.getPrivate();

  java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(

           new java.io.FileOutputStream(“myprikey.dat”));

  out.writeObject(prikey);

  out.close();

  System.out.println(“写入对象 prikeys ok”);

  out=new java.io.ObjectOutputStream(

           new java.io.FileOutputStream(“mypubkey.dat”));

   out.writeObject(pubkey);

   out.close();

   System.out.println(“写入对象 pubkeys ok”);

   System.out.println(“生成密钥对成功”);

   return true;

  }

  catch (java.lang.Exception e) {

   e.printStackTrace();

   System.out.println(“生成密钥对失败”);

   return false;

   };

  }

  public String byte2hex(byte[] b)

    {

     String hs=””;

     String stmp=””;

     for (int n=0;n<b.length;n++)

      {

       stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));

       if (stmp.length()==1) hs=hs+”0″+stmp;

       else hs=hs+stmp;

       if (n<b.length-1)  hs=hs+”:”;

      }

     return hs.toUpperCase();

    }

 }

2.4. DESede/DES 对称算法

首先生成密钥 , 并保存 ( 这里并没的保存的代码 , 可参考 DSA 中的方法 )

KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);

SecretKey deskey = keygen.generateKey();

用密钥加密明文 (myinfo), 生成密文 (cipherByte)

Cipher c1 = Cipher.getInstance(Algorithm);

c1.init(Cipher.ENCRYPT_MODE,deskey);

byte[] cipherByte=c1.doFinal(myinfo.getBytes());

传送密文和密钥 , 本文没有相应代码可参考 DSA

………….

用密钥解密密文

c1 = Cipher.getInstance(Algorithm);

c1.init(Cipher.DECRYPT_MODE,deskey);

byte[] clearByte=c1.doFinal(cipherByte);

相对来说对称密钥的使用是很简单的 , 对于 JCE 来讲支技 DES,DESede,Blowfish 三种加密术

对于密钥的保存各传送可使用对象流或者用二进制编码 , 相关参考代码如下

SecretKey deskey = keygen.generateKey();

byte[] desEncode=deskey.getEncoded();

javax.crypto.spec.SecretKeySpec destmp =

    new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm);

SecretKey mydeskey=destmp;

相关 API

KeyGenerator 在 DSA 中已经说明 , 在添加 JCE 后在 instance 进可以如下参数

DES,DESede,Blowfish,HmacMD5,HmacSHA1

javax.crypto.Cipher 加 / 解密器

public static final Cipher getInstance(java.lang.String transformation)

                                throws java.security.NoSuchAlgorithmException,

                                       NoSuchPaddingException

返回一个指定方法的 Cipher 对象

参数 :transformation 方法名 ( 可用 DES,DESede,Blowfish)

public final void init(int opmode, java.security.Key key)
throws java.security.InvalidKeyException

用指定的密钥和模式初始化 Cipher 对象

参数:opmode 方式 (ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)

key 密钥

public final byte[] doFinal(byte[] input)

                     throws java.lang.IllegalStateException,

                            IllegalBlockSizeException,

                            BadPaddingException

对 input 内的串 , 进行编码处理 , 返回处理后二进制串 , 是返回解密文还是加解文由 init 时的 opmode 决定

注意 : 本方法的执行前如果有 update, 是对 updat 和本次 input 全部处理 , 否则是本 inout 的内容

/*

安全程序 DESede/DES 测试

 */

 import java.security.*;

 import javax.crypto.*;

 public class testdes {

 public static void main(String[] args){

    testdes my=new testdes();

    my.run();

  }

 public  void run() {

 // 添加新安全算法 , 如果用 JCE 就要把它添加进去

 Security.addProvider(new com.sun.crypto.provider.SunJCE());

 String Algorithm=”DES”; // 定义 加密算法 , 可用 DES,DESede,Blowfish

 String myinfo=”要加密的信息”;

   try {

   // 生成密钥

   KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);

   SecretKey deskey = keygen.generateKey();

   // 加密

   System.out.println(“加密前的二进串 :”+byte2hex(myinfo.getBytes()));

   System.out.println(“加密前的信息 :”+myinfo);

   Cipher c1 = Cipher.getInstance(Algorithm);

   c1.init(Cipher.ENCRYPT_MODE,deskey);

   byte[] cipherByte=c1.doFinal(myinfo.getBytes());

    System.out.println(“加密后的二进串 :”+byte2hex(cipherByte));

   // 解密

   c1 = Cipher.getInstance(Algorithm);

   c1.init(Cipher.DECRYPT_MODE,deskey);

   byte[] clearByte=c1.doFinal(cipherByte);

   System.out.println(“解密后的二进串 :”+byte2hex(clearByte));

   System.out.println(“解密后的信息 :”+(new String(clearByte)));

  }

   catch (java.security.NoSuchAlgorithmException e1) {e1.printStackTrace();}

   catch (javax.crypto.NoSuchPaddingException e2) {e2.printStackTrace();}

   catch (java.lang.Exception e3) {e3.printStackTrace();}

  }

 public String byte2hex(byte[] b) // 二行制转字符串

    {

     String hs=””;

     String stmp=””;

     for (int n=0;n<b.length;n++)

      {

       stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));

       if (stmp.length()==1) hs=hs+”0″+stmp;

       else hs=hs+stmp;

       if (n<b.length-1)  hs=hs+”:”;

      }

     return hs.toUpperCase();

    }

 }

2.5. Diffie-Hellman 密钥一致协议

公开密钥密码体制的奠基人 Diffie 和 Hellman 所提出的 “指数密钥一致协议”(Exponential Key Agreement Protocol), 该协议不要求别的安全性 先决条件 , 允许两名用户在公开媒体上交换信息以生成”一致”的 , 可以共享的密钥。在 JCE 的中实现用户 alice 生成 DH 类型的密钥对 , 如果长度用 1024 生成的时间请 , 推荐第一次生成后保存 DHParameterSpec, 以便下次使用直接初始化 . 使其速度加快

System.out.println(“ALICE: 产生 DH 对 …”);

 KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance(“DH”);

 aliceKpairGen.initialize(512);

 KeyPair aliceKpair = aliceKpairGen.generateKeyPair();

alice 生成公钥发送组 bob

byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

bob 从 alice 发送来的公钥中读出 DH 密钥对的初始参数生成 bob 的 DH 密钥对

注意这一步一定要做 , 要保证每个用户用相同的初始参数生成的

  DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();

    KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance(“DH”);

    bobKpairGen.initialize(dhParamSpec);

    KeyPair bobKpair = bobKpairGen.generateKeyPair();

bob 根据 alice 的公钥生成本地的 DES 密钥

  KeyAgreement bobKeyAgree = KeyAgreement.getInstance(“DH”);

    bobKeyAgree.init(bobKpair.getPrivate());

    bobKeyAgree.doPhase(alicePubKey, true);

    SecretKey bobDesKey = bobKeyAgree.generateSecret(“DES”);

bob 已经生成了他的 DES 密钥 , 他现把他的公钥发给 alice,

     byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

alice 根据 bob 的公钥生成本地的 DES 密钥

      ,,,,,, 解码

    KeyAgreement aliceKeyAgree = KeyAgreement.getInstance(“DH”);

    aliceKeyAgree.init(aliceKpair.getPrivate());

    aliceKeyAgree.doPhase(bobPubKey, true);

    SecretKey aliceDesKey = aliceKeyAgree.generateSecret(“DES”);

bob 和 alice 能过这个过程就生成了相同的 DES 密钥 , 在这种基础就可进行安全能信

常用 API

java.security.KeyPairGenerator 密钥生成器类
public static KeyPairGenerator getInstance(String algorithm)
throws NoSuchAlgorithmException
以指定的算法返回一个 KeyPairGenerator 对象
参数 : algorithm 算法名 . 如 : 原来是 DSA, 现在添加了 DiffieHellman(DH)

public void initialize(int keysize)
以指定的长度初始化 KeyPairGenerator 对象 , 如果没有初始化系统以 1024 长度默认设置
参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间,且必须为 64 的倍数
注意 : 如果用 1024 生长的时间很长 , 最好生成一次后就保存 , 下次就不用生成了

public void initialize(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException
以指定参数初始化

javax.crypto.interfaces.DHPublicKey
public DHParameterSpec getParams()
返回
java.security.KeyFactory

public static KeyFactory getInstance(String algorithm)
throws NoSuchAlgorithmException
以指定的算法返回一个 KeyFactory
参数 : algorithm 算法名:DSH,DH

public final PublicKey generatePublic(KeySpec keySpec)
throws InvalidKeySpecException
根据指定的 key 说明 , 返回一个 PublicKey 对象

java.security.spec.X509EncodedKeySpec
public X509EncodedKeySpec(byte[] encodedKey)
根据指定的二进制编码的字串生成一个 key 的说明
参数 :encodedKey 二进制编码的字串 ( 一般能过 PublicKey.getEncoded() 生成 )
javax.crypto.KeyAgreement 密码一至类

public static final KeyAgreement getInstance(java.lang.String algorithm)
throws java.security.NoSuchAlgorithmException
返回一个指定算法的 KeyAgreement 对象
参数 :algorithm 算法名 , 现在只能是 DiffieHellman(DH)

public final void init(java.security.Key key)
throws java.security.InvalidKeyException
用指定的私钥初始化
参数 :key 一个私钥

public final java.security.Key doPhase(java.security.Key key,
boolean lastPhase)
throws java.security.InvalidKeyException,
java.lang.IllegalStateException
用指定的公钥进行定位 ,lastPhase 确定这是否是最后一个公钥 , 对于两个用户的
情况下就可以多次定次 , 最后确定
参数 :key 公钥
lastPhase 是否最后公钥

public final SecretKey generateSecret(java.lang.String algorithm)
throws java.lang.IllegalStateException,
java.security.NoSuchAlgorithmException,
java.security.InvalidKeyException
根据指定的算法生成密钥
参数 :algorithm 加密算法 ( 可用 DES,DESede,Blowfish)

*/

 import java.io.*;

 import java.math.BigInteger;

 import java.security.*;

 import java.security.spec.*;

 import java.security.interfaces.*;

 import javax.crypto.*;

 import javax.crypto.spec.*;

 import javax.crypto.interfaces.*;

 import com.sun.crypto.provider.SunJCE;

 public class testDHKey {

    public static void main(String argv[]) {

    try {

        testDHKey my= new testDHKey();

        my.run();

    } catch (Exception e) {

        System.err.println(e);

    }

    }

    private void run() throws Exception {

        Security.addProvider(new com.sun.crypto.provider.SunJCE());

    System.out.println(“ALICE: 产生 DH 对 …”);

    KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance(“DH”);

        aliceKpairGen.initialize(512);

    KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); // 生成时间长

        // 张三 (Alice) 生成公共密钥 alicePubKeyEnc 并发送给李四 (Bob) ,

        // 比如用文件方式 ,socket…..

    byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

       //bob 接收到 alice 的编码后的公钥 , 将其解码

    KeyFactory bobKeyFac = KeyFactory.getInstance(“DH”);

    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec  (alicePubKeyEnc);

    PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);

        System.out.println(“alice 公钥 bob 解码成功”);

     // bob 必须用相同的参数初始化的他的 DH KEY 对 , 所以要从 Alice 发给他的公开密钥 ,

         // 中读出参数 , 再用这个参数初始化他的 DH key 对

         // 从 alicePubKye 中取 alice 初始化时用的参数

    DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();

    KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance(“DH”);

    bobKpairGen.initialize(dhParamSpec);

    KeyPair bobKpair = bobKpairGen.generateKeyPair();

        System.out.println(“BOB: 生成 DH key 对成功”);

    KeyAgreement bobKeyAgree = KeyAgreement.getInstance(“DH”);

    bobKeyAgree.init(bobKpair.getPrivate());

        System.out.println(“BOB: 初始化本地 key 成功”);

        // 李四 (bob) 生成本地的密钥 bobDesKey

    bobKeyAgree.doPhase(alicePubKey, true);

    SecretKey bobDesKey = bobKeyAgree.generateSecret(“DES”);

    System.out.println(“BOB: 用 alice 的公钥定位本地 key, 生成本地 DES 密钥成功”);

        // Bob 生成公共密钥 bobPubKeyEnc 并发送给 Alice,

        // 比如用文件方式 ,socket….., 使其生成本地密钥

    byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

        System.out.println(“BOB 向 ALICE 发送公钥”);

         // alice 接收到 bobPubKeyEnc 后生成 bobPubKey

         // 再进行定位 , 使 aliceKeyAgree 定位在 bobPubKey

    KeyFactory aliceKeyFac = KeyFactory.getInstance(“DH”);

    x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);

    PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);

       System.out.println(“ALICE 接收 BOB 公钥并解码成功”);

 ;

    KeyAgreement aliceKeyAgree = KeyAgreement.getInstance(“DH”);

    aliceKeyAgree.init(aliceKpair.getPrivate());

        System.out.println(“ALICE: 初始化本地 key 成功”);

    aliceKeyAgree.doPhase(bobPubKey, true);

        // 张三 (alice) 生成本地的密钥 aliceDesKey

    SecretKey aliceDesKey = aliceKeyAgree.generateSecret(“DES”);

        System.out.println(“ALICE: 用 bob 的公钥定位本地 key, 并生成本地 DES 密钥”);

        if (aliceDesKey.equals(bobDesKey)) System.out.println(“张三和李四的密钥相同”);

       // 现在张三和李四的本地的 deskey 是相同的所以 , 完全可以进行发送加密 , 接收后解密 , 达到

       // 安全通道的的目的

        /*

         * bob 用 bobDesKey 密钥加密信息

         */

    Cipher bobCipher = Cipher.getInstance(“DES”);

    bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey);

        String bobinfo= “这是李四的机密信息”;

        System.out.println(“李四加密前原文 :”+bobinfo);

    byte[] cleartext =bobinfo.getBytes();

    byte[] ciphertext = bobCipher.doFinal(cleartext);

        /*

         * alice 用 aliceDesKey 密钥解密

         */

    Cipher aliceCipher = Cipher.getInstance(“DES”);

    aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey);

    byte[] recovered = aliceCipher.doFinal(ciphertext);

        System.out.println(“alice 解密 bob 的信息 :”+(new String(recovered)));

    if (!java.util.Arrays.equals(cleartext, recovered))

        throw new Exception(“解密后与原文信息不同”);

    System.out.println(“解密后相同”);

    }

 }

3 章小结

在加密术中生成密钥对时,密钥对的当然是越长越好,但费时也越多,请从中从实际出发选取合适的长度,大部分例码中的密钥是每次运行就从新生成,在实际的情况中是生成后在一段时间保存在文件中,再次运行直接从文件中读入,从而加快速度。当然定时更新和加强密钥保管的安全性也是必须的。

 转载自:http://www.ibm.com/developerworks/cn/java/l-security/

关于域名备案

关于域名备案,我真的无话可说。www.ahsiu.com是我大一的时候在美橙互联注册的。那时候搞活动很便宜。那时候主机是用的主机屋,可以不需备案免费绑定到虚拟主机上的,但搬迁到sae却无法直接绑定。需要通过通过国外服务器中转。所以云豆要翻倍,而且速度只有直接访问二级域名的20%不到。如果要直接解析到网站则需提供备案号,但网站备案又需要提供主机信息。美橙互联客服直接来了一句只能备案到美橙的主机。
    好吧这备案号估计是搞不到了。恨透这些没事找事。拿纳税人的钱不做实事的人和相关单位了。备个案搞这么麻烦,又没有从根本上阻止那些非法网站,还不如一个360浏览器呢。不晓得那些人脑袋怎么长的。

Blog搬家了~

很久没有再跟新这个blog了。我觉得我是个比较懒的人,有时候兴致来了很想做某件事,却总觉得自己很忙,又懒于立即行动。时间就这样过去了,最后反思的时候发现原来什么也没做。

首先我想说的是为什么我会重新开启我的blog,有时候我非常想分享一些好的技术文章,和自己的一些见解。我也曾想过为何不直接放在其它网站提供的blog上呢?比如(QQ空间,csdn,博客园)上呢,第一个是限制太多了,不能写自己的脚本。第二个搜索引擎无法记录,第三方博客往往会屏蔽一些搜索引擎。我希望一些有用的东西能够被大家搜索到。第三个是这将是我的唯一博客。我的域名是 ahsiu.com 阿修,(这是google音译过来的),如果哥以后有钱了会自己搞个服务器,毕竟sae还是有限制的。

重启博客我是把网站从主机屋上搬迁到sae上的,以前一直用主机屋,虽然免费,但每个月总要去做几次广告,否则就会停掉。实在不是我的风格。

顺便发一下变迁的过程吧。。wordpress搬迁到新浪sae

我觉得我应该养成一个记录的习惯。很久没有写点东西,现在写来确实有些词穷。随意吧,想写到哪就写到哪。呵呵,反正大部分内容是自己看。

 

顺带如果有人也想拥有用这个博客的话,可以点击这个注册 http://sae.sina.com.cn/activity/invite/163473/weibo

 

wordpress搬迁到新浪sae

今天花了几个小时终于搞定了,把网站从主机屋搬迁到了新浪sae。写这些东西确实有点小菜,老鸟莫笑。首先分析一下难点在哪里。主机屋是普通的虚拟主机,搭建的时候只要把数据库导入数据库,然后把网站上传到服务器上就可以了。但是sae的架构不一样,但是理解起来也简单。sae采用的是分布式的架构,你的资源和你的数据库是保存在别的服务器上的,比如其附件是单独存在saestorage中,不能存放在代码目录中的,这些问题我想还好理解。同时也理解了大型应用是如何处理这些压力的。

废话少说,首先通过ftp把主机屋上的网站下载到本地。数据库通过主机屋提供的 PHPMyAdmin进行全部备份到本地。如果不确定有没有没问题的话可以先在本地搭建环境跑一边。

然后创建一个php应用 具体教程在这里

http://sae.sina.com.cn/?m=devcenter&catId=20

但是。。。。。 sae如果直接装我们自己搭建的wordpress会有很多问题的,因为它是分布式的架构,一种简便的方法是我们之间创建一个WordPress for SAE 地址在:http://sae.sina.com.cn/?m=apps&a=detail&aid=1

安装完成后我们找到创建的应用〉服务管理〉管理Mysql 进入phpMyAdmin管理界面 里面的表全删掉,然后导入我们 之前从主机屋上备份的sql文件。

然后在本地创建一个空文件夹,用TortoiseSVN迁出版本库中的文件到空白文件夹中。svn具体教程在

http://sae.sina.com.cn/?m=devcenter&a=index&catId=212

下一步我把我们之前本地的网站中的 wp-contentuploads文件夹单独剪切出来,其它文件拷贝到版本库中,(就是你迁出的那个默认目录是 1) 注意同名不要覆盖掉版本库中的文件,然后commit 到服务器上。

然后利用另外一个工具cyberduck 把文件提交到saeStorage中,

也可以在

下载地址:

http://src.sae.sinacdn.com/clients/Cyberduck-Installer-4.2.1.exe

使用方法

http://sae.sina.com.cn/?m=devcenter&catId=204&content_id=375

同时可以在服务管理〉storage中查看更多内容。。

 

最后 如果少的话慢慢修改你文章中 相册中的附件地址吧(要改成storage中的地址,比如

http://应用名-wordpress.stor.sinaapp.com/uploads/xxx.jpg)。如果多的用sql要快很多(这个你就自己去写吧).