2008年11月26日星期三

现代密码学的一些基础理论

本文简要地介绍了现代密码学的一些基础理论,供参考。

  1 加密技术概述

  一个密码系统的安全性只在于密钥的保密性,而不在算法的保密性。

  对纯数据的加密的确是这样。对于你不愿意让他看到这些数据(数据的明文)的人,用可靠的加密算法,只要破解者不知道被加密数据的密码,他就不可解读这些数据。

  但是,软件的加密不同于数据的加密,它只能是“隐藏”。不管你愿意不愿意让他(合法用户,或 Cracker)看见这些数据(软件的明文),软件最终总要在机器上运行,对机器,它就必须是明文。既然机器可以“看见”这些明文,那么 Cracker,通过一些技术,也可以看到这些明文。

  于是,从理论上,任何软件加密技术都可以破解。只是破解的难度不同而已。有的要让最高明的 Cracker 忙上几个月,有的可能不费吹灰之力,就被破解了。

  所以,反盗版的任务(技术上的反盗版,而非行政上的反盗版)就是增加 Cracker 的破解难度。让他们花费在破解软件上的成本,比他破解这个软件的获利还要高。这样 Cracker 的破解变得毫无意义——谁会花比正版软件更多的钱去买盗版软件 ?

  2 密码学简介

  2.1 概念

  (1) 发送者和接收者

  假设发送者想发送消息给接收者,且想安全地发送信息:她想确信偷听者不能阅读发送的消息。

  (2) 消息和加密

  消息被称为明文。用某种方法伪装消息以隐藏它的内容的过程称为加密,加了密的消息称为密文,而把密文转变为明文的过程称为解密。

  明文用M(消息)或P(明文)表示,它可能是比特流(文本文件、位图、数字化的语音流或数字化的视频图像)。至于涉及到计算机,P是简单的二进制数据。明文可被传送或存储,无论在哪种情况,M指待加密的消息。

  密文用C表示,它也是二进制数据,有时和M一样大,有时稍大(通过压缩和加密的结合,C有可能比P小些。然而,单单加密通常达不到这一点)。加密函数E作用于M得到密文C,用数学表示为:

  E(M)=C.

  相反地,解密函数D作用于C产生M

  D(C)=M.

  先加密后再解密消息,原始的明文将恢复出来,下面的等式必须成立:

  D(E(M))=M

  (3) 鉴别、完整性和抗抵赖

  除了提供机密性外,密码学通常有其它的作用:.

  (a) 鉴别

  消息的接收者应该能够确认消息的来源;入侵者不可能伪装成他人。

  (b) 完整性检验

  消息的接收者应该能够验证在传送过程中消息没有被修改;入侵者不可能用假消息代替合法消息。

  (c) 抗抵赖

  发送者事后不可能虚假地否认他发送的消息。

  (4) 算法和密钥

  密码算法也叫密码,是用于加密和解密的数学函数。(通常情况下,有两个相关的函数:一个用作加密,另一个用作解密)

  如果算法的保密性是基于保持算法的秘密,这种算法称为受限制的算法。受限制的算法具有历史意义,但按现在的标准,它们的保密性已远远不够。大的或经常变换的用户组织不能使用它们,因为每有一个用户离开这个组织,其它的用户就必须改换另外不同的算法。如果有人无意暴露了这个秘密,所有人都必须改变他们的算法。

  更糟的是,受限制的密码算法不可能进行质量控制或标准化。每个用户组织必须有他们自己的唯一算法。这样的组织不可能采用流行的硬件或软件产品。但窃听者却可以买到这些流行产品并学习算法,于是用户不得不自己编写算法并予以实现,如果这个组织中没有好的密码学家,那么他们就无法知道他们是否拥有安全的算法。

  尽管有这些主要缺陷,受限制的算法对低密级的应用来说还是很流行的,用户或者没有认识到或者不在乎他们系统中内在的问题。

  现代密码学用密钥解决了这个问题,密钥用K表示。K可以是很多数值里的任意值。密钥K的可能值的范围叫做密钥空间。加密和解密运算都使用这个密钥(即运算都依赖于密钥,并用K作为下标表示),这样,加/解密函数现在变成:

  EK(M)=C

  DK(C)=M.

  这些函数具有下面的特性:

  DK(EK(M))=M.

  有些算法使用不同的加密密钥和解密密钥,也就是说加密密钥K1与相应的解密密钥K2不同,在这种情况下:

  EK1(M)=C

  DK2(C)=M

  DK2 (EK1(M))=M

  所有这些算法的安全性都基于密钥的安全性;而不是基于算法的细节的安全性。这就意味着算法可以公开,也可以被分析,可以大量生产使用算法的产品,即使偷听者知道你的算法也没有关系;如果他不知道你使用的具体密钥,他就不可能阅读你的消息。

  密码系统由算法、以及所有可能的明文、密文和密钥组成的。

  基于密钥的算法通常有两类:对称算法和公开密钥算法。下面将分别介绍:

  2.2 对称密码算法

  对称算法有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,反过来也成立。在大多数对称算法中,加/解密密钥是相同的。这些算法也叫秘密密钥算法或单密钥算法,它要求发送者和接收者在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都能对消息进行加/解密。只要通信需要保密,密钥就必须保密。

  对称算法的加密和解密表示为:

  EK(M)=C

  DK(C)=M

  对称算法可分为两类。一次只对明文中的单个比特(有时对字节)运算的算法称为序列算法或序列密码。另一类算法是对明文的一组比特亚行运算,这些比特组称为分组,相应的算法称为分组算法或分组密码。现代计算机密码算法的典型分组长度为64比特——这个长度大到足以防止分析破译,但又小到足以方便使用(在计算机出现前,算法普遍地每次只对明文的一个字符运算,可认为是序列密码对字符序列的运算)。

  2.3 公开密码算法

  公开密钥算法(也叫非对称算法)是这样设计的:用作加密的密钥不同于用作解密的密钥,而且解密密钥不能根据加密密钥计算出来(至少在合理假定的长时间内)。之所以叫做公开密钥算法,是因为加密密钥能够公开,即陌生者能用加密密钥加密信息,但只有用相应的解密密钥才能解密信息。在这些系统中,加密密钥叫做公开密钥(简称公钥),解密密钥叫做私人密钥(简称私钥)。私人密钥有时也叫秘密密钥。为了避免与对称算法混淆,此处不用秘密密钥这个名字。

  用公开密钥K加密表示为

  EK(M)=C.

  虽然公开密钥和私人密钥是不同的,但用相应的私人密钥解密可表示为:

  DK(C)=M

  有时消息用私人密钥加密而用公开密钥解密,这用于数字签名(后面将详细介绍),尽管可能产生混淆,但这些运算可分别表示为:

  EK(M)=C

  DK(C)=M

  当前的公开密码算法的速度,比起对称密码算法,要慢的多,这使得公开密码算法在大数据量的加密中应用有限。

  2.4 单向散列函数

  单向散列函数 H(M) 作用于一个任意长度的消息 M,它返回一个固定长度的散列值 h,其中 h 的长度为 m 。

  输入为任意长度且输出为固定长度的函数有很多种,但单向散列函数还有使其单向的其它特性:

  (1) 给定 M ,很容易计算 h ;

  (2) 给定 h ,根据 H(M) = h 计算 M 很难 ;

  (3) 给定 M ,要找到另一个消息 M‘ 并满足 H(M) = H(M’) 很难。

  在许多应用中,仅有单向性是不够的,还需要称之为“抗碰撞”的条件:

  要找出两个随机的消息 M 和 M‘,使 H(M) = H(M’) 满足很难。

  由于散列函数的这些特性,由于公开密码算法的计算速度往往很慢,所以,在一些密码协议中,它可以作为一个消息 M 的摘要,代替原始消息 M,让发送者为 H(M) 签名而不是对 M 签名 。

  如 SHA 散列算法用于数字签名协议 DSA中。

  2.5 数字签名

  提到数字签名就离不开公开密码系统和散列技术。

  有几种公钥算法能用作数字签名。在一些算法中,例如RSA,公钥或者私钥都可用作加密。用你的私钥加密文件,你就拥有安全的数字签名。在其它情况下,如DSA,算法便区分开来了??数字签名算法不能用于加密。这种思想首先由Diffie和Hellman提出 。

  基本协议是简单的 :

  (1) A 用她的私钥对文件加密,从而对文件签名。

  (2) A 将签名的文件传给B。

  (3) B用A的公钥解密文件,从而验证签名。

  这个协议中,只需要证明A的公钥的确是她的。如果B不能完成第(3)步,那么他知道签名是无效的。

  这个协议也满足以下特征:

  (1) 签名是可信的。当B用A的公钥验证信息时,他知道是由A签名的。

  (2) 签名是不可伪造的。只有A知道她的私钥。

  (3) 签名是不可重用的。签名是文件的函数,并且不可能转换成另外的文件。

  (4) 被签名的文件是不可改变的。如果文件有任何改变,文件就不可能用A的公钥验证。

  (5) 签名是不可抵赖的。B不用A的帮助就能验证A的签名。

  在实际应用中,因为公共密码算法的速度太慢,签名者往往是对消息的散列签名而不是对消息本身签名。这样做并不会降低签名的可信性。

  注:本文由计算机专业相关教材整理

2008年11月24日星期一

发誓

2008年11月17日星期一

group by rollup 与 cube

oracle group by rollup 与 cube 语句.很有用的统计




Oracle的GROUP BY语句除了最基本的语法外,还支持ROLLUP和CUBE语句。如果是ROLLUP(A, B, C)的话,首先会对(A、B、C)进行GROUP BY,然后对(A、B)进行GROUP BY,然后是(A)进行GROUP BY,最后对全表进行GROUP BY操作。如果是GROUP BY CUBE(A, B, C),则首先会对(A、B、C)进行GROUP BY,然后依次是(A、B),(A、C),(A),(B、C),(B),(C),最后对全表进行GROUP BY操作。 grouping_id()可以美化效果:


Oracle的GROUP BY语句除了最基本的语法外,还支持ROLLUP和CUBE语句。




除本文内容外,你还可参考:
分析函数参考手册: http://xsb.itpub.net/post/419/33028
分析函数使用例子介绍:http://xsb.itpub.net/post/419/44634

SQL> create table t as select * from dba_indexes;


表已创建。


SQL> select index_type, status, count(*) from t group by index_type, status;


INDEX_TYPE STATUS COUNT(*)
--------------------------- -------- ----------
LOB VALID 51
NORMAL N/A 25
NORMAL VALID 479
CLUSTER VALID 11


下面来看看ROLLUP和CUBE语句的执行结果。


SQL> select index_type, status, count(*) from t group by rollup(index_type, status);


INDEX_TYPE STATUS COUNT(*)
--------------------------- -------- ----------
LOB VALID 51
LOB 51
NORMAL N/A 25
NORMAL VALID 479
NORMAL 504
CLUSTER VALID 11
CLUSTER 11
566


已选择8行。


SQL> select index_type, status, count(*) from t group by cube(index_type, status);


INDEX_TYPE STATUS COUNT(*)
--------------------------- -------- ----------
566
N/A 25
VALID 541
LOB 51
LOB VALID 51
NORMAL 504
NORMAL N/A 25
NORMAL VALID 479
CLUSTER 11
CLUSTER VALID 11


已选择10行。


查询结果不是很一目了然,下面通过Oracle提供的函数GROUPING来整理一下查询结果。


SQL> select grouping(index_type) g_ind, grouping(status) g_st, index_type, status, count(*)
2 from t group by rollup(index_type, status) order by 1, 2;


G_IND G_ST INDEX_TYPE STATUS COUNT(*)
---------- ---------- --------------------------- -------- ----------
0 0 LOB VALID 51
0 0 NORMAL N/A 25
0 0 NORMAL VALID 479
0 0 CLUSTER VALID 11
0 1 LOB 51
0 1 NORMAL 504
0 1 CLUSTER 11
1 1 566


已选择8行。


这个查询结果就直观多了,和不带ROLLUP语句的GROUP BY相比,ROLLUP增加了对INDEX_TYPE的GROUP BY统计和对所有记录的GROUP BY统计。


也就是说,如果是ROLLUP(A, B, C)的话,首先会对(A、B、C)进行GROUP BY,然后对(A、B)进行GROUP BY,然后是(A)进行GROUP BY,最后对全表进行GROUP BY操作。


下面看看CUBE语句。


SQL> select grouping(index_type) g_ind, grouping(status) g_st, index_type, status, count(*)
2 from t group by cube(index_type, status) order by 1, 2;


G_IND G_ST INDEX_TYPE STATUS COUNT(*)
---------- ---------- --------------------------- -------- ----------
0 0 LOB VALID 51
0 0 NORMAL N/A 25
0 0 NORMAL VALID 479
0 0 CLUSTER VALID 11
0 1 LOB 51
0 1 NORMAL 504
0 1 CLUSTER 11
1 0 N/A 25
1 0 VALID 541
1 1 566


已选择10行。


和ROLLUP相比,CUBE又增加了对STATUS列的GROUP BY统计。


如果是GROUP BY CUBE(A, B, C),则首先会对(A、B、C)进行GROUP BY,然后依次是(A、B),(A、C),(A),(B、C),(B),(C),最后对全表进行GROUP BY操作。


除了使用GROUPING函数,还可以使用GROUPING_ID来标识GROUP BY结果。


SQL> select grouping_id(index_type, status) g_ind, index_type, status, count(*)
2 from t group by rollup(index_type, status) order by 1;


G_IND INDEX_TYPE STATUS COUNT(*)
---------- --------------------------- -------- ----------
0 LOB VALID 51
0 NORMAL N/A 25
0 NORMAL VALID 479
0 CLUSTER VALID 11
1 LOB 51
1 NORMAL 504
1 CLUSTER 11
3 566


已选择8行。


SQL> select grouping_id(index_type, status) g_ind, index_type, status, count(*)
2 from t group by cube(index_type, status) order by 1;


G_IND INDEX_TYPE STATUS COUNT(*)
---------- --------------------------- -------- ----------
0 LOB VALID 51
0 NORMAL N/A 25
0 NORMAL VALID 479
0 CLUSTER VALID 11
1 LOB 51
1 NORMAL 504
1 CLUSTER 11
2 N/A 25
2 VALID 541
3 566


已选择10行。

grouping_id()可以美化效果:

select DECODE(GROUPING_ID(C1), 1, '合计', C1) D1,
DECODE(GROUPING_ID(C1, C2), 1, '小计', C2) D2,
DECODE(GROUPING_ID(C1, C2, C1 + C2), 1, '小计', C1 + C2) D3,
count(*),
GROUPING_ID(C1, C2, C1 + C2, C1 + 1, C2 + 1),
GROUPING_ID(C1)
from T2
group by rollup(C1, C2, C1 + C2, C1 + 1, C2 + 1);

===========================================================

1.报表合计专用的Rollup函数

销售报表

广州 1月 2000元

广州 2月 2500元

广州 4500元

深圳 1月 1000元

深圳 2月 2000元

深圳 3000元

所有地区 7500元



以往的查询SQL:

Select area,month,sum(money) from SaleOrder group by area,month

然后广州,深圳的合计和所有地区合计都需要在程序里自行累计


1.其实可以使用如下SQL:

Select area,month,sum(total_sale) from SaleOrder group by rollup(area,month)

就能产生和报表一模一样的纪录


2.如果year不想累加,可以写成

Select year,month,area,sum(total_sale) from SaleOrder group by year, rollup(month,area)

另外Oracle 9i还支持如下语法:

Select year,month,area,sum(total_sale) from SaleOrder group by rollup((year,month),area)


3.如果使用Cube(area,month)而不是RollUp(area,month),除了获得每个地区的合计之外,还将获得每个月份的合计,在报表最后显示。


4.Grouping让合计列更好读

RollUp在显示广州合计时,月份列为NULL,但更好的做法应该是显示为"所有月份"

Grouping就是用来判断当前Column是否是一个合计列,1为yes,然后用Decode把它转为"所有月份"

Select Decode(Grouping(area),1,'所有地区',area) area, Decode(Grouping(month),1,'所有月份',month), sum(money) From SaleOrder Group by RollUp(area,month);


2.对多级层次查询的start with.....connect by

比如人员组织,产品类别,Oracle提供了很经典的方法

SELECT LEVEL, name, emp_id,manager_emp_id FROM employee START WITH manager_emp_id is null CONNECT BY PRIOR emp_id = manager_emp_id;

上面的语句demo了全部的应用,start with指明从哪里开始遍历树,如果从根开始,那么它的manager应该是Null,如果从某个职员开始,可以写成emp_id='11'

CONNECT BY 就是指明父子关系,注意PRIOR位置

另外还有一个LEVEL列,显示节点的层次


3.更多报表/分析决策功能

3.1 分析功能的基本结构

分析功能() over( partion子句,order by子句,窗口子句)

概念上很难讲清楚,还是用例子说话比较好.


3.2 Row_Number 和 Rank, DENSE_Rank

用于选出Top 3 sales这样的报表

当两个业务员可能有相同业绩时,就要使用Rank和Dense_Rank

比如

金额 RowNum Rank Dense_Rank

张三 4000元 1 1 1

李四 3000元 2 2 2

钱五 2000元 3 3 3

孙六 2000元 4 3 3

丁七 1000元 5 5 4

这时,应该把并列第三的钱五和孙六都选进去,所以用Ranking功能比RowNumber保险.至于Desnse还是Ranking就看具体情况了。

SELECT salesperson_id, SUM(tot_sales) sp_sales, RANK( ) OVER (ORDER BY SUM(tot_sales) DESC) sales_rank FROM orders GROUP BY salesperson_id

3.3 NTILE 把纪录平分成甲乙丙丁四等

比如我想取得前25%的纪录,或者把25%的纪录当作同一个level平等对待,把另25%当作另一个Level平等对待

SELECT cust_nbr, SUM(tot_sales) cust_sales, NTILE(4) OVER (ORDER BY SUM(tot_sales) DESC) sales_quartile FROM orders GROUP BY cust_nbr ORDER BY 3,2 DESC;

NTITLE(4)把纪录以 SUM(tot_sales)排序分成4份.


3.4 辅助分析列和Windows Function

报表除了基本事实数据外,总希望旁边多些全年总销量,到目前为止的累计销量,前后三个月的平均销量这样的列来参考.

这种前后三个月的平均和到目前为止的累计销量就叫windows function, 见下例

SELECT month, SUM(tot_sales) monthly_sales, SUM(SUM(tot_sales)) OVER (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_preceeding FROM orders GROUP BY month ORDER BY month;

SELECT month, SUM(tot_sales) monthly_sales, AVG(SUM(tot_sales)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) rolling_avg FROM orders GROUP BY month ORDER BY month;

Windows Function的关键就是Windows子句的几个取值

1 PRECEDING 之前的一条记录

1 FOLLOWING 之后的一条记录

UNBOUNDED PRECEDING 之前的所有记录

CURRENT ROW 当前纪录


4.SubQuery总结

SubQuery天天用了,理论上总结一下.SubQuery 分三种

1.Noncorrelated 子查询 最普通的样式.

2.Correlated Subqueries 把父查询的列拉到子查询里面去,头一回cyt教我的时候理解了半天.

3.Inline View 也被当成最普通的样式用了.


然后Noncorrelated 子查询又有三种情况

1.返回一行一列 where price < (select max(price) from goods )

2.返回多行一列 where price>= ALL (select price from goods where type=2)

or where NOT price< ANY(select price from goods where type=2)

最常用的IN其实就是=ANY()

3.返回多行多列 一次返回多列当然就节省了查询时间

UPDATE monthly_orders SET (tot_orders, max_order_amt) = (SELECT COUNT(*), MAX(sale_price) FROM cust_order) DELETE FROM line_item WHERE (order_nbr, part_nbr) IN (SELECT order_nbr, part_nbr FROM cust_order c)

========================================
/*--------理解grouping sets
select a, b, c, sum( d ) from t
group by grouping sets ( a, b, c )

等效于

select * from (
select a, null, null, sum( d ) from t group by a
union all
select null, b, null, sum( d ) from t group by b
union all
select null, null, c, sum( d ) from t group by c
)
*/

2008年11月11日星期二

午睡醒来

每次醒来,心里都有一种说不出的痛处.一种必须面对事实的心情.

2008年11月10日星期一

时间过得真快啊

一晃一年就过去了,去年此时的事情,我还记得清清楚楚。

这就是生活。。。。。。。。。。。。。

路还要继续走下去,只是方向。。。。。。。。。

2008年11月9日星期日

SQL 联表更新

表A(A1,A2,A3),表B(B1,B2,B3)
任务:当A3=B3时,更新A中A1,A2字段的内容为B1,B2


实例:
update A o
set (o.A1, o.A2) = (select r.B1, r.B2 from B r where o.A3 = r.B3)
where o.A3 in (select r.B3 from B r);

2008年11月6日星期四

贴一个自认有点取巧的,关键是理解逻辑啊.

--add by xieh 2008-11-07

create or replace function FUNC_GET_ONLINETIME(
p_starttime in date, --开始时间,以半小是为步长
p_workno in number --工号
)
return number is
Result number; --半小时的在线时间(签入时间)
v_number1 number;--半小时内签出工作时间之和
v_number2 number;--半小时内未签出工作时间之和
begin
begin
select sum((endtime-begintime)*24*60*60) into v_number1 from(
select
case when t.actbegin<=p_starttime then p_starttime
else t.actbegin end as begintime, --实际开始时间
case when t.actend>=p_starttime+1/48 then p_starttime+1/48
else t.actend end as endtime --实际结束时间
from tagentoprinfo t
where t.agentid=p_workno
and t.operatetype=0
and t.actbegin < p_starttime+1/48--落在区间的记录
and t.actend >p_starttime--落在区间的记录
);
exception
when no_data_found then
v_number1 := 0;
end;

begin
select sum((endtime-begintime)*24*60*60) into v_number2 from
(
select
case when t1.actbegin<= p_starttime then p_starttime
else t1.actbegin end as begintime, --实际开始时间
p_starttime+1/48 as endtime --实际结束时间
from tagentoprinfo t1
where t1.agentid=p_workno
and t1.operatetype=1
and t1.actbegin < p_starttime+1/48 --落在区间的记录
and t1.actend > trunc(p_starttime,'dd')-2
and t1.actend < trunc(p_starttime,'dd')+2 --缩小查询范围,不会工作四天吧.
and rownum=1--应该只有一条才正常
);
exception
when no_data_found then
v_number2 := 0;
end;
if v_number1 is null then
v_number1 := 0;
end if;

if v_number2 is null then
v_number2 := 0;
end if;
Result := round((v_number1 + v_number2),0);
return(Result);

exception
when others then
Result := -1;
return(Result);
end FUNC_GET_ONLINETIME;

2008年11月5日星期三

TortoiseCVS

转牛人好人写的
TortoiseCVS是Windows平台上最最简单最最方便的CVS工具,如果你使用了TortoiseCVS之后,你一定会把WinCVS立刻扔掉。

TortoiseCVS的特点就是完全结合到资源管理器的鼠标右键菜单中进行操作,异常简单和方便,对于任何有过CVS使用经验的人来说,掌握TortoiseCVS不会超过1分钟的时间,那么下面请你花1分钟时间把帖子看完,就已经学会了TortoiseCVS。

Tortorise下载网址:
http://sourceforge.net/projects/tortoisecvs/
使用教程可以参考:
http://www.javaeye.com/a/104.html
http://www.redsaga.com/CVS_newbie_win32/TortoiseCVS.html
上面的教程里面的版本可能稍低,但是不影响学习,因为基本上很快就能学会的~推荐不习惯使用Eclipse里自带的CVS或是没有Eclipse并且讨厌WinCVS不友好的操作界面的朋友使用~

2008年11月3日星期一

oracle job

begin
sys.dbms_job.submit(job => :job,
what => 'PROC_OBS_CDHF_RJ;',
next_date => to_date('05-11-2008 03:00:00', 'dd-mm-yyyy hh24:mi:ss'),
interval => 'trunc(sysdate+1,''dd'')+3/24');
commit;
end;

参数说明:
job 系统自动生成编号;
what 要运行的过程名;
next_date 下次运行时间;
interval 设置时间间隔,多久执行一次;我这里是每天3点钟执行。