海鸥航迹

学习之笔记,好文之收集。

2011年8月19日 #

Windows批处理中的等待技巧

1、直接使用Windows 2003资源工具包中的Sleep.exe 程序,它在全系列Windows中都可以运行;

2、使用下面的技巧

@ping 127.0.0.1 –n 12 >nul

由于Windows Ping目标地址是间隔1秒,上面的指令相当于等候12秒;

posted @ 2011-08-19 23:08 海天一鸥 阅读(225) 评论(0) 编辑

2011年8月9日 #

The Ice::Current Object

The Ice::Current Object

服务器端Servant骨架方法(skeleton operation)都有一个Ice::Current类型的参数,这个对象定义如下:

module Ice {

local dictionary<string, string> Context;

enum OperationMode { Normal, \Nonmutating, \Idempotent };

local struct Current {

ObjectAdapter adapter;

Connection con;

Identity id;

string facet;

string operation;

OperationMode mode;

Context ctx;

int requestId;

};

};

这个对象提供了服务器端实现当前正在执行的这个操作的一些信息访问入口:

adapter:

adapter成员提供对object adapter的访问,请求就是通过它被分派的。依次的,adapter提供对communicator的访问,通过getCommunicator操作,如此,就能访问到ICE一切环境信息,如配置属性。

con

con成员提供对接收请求的连接的访问,参见37.5.1;

id

id成员提供当前请求的对象标识,实际就是当前servant的对象标识。

Facet

提供对当前请求的facet的访问;

Operation

包含了要调用的方法的名称。注意操作名也可能是Ice::Object 上的方法,诸如ice_ping,ice_isA(checkCast方法会调用ice_isA)等等;

Mode

代表当前操作的调用模式;

Ctx

包含了当前调用的上下文;

RequestId

Ice协议的请求ID;

posted @ 2011-08-09 22:46 海天一鸥 阅读(95) 评论(0) 编辑

ICE代理的固有方法

 

Table 32.1. The semantics of core proxy methods.

Method

Description

Remote

ice_isA

Returns true if the remote object supports the type indi­cated by the id argument, oth­erwise false. This method can only be invoked on a two­way proxy.

Yes

ice_ping

Determines whether the remote object is reachable. Does not return a value.

Yes

ice_ids

Returns the type ids of the types supported by the remote object. The return value is an array of strings. This method can only be invoked on a twoway proxy.

Yes

ice_id

Returns the type id of the most-derived type supported by the remote object. This method can only be invoked on a twoway proxy.

Yes

ice_getHash

Returns a hash value for the proxy for C++. For other lan­guage mappings, use the built-in hash method.

No

ice_getCommunicator

Returns the communicator that was used to create this proxy.

No

ice_toString

Returns the string representa­tion of the proxy.

No

ice_identity

Returns a new proxy having the given identity.

No

ice_getIdentity

Returns the identity of the Ice object represented by the proxy.

No

ice_adapterId

Returns a new proxy having the given adapter id.

No

ice_getAdapterId

Returns the proxy’s adapter id, or an empty string if no adapter id is configured.

No

ice_endpoints

Returns a new proxy having the given endpoints.

No

ice_getEndpoints

Returns a sequence of End­point objects representing the proxy’s endpoints. See Section 36.5.2 for more infor­mation.

No

ice_endpointSelection

Returns a new proxy having the given selection policy (random or ordered). See Section 36.3.1 for more information.

No

ice_getEndpointSelection

Returns the endpoint selection policy for the proxy.

No

ice_context

Returns a new proxy having the given request context. See Section 32.12 for more infor­mation on request contexts.

No

ice_getContext

Returns the request context associated with the proxy. See Section 32.12 for more infor­mation on request contexts.

No

ice_facet

Returns a new proxy having the given facet name. See Chapter 33 for more informa­tion on facets.

No

ice_getFacet

Returns the name of the facet associated with the proxy, or an empty string if no facet has been set. See Chapter 33 for more information on facets.

No

ice_twoway

Returns a new proxy for mak­ing twoway invocations.

No

ice_isTwoway

Returns true if the proxy uses twoway invocations, otherwise false.

No

ice_oneway

Returns a new proxy for mak­ing oneway invocations (see Section 32.14).

No

ice_isOneway

Returns true if the proxy uses oneway invocations, otherwise false.

No

ice_batchOneway

Returns a new proxy for mak­ing batch oneway invocations (see Section 32.16).

No

ice_isBatchOneway

Returns true if the proxy uses batch oneway invocations, oth­erwise false.

No

ice_datagram

Returns a new proxy for mak­ing datagram invocations (see Section 32.15).

No

ice_isDatagram

Returns true if the proxy uses datagram invocations, other­wise false.

No

ice_batchDatagram

Returns a new proxy for mak­ing batch datagram invocations (see Section 32.16).

No

ice_isBatchDatagram

Returns true if the proxy uses batch datagram invocations, otherwise false.

No

ice_secure

Returns a new proxy whose endpoints may be filtered depending on the boolean argu­ment. If true, only endpoints using secure transports are allowed, otherwise all end­points are allowed.

No

ice_isSecure

Returns true if the proxy uses only secure endpoints, other­wise false.

No

ice_preferSecure

Returns a new proxy whose endpoints are filtered depend­ing on the boolean argument. If true, endpoints using secure transports are given precedence over endpoints using non-secure transports. If false, the default behavior gives prece­dence to endpoints using non-secure transports.

No

ice_isPreferSecure

Returns true if the proxy pre­fers secure endpoints, otherwise false.

No

ice_compress

Returns a new proxy whose protocol compression capability is determined by the boolean argument. If true, the proxy uses protocol compression if it is supported by the endpoint. If false, protocol compression is never used.

No

ice_timeout

Returns a new proxy with the given timeout value in millisec­onds. A value of ‑1 disables timeouts. See Section 32.13 for more information on timeouts.

No

ice_router

Returns a new proxy configured with the given router proxy. See Chapter 42 for more informa­tion on routers.

No

ice_getRouter

Returns the router that is con­figured for the proxy (null if no router is configured).

No

ice_locator

Returns a new proxy with the specified locator. See Chapter 38 for more informa­tion on locators.

No

ice_getLocator

Returns the locator that is con­figured for the proxy (null if no locator is configured).

No

ice_locatorCacheTimeout

Returns a new proxy with the specified locator cache time­out. When binding a proxy to an endpoint, the run time caches the proxy returned by the loca­tor and uses the cached proxy while the cached proxy has been in the cache for less than the timeout. Proxies older than the timeout cause the run time to rebind via the locator. A value of 0 disables caching entirely, and a value of ‑1 means that cached proxies never expire. The default value is ‑1.

No

ice_getLocatorCacheTimeout

Returns the locator cache time­out value in seconds.

No

ice_collocationOptimized

Returns a new proxy configured for collocation optimization. If true, collocated optimiza­tions are enabled. The default value is true.

No

ice_isCollocationOptimized

Returns true if the proxy uses collocation optimization, other­wise false.

No

ice_connectionId

Returns a new proxy having the given connection identifier. See Section 36.3.3 for more infor­mation.

No

ice_getConnectionId

Returns the connection id, or an empty string if no connection id has been configured.

No

ice_getConnection

Returns an object representing the connection used by the proxy. If the proxy is not cur­rently associated with a connec­tion, the Ice run time attempts to establish a connection first. See Section 36.5 for more information.

No

ice_getCachedConnection

Returns an object representing the connection used by the proxy, or null if the proxy is not currently associated with a con­nection. See Section 36.5 for more information.

No

ice_connectionCached

Enables or disables connection caching for the proxy. See Section 36.3.4 for more infor­mation

No

ice_isConnectionCached

Returns true if the proxy uses connection caching, otherwise false.

No

ice_flushBatchRequests

Sends a batch of operation invocations synchronously or asynchronously (see Section 32.16).

Yes

begin_ice_flushBatchRequests

ice_invoke

Allows dynamic invocation of an operation without the need for compiled Slice definitions. Requests can be sent synchro­nously (see Section 35.3.1) or asynchronously (see Section 35.4).

Yes

begin_ice_invoke

posted @ 2011-08-09 22:45 海天一鸥 阅读(141) 评论(0) 编辑

2011年8月7日 #

C# Tips 2则

C# Textbox Auto Scroll To End ScrollToCaret Scrolling Textbox
Many of my sample C# codes,
I use textbox to write the results.

When textbox is multiline property set to true, and when I insert text into it,
I want it to auto scroll to the last line.

Here is a simple way to auto scrolling textbox.

textbox1.SelectionStart = textbox1.Text.Length;
textbox1.ScrollToCaret();
textbox1.Refresh();

Textbox SelectionStart will force the textbox control to select the last part of the text,
and ScrollToCaret() function will auto scroll textbox to the end.

 

C# Convert Hexadecimal to Binary String Conversion

There is no need to code tons of codes, loops, to convert hex to binary string. Convert.ToInt32 function is very useful for this purpose.
Let's convert the "A" character to binary format.

private string hex2binary(string hexvalue)
{
string binaryval = "";
binaryval = Convert.ToString(Convert.ToInt32(hexvalue, 16), 2);
return binaryval;
}
When we call hex2binary("A"); it will return "1010" similar samples below;
hex2binary("1a"); will return "11010";
hex2bianry("1a2c"); will return "1101000101100"; and so on.
Keep in mind that this hex to binary conversion style uses 32 bit integer number.

posted @ 2011-08-07 21:42 海天一鸥 阅读(97) 评论(0) 编辑

2011年8月2日 #

Configuring log4net with VS2010 and .Net 4.0

摘要: Configuring log4net with VS2010 and .Net 4.0 After spending a few hours this morning trying to get l...阅读全文

posted @ 2011-08-02 21:28 海天一鸥 阅读(204) 评论(0) 编辑

2011年7月28日 #

IoC Container Benchmark - Unity, Windsor, StructureMap and Spring.NET

There are a number of inversion of control containers out there so I thought it would be an interesting experiment to do a simple benchmark. There are different ways that one can instantiate a type in .NET, for example via the new operator, Activator, GetUninitializedObject and Dynamic Method. The performance difference between these methods are in some cases quite high, maybe the same is true for these IoC containers? Granted IoC containers do more than just create objects so other factors will probably play a big role in the results.

So here are the contestants:

I have been using Castle Windsor since 2005 and I think it is the best of the bunch, so I guess I am unconsciously biased toward Windsor.  However I will try to make this benchmark as objective as I can.

The scenario for this test:

  • Have each IoC container resolve a UserController 1000 000 times
  • The UserController will have two constructor dependencies
  • Run the test with transient (new instance for each resolve) and singleton components

The UserController looks like this:

public class UserController

{

private IUserRepository repository;

private IAuthentificationService authService;

public UserController(IUserRepository repository, IAuthentificationService authService)

{

this.repository = repository;

this.authService = authService;

}

}

I have also a general container interface that the benchmark engine will use. Each container will implement this interface.

public interface IContainer

{

string Name { get; }

T Resolve<T>();

void SetupForTransientTest();

void SetupForSingletonTest();

}

All tests used the latest released version of each library. Before you interpret these charts please observe that the measurement is for one million component resolves which means the actual time difference between each container is actually very small.

Here are the results when all components were setup as singletons:

clip_image002

Here are the results when all components were setup as transient:

clip_image004

So what does these charts tell us? Lets take the biggest difference in the transient case, Spring.NET took 44.149 seconds and Unity took 8.164 seconds, what is the actual difference when resolving a single instance?

Spring.NET : 44.149 / 1000000 = 0.000044149 seconds

Unity : 8.164 / 1000000 = 0.000008164 seconds

So the actual difference is only about 36 microseconds. Another way to put these values into perspective is to compare against the new operator. I created a NewOperatorContainer with a resolve method that looks like this:

public T Resolve<T>()

{

object o = new UserController(new LdapUserRepository(), new DefaultAuthentificationService());

return (T) o;

}

OK, comparing the above with an inversion of control container is like comparing apples to oranges, an IoC handles so much more than just object creation. Also an IoC cannot use the new operator directly but must use one of the other methods. My guess is that all IoC containers in this test uses an approach which involve IL Generation which if cashed comes close to using the new operator directly. Anyway I think it will show just how small the difference between the real IoC containers are. In order to visualize this I needed to invert the values so that high means fast and low means slow.

image

http://lh3.ggpht.com/torkel.odegaard/SALo6OJA3yI/AAAAAAAAAWg/Nhrvuby1VUE/s1600-h/IoCInversed[5].png

Update: The above chart can be very misleading. The x-axis is not seconds but 1/s. I hope it shows that the difference between the containers are very small compared to instantiating the objects manually.

OK, can we draw any conclusion from the test? Well I think we can say that performance should not be an issue when choosing one of these IoC containers. The difference is too small. When you choose which container to use you should consider other aspects, like how invasive the container is to they way you want to work.

For the complete code: IoCBenchmark.zip

Posted by Torkel Ödegaard at 6:46 AM

Labels: Benchmarks, C#, Castle, IoC

13 comments:

Anonymous said...

IMHO your last graph is very misleading. why do you use the inverse values? use the usual values and point out how tiny the "new" value is - or if you feel like the inverse is beneficial at least label your axis correctly.
otherwise nice article

April 14, 2008 1:20 PM clip_image006

Torkel Ödegaard said...

Yes, you are right. I also feel that the last graph is too misleading. I will correct it when I get home from work.

April 14, 2008 1:25 PM clip_image006[1]

Joshua said...

I would interested to see how Ninject compares.

April 14, 2008 6:57 PM clip_image006[2]

Torkel Ödegaard said...

I guess it should have been in the test having a slogan like "Lightning-fast dependency injection for .NET"
Hopefully I will have time to do it later in the week, thanks for the tip!

April 14, 2008 7:40 PM clip_image006[3]

Bil Simser said...

This is interesting but IMHO a bit of a waste of time. I mean, what application would *ever* need to try to create a million objects all at once? Even in a tight loop you *might* create a few thousand objects. I just can't think of any use case where this situation would ever manifest itself so to me the numbers are pretty meaningless. Interesting to look at, but not of any value to judge something by. If the differences were significant with say a few hundred objects then maybe this exercise would be worth something.

April 16, 2008 3:53 PM clip_image006[4]

Torkel Ödegaard said...

Yes, I agree that this is not a realistic scenario. Doing one million resolves is not something that do in one request. That was just to accumulate the performance difference to see if there were any substantial difference.
I don't think it was a waste of time, because it could have potentially been a big meaningful difference between them. Now it turned out that there weren't but that didn't make the test meaningless, because now you know :)

April 16, 2008 4:25 PM clip_image006[5]

Nate Kohari said...

Nice post. I'd also be interested to know how Ninject does in comparison. :)
Bil's right, though, that it wouldn't typically make a difference, because most applications don't need to create 1,000,000 instances. However, faster IoC also means that you can use it in places that you wouldn't otherwise be able to -- for example, devices that support the compact framework.
Still a worthwhile study, and it's interesting to see the results!

April 16, 2008 9:43 PM clip_image006[6]

Ruurd Boeke said...

I'm sorry, but if you are going to do a test and find a huge relative difference, you should not disregard it by looking at the absolute difference. What's the point in doing the test than?
I think it's pretty clear that no container takes a very long time, so what were you hoping to find?
(no disrespect meant, I clicked on the post because I was curious as well ;-) )

April 16, 2008 10:09 PM clip_image006[7]

Torkel Ödegaard said...

Well the point was to check if there was any relevant difference, not to check which was the fastest.
And I think you can actually disregard a relative difference if that difference is still not relevant when you look at the absolute performance.
My conclusion to the test was that the relative difference was too small to make any relevant difference in real applications.

April 16, 2008 10:41 PM clip_image006[8]

Anonymous said...

Nice benchmark. A functional comparison for the used Ioc Containers would be interesting. Where do the performance differences come from?

April 17, 2008 9:20 AM clip_image006[9]

Nick said...

I think the comment about functional differences is important - what are you getting for you time?
In a real app with more components, the factors affecting container performance will shift from the expense of creating instances, to the expense associated with algorithms that are affected by the number of instances (e.g. which instance from many should be returned?) and algorithms that take a time proportional to the size of the dependency graph (e.g. circular dependency checking.)
You can never tell where that performance bottleneck is going to be until you measure it ;)

April 20, 2008 8:09 AM clip_image006[10]

sharkboy said...

I think what this page shows is that using IOC containers will not make your app significantly slower. What makes apps slow are poor design, bad databases, and network latency.
As to which one to use, you have to try and figure out which one has a future.
I would rule out Spring.Net because it is a Java port and will always be several steps behind in supporting the latest .Net framework features.
StructureMap is cool but since only one guy is supporting it I would expect the project to die once that dude gets tired of dealing with it.
Unity may be the safe bet being that it has "Official" support from Microsoft. The MS guys where starting to promote this at TechEd this year. On the other hand, don't expect any innovation from Microsoft.
If you want a supported component, go with Unity. If you want innovation, go Windsor.

June 16, 2008 6:24 AM clip_image006[11]

Luke said...

You clearly don't know Jeremy Miller very well if you think that's what'll happen with StructureMap.

July 6, 2008 5:31 PM

posted @ 2011-07-28 21:23 海天一鸥 阅读(93) 评论(1) 编辑

Functional .NET 4.0 – Tuples and Zip

Previously, when covering some of the additions to the .NET 4.0 Framework such as optional and named parameters, some of the other additions have caught my eye from the perspective of functional programming.  Unlike .NET 3.5, this release is not as targeted towards functional programming as it is more towards dynamic programming and COM interoperability.  But, there are a few items to note that we can soon take advantage of, including the Tuple type and the Zip operator function among other items.

Looking at Tuples

To define a tuple, it comes from the mathematics field, and is simply an ordered list of values, which are components of that tuple.  These components can be of any type, whether it be string, integer, or otherwise.  In order to refer to these components, we retrieve references to them by absolute position in that sequence.

In F#, the tuple is a fully supported data type and perhaps one of the most useful.  To define a tuple is to define a number of expressions grouped together with comma separation to form a new expression such as the following:

#light

// val blogger : string * string
let blogger1 = "Matthew", "Podwysocki"
let blogger2 = "Jeremy", "Miller"
let blogger3 = "David", "Laribee"

// val bloggers :
// (string * string) * (string * string) * (string * string)
let bloggers = blogger1, blogger2, blogger3

From there, tuples can be decomposed into their components in either of two ways.  For pair tuples, a tuple with exactly two components, can be deconstructed using the fst and snd functions such as the following:

#light

let pageHitCount = "http://www.codebetter.com/", 25500
let page = fst pageHitCount
let hitCount = snd pageHitCount

However, it is more common to use a pattern expression to retrieve values from a tuple, such as the following code:

#light

let request = 
"http://codebetter", 
new DateTime(2008, 11, 15),
"Firefox/3.0.4 (.NET CLR 3.5.30729)"

let host, date, userAgent = request

What we’re able to do is break down the given request into three pieces, the host, date and user-agent.  This makes pattern matching against tuples really powerful such as the following:

#light

// val permit_request : string * string * int -> bool
let permit_request = function
| "http", "google.com", 80 -> true
| _, "microsoft.com", _ -> true
| "ftp", _, 21 -> true
| _ -> false

Just as well, we could even use them in active patterns so that we could pattern match against parts of a FileVersionInfo in order to determine which action to take such as the following.

#light

open System.Diagnostics

let (|FileVersionSections|) (f:FileVersionInfo) = 
(f.FileName,f.ProductName,f.ProductVersion)
let parse_files = function
| FileVersionSections(fn, "Parallel Extensions for the .NET Framework", _)
-> printfn "Parallel Extensions file %s" fn
| FileVersionSections(fn, "Microsoft Office Communicator 2007", _)
-> printfn "Communicator file %s" fn
| _ -> printfn "Unknown file"

You’re saying, great, but what has this to do with .NET 4.0?

Tuples in .NET 4.0

Earlier this month, Justin Van Patten, on the BCL Team Blog announced some the base class library changes coming to .NET 4.0.  Among them was Tuples in which was stated:

We are providing common tuple types in the BCL to facilitate language interoperability and to reduce duplication in the framework.  A tuple is a simple generic data structure that holds an ordered set of items of heterogeneous types.  Tuples are supported natively in languages such as F# and IronPython, but are also easy to use from any .NET language such as C# and VB.

What does that mean exactly?  Does this mean we’ll get some form of syntactic sugar around them as well?  If we could decompose them in such a fashion as we do in F#, and to initialize them in an easy fashion without a lot of pomp and circumstance.  Gazing from the intent in the .NET libraries, something like this might be an option:

var t1 = Tuple.Create(1, ‘a’); 
var i1 = t1.Item1; 
var i2 = t1.Item2;

But, unless there were a nicer way to tease apart the data, it just becomes a simple holder of data, instead of something that we could decompose easily into patterns.  I would love to some sort of syntactic sugar in C# to allow for this to happen.  I am, however, encouraged that they are working with the F# team and other teams to ensure compatibility between the libraries.

If you open Reflector, you will find the type definitions in mscorlib.dll version 4.0 under the System namespace.  You may also be surprised to find them as internal classes only at this point, which is unfortunate and we find ourselves not able to take advantage of these things such as the CodeContracts and BigInteger/BigNumber in the .NET 3.5 libraries.

 

As you can see from the above screen catpure, we have up to 7 arguments for a given tuple and the rest as defined by another tuple.  I, however, haven’t seen tuples quite that large before, but it’s always possible…

The Zip Operator Function

Another functional programming item that has been added to the System.Linq.Enumerable class in System.Core.dll.  This method allows us to combine two collections together using a function to calculate the new element given the element from each collection. 

In F#, we have two ways of doing this in F# in the Seq module.  They are defined as:

val map2 : (‘a -> ‘b -> ‘c) -> seq<’a> -> seq<’b> -> seq<’c>
val zip : seq<’a> -> seq<’b> -> seq<’a * ‘b>

The map2 function takes a function which takes the two items from the list to produce the calculated item, and two collections and returns a new collection of the computed items.  If one collection is shorter than the other, the rest of the computations are not completed.  The zip function is a simple function which takes the items from the first and second collection and combines them in a tuple.

An example of each follows:

// Map2
let l1 = seq[1 .. 26]
let l2 = seq['a' .. 'z']
let mapped = Seq.map2 
(fun a b -> sprintf "%d%c" a b) l1 l2

// Zip
let z1 = seq['a' .. 'z']
let z2 = seq['A' .. 'Z']
let zipped = Seq.zip z1 z2

Now, to use the C# version is rather simple.  The signature of this method is simply:

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first, 
  IEnumerable<TSecond> second, 
  Func<TFirst, TSecond, TResult> func)

As you can see, this follows the same exact pattern as the map2 function from F#, which allows us to compose the two items together via a function to compute the hew item.  Let’s define a few tests that will pass given our knowledge of the Zip function.  We can also include the Tuple class, well, at least the F# version to show that behavior as well.  These are basically tests that I wrote for my Functional C# library, but I hadn’t published my tests, and I probably should. 

[Fact]
public void ZipWithAdding_ShouldAddRanges()
{
// Arrange
var range1 = Enumerable.Range(1, 10);
var range2 = Enumerable.Range(11, 10);

// Act
var range3 = range1.Zip(range2, (i, j) => i + j);

// Assert
    Assert.True(range3.Count() == 10);
    Assert.True(range3.ElementAt(0) == 12);
    Assert.True(range3.ElementAt(9) == 30);
}

[Fact]
public void ZipWithIntAndChar_ShouldCombine()
{
// Arrange
var range1 = Enumerable.Range(1, 5);
var range2 = new[] { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ };

// Act
var range3 = range1.Zip(range2, (i, j) => i + j.ToString());

// Assert
    Assert.True(range3.Count() == 5);
    Assert.True(range3.ElementAt(0) == "1a");
    Assert.True(range3.ElementAt(4) == "5e");
}

[Fact]
public void ZipWithTuples_ShouldCombineLists()
{
// Arrange
var range1 = Enumerable.Range(1, 5);
var range2 = new[] { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ };

// Act
var range3 = range1.Zip(range2, (i, j) => new Tuple<int, char>(i, j));

// Assert
    Assert.True(range3.Count() == 5);
    Assert.True(range3.ElementAt(0).CompareTo(
new Tuple<int, char>(1, ‘a’)) == 0);
    Assert.True(range3.ElementAt(4).CompareTo(
new Tuple<int, char>(5, ‘e’)) == 0);
}

Because the Parallel Extensions for .NET are becoming part of the BCL in .NET 4.0, the ParallelEnumerable also has the Zip method as well, which allows us to take advantage of data parallelism, should our machine allow such as this:

[Fact]
public void ParallelZipWithAdding_ShouldAddRanges()
{
// Arrange
var range1 = ParallelEnumerable.Range(1, 10);
var range2 = ParallelEnumerable.Range(11, 10);

// Act
var range3 = range1.Zip(range2, (i, j) => i + j);

// Assert
    Assert.True(range3.Count() == 10);
    Assert.True(range3.ElementAt(0) == 12);
    Assert.True(range3.ElementAt(9) == 30);
}

With the including of the Parallel Extensions for .NET, it’s going to be a lot of more functional fun built-into the BCL.  I can only hope for more of this coming down the road.

Wrapping It Up

Although the .NET Framework 4.0 release didn’t give too many items for functional programming as they had in the .NET 3.5 release, the .NET 4.0 Framework has a few interesting items with the inclusion of the Tuple and Zip method.  Even more intrigue of course comes from adding the Parallel Extensions for the .NET Framework to the base class library as a first-class citizen. 

I’d wish they would have made the Tuple class public already so that we could at least play around with some of those features, but I as many understand why some of the decisions were made, and I also realize it’s early in the cycle still.  Hopefully in the next release or so, it will become available to us to use, including some syntactic sugar about their creation and decomposition, but ultimately, that’s a language decision and not necessarily a framework decision. 

It’s great to see a language convergence in terms of libraries now being available to all.  F# will continue to be my language of choice, but with C# gaining some of these libraries, it makes the transition switch much easier without having to reinvent the wheel with either re-implementing the feature or converting Func delegates to F# FastFunc types and back again.

This entry was posted in C#, F#, Functional Programming. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

← .NET Code Contracts and TDD Are Complementary

DC ALT.NET 11/25 – Web Testing Frameworks →

  • rsenna

    Perhaps I got it wrong.

    But your C# *Zip* method represents an implementation of F# *map2* function, right? I’m trying to learn F#, so that got me confused.

    Anyway, the zip function may be seen as a special case of map2…

  • http://podwysocki.codebetter.com/ Matthew.Podwysocki

    @rsenna

    That is correct, the Zip is an implementation of the map2 function.

    Matt

  • http://smellegantcode.wordpress.com/ Daniel Earwicker

    Where you wrote:

    var range3 = range1.Zip(range2, (i, j) => new Tuple(i, j));

    You can actually just put:

    var range3 = range1.Zip(range2, Tuple.Create);

    This is because there’s a static non-generic helper class with generic overloads of Create (for up to 8 args). Neat!

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Daniel,

    You are correct, but this wasn’t there at the time this post was done.

posted @ 2011-07-28 21:21 海天一鸥 阅读(114) 评论(1) 编辑

binary search of an integer array

二分法查找

   1:  // binary search of an integer array, this search is efficient for large arrays
   2:  // tested with PellesC       vegaseat     24jan2005
   3:   
   4:  #include <stdio.h>
   5:   
   6:  int main()
   7:  {
   8:    int a[20] = {0}; 
   9:    int n, i, j, temp;
  10:    int *beg, *end, *mid, target;
  11:    
  12:    printf(" enter the total integers you want to enter (make it less then 20):\n");
  13:    scanf("%d", &n);
  14:    if (n >= 20) return 0;   // ouch!
  15:    printf(" enter the integer array elements:\n" );
  16:    for(i = 0; i < n; i++)
  17:    {
  18:      scanf("%d", &a[i]);
  19:    }
  20:      
  21:    // sort the loaded array, a must for binary search! 
  22:    // you can apply qsort or other algorithms here
  23:    for(i = 0; i < n-1; i++)
  24:    {  
  25:      for(j = 0; j < n-i-1; j++)
  26:      {
  27:        if (a[j+1] < a[j])
  28:        {
  29:          temp = a[j];
  30:          a[j] = a[j+1];
  31:          a[j+1] = temp;
  32:        }
  33:      }
  34:    }
  35:    printf(" the sorted numbers are:");
  36:    for(i = 0; i < n; i++)
  37:    {
  38:      printf("%d ", a[i]);
  39:    }
  40:      
  41:    // point to beginning and end of the array
  42:    beg = &a[0];
  43:    end = &a[n];  // use n = one element past the loaded array!
  44:    printf("\n beg points to address %d and end to %d",beg, end);  // test
  45:   
  46:    // mid should point somewhere in the middle of these addresses
  47:    mid = beg += n/2;
  48:    printf("\n mid points to address %d", mid);  // test
  49:    
  50:    printf("\n enter the number to be searched:");
  51:    scanf("%d",&target);
  52:    
  53:    // binary search, there is an AND in the middle of while()!!!
  54:    while((beg <= end) && (*mid != target))
  55:    {
  56:      // is the target in lower or upper half?
  57:        if (target < *mid)
  58:        {
  59:        end = mid - 1;     // new end
  60:        n = n/2;
  61:        mid = beg += n/2;  // new middle
  62:      }
  63:      else
  64:      {
  65:        beg = mid + 1;     // new beginning
  66:        n = n/2;
  67:        mid = beg += n/2;  // new middle      
  68:      }
  69:    }
  70:    
  71:    // did you find the target?
  72:    if (*mid == target)
  73:    {
  74:      printf("\n %d found!", target);
  75:    }
  76:    else
  77:    {
  78:      printf("\n %d not found!", target);
  79:    }
  80:    
  81:    getchar();  // trap enter
  82:    getchar();  // wait
  83:    return 0;
  84:  }
  85:   

posted @ 2011-07-28 21:20 海天一鸥 阅读(47) 评论(1) 编辑

JAVA 上加密算法的实现用例

MD5/SHA1,DSA,DESede/DES,Diffie-Hellman 的使用

第 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.1\lib 下的所有内容复制到 %java_home%\lib\ext 下 , 如果没有 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(); 
    
  2. 用他私人密钥 (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(); 
    把他的公钥的信息及签名发给其它用户
    
  3. 其他用户用他的公共密钥 (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); 
      
  4. 常用 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 章小结

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

posted @ 2011-07-28 21:19 海天一鸥 阅读(68) 评论(1) 编辑

2011年7月8日 #

Exploring The Major Interfaces in Rx

摘要: 本文描述了主要的Reactive Extensions (Rx)接口,其用于表示observable序列,并subscribe它们。 IObservable<T>/IObserver<T>在.NET ...阅读全文

posted @ 2011-07-08 14:09 海天一鸥 阅读(57) 评论(0) 编辑