当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks

#

MD5是消息摘要算法的一种,它和SHA,HMAC是消息摘要算法的主要代表,其前身有MD2,MD3,MD4算法。
消息摘要算法又称为散列算法,其不可破解的核心在于散列函数的单向性,即可以通过散列函数得到结果,却不可能通过结果反推出其原始信息。这是消息摘要算法的安全性根本所在。如果用户输入的密码是123456789,则会得到25f9e794323b453885f5181f1b624d0这样的结果;如果有人拿到25f9e794323b453885f5181f1b624d0这样的结果,他是不可能反推出密码123456789的。
但是,总所周知的是,MD5已经被我国山东大学王小云教授攻破了。他是怎么做到这不可能的事呢?当然不是反推,而是使用的碰撞算法,具体来说就是,拿到25f9e794323b453885f5181f1b624d0这样的结果,用多种精心设计的字符串去试试,总有一个字符串经MD5加密后能得到25f9e794323b453885f5181f1b624d0这样的结果,这个字符串也许是真实密码,也是是别的,但它加密后可以得到和123456789加密后一样的效果。这就意味着,你给自己设定的密码,别人通过其他密码也可能通过验证!
其原因还是在于散列函数,不同的输入通过散列函数可能得到同一结果,虽然这个可能性较小。王教授成果的意义在于,以前号称用全世界所有计算机算一百年不能做到的,用他的办法用一台普通微机在数个小时内就能做到。这个很了不起,诸位如果有意可以去当他的研究生,这样就知道是怎么做的了。
那么,MD5还有存在的价值吗。当然有,因为破解者要破解成功有三个必要条件,一,知道算法;二,知道密钥;三,有大量数据供测试。如果把几种其它算法和MD5混合,破解者就容易困惑,再加上时间限制,破解也不是件容易的事。最后,还有理论上不可能破解的量子密码,如果它能实用化,则能达到真正意义上的不可破解。


posted @ 2010-12-08 18:58 何杨 阅读(408) | 评论 (2)编辑 收藏

密码学的加密算法可分为 单向加密算法,对称加密算法和非对称加密算法三类。
  • 单向加密算法是数据完整性验证的常用算法,MD5SHA是单向加密算法的代表;
  • 对称加密算法是数据存储加密的常用算法,DESAES是对称加密算法的代表;
  • 非对称加密算法是数据传输加密的常用算法,RSA是非对称加密算法的代表。对称加密算法也可以用作数据传输加密,但非对称加密算法在密钥管理方面更有优势,在安全级别上更高,只是时间效率上不如对称加密算法。

JAVA API对密码学的支持
  • MessageDigest类,可以构建MD5,SHA两种加密算法;
  • Mac类可以构建HMAC加密算法;
  • Cipher类可以构建多种加密算法,如DES,AES,RSA,DSA,DH等;
  • Signature类可用于数字签名和签名验证;
  • Certificate类可用于操作证书。

posted @ 2010-12-05 14:24 何杨 阅读(216) | 评论 (0)编辑 收藏

本版新增功能:
1.增加对DB2数据库的支持。
2.过滤器不区分大小写。
3.取消了欢迎窗口。

下载地址:
http://www.box.net/shared/0flunl0zul

Softonic下载页面:
http://sqltoolbox.softonic.cn/

概述

SqlToolBox是一款纯绿色的免费数据库客户端软件,基于Java Swing编制而成,旨在于为开发人员,系统工程师和数据库管理员提供一种通用方便和快捷的数据库操作工具,使他们摆脱需要学习掌握使用多种数据库客户端 的苦恼,并减轻他们日常操作数据库和编写Sql语句的任务量,帮助他们把精力投入到解决更有意义的问题上去。

SqlToolBox现有功能

  1. 能连接到MySql,Oracle,Ms Sql Server和DB2四种数据库。
  2. 连接到数据库后,会提供数据库Schema和表的树视图以便用户进行浏览和查找,另外还提供了一个过滤器帮助用户缩小查找范围。
  3. 用户能自动快速获取单表的创建,查询,更新,删除,建表语句,整表全部数据插入语句,单表对应Pojo类和单表的Hibernate映射文件等常用文字,且可借此构造更复杂的Sql语句。
  4. 能执行Sql语句并显示执行结果,如果是查询语句会以表格形式显示结果,还提供CSV形式数据下载;如果是非查询语句或是错误的查询语句则会以文字形式告知用户。
  5. 在用户输入Sql语句的过程中提供Sql语法高亮功能,以助于Sql语句的识别。
  6. 提供Sql格式化功能以助于Sql语句的识别和整理。
  7. 提供Redo/Undo,Shift整体退格进格,大小写转化,将Sql语句用StringBuilder包容以及将Sql语句中关键字大写表示等常用文字编辑功能。这些都能帮助程序员在程序中书写Sql语句。
  8. 能保存和记忆数据库信息,以便下次打开。

运行SqlToolBox有何前提条件?

将SqlToolBox运行起来的唯一前提是安装JDK6或以上版本。

SqlToolBox需要安装吗?

SqlToolBox是一款纯绿色软件,它对您的系统不做出任何更改,因此不需要安装和卸载。

SqlToolBox安全吗?

由于软件使用Java编写而成,它本身就具有较高的安全性。此外作者保证在SqlToolBox整个系列中都不会加入病毒,木马,插件等坏东西。

如何运行SqlToolBox?

解开下载包,然后双击run.bat即可。

在Unix/Linux下如何运行SqlToolBox?

除了也需要安装JDK外,您还需要参照run.bat写一份脚本,然后执行它。

如何使用SqlToolBox打开一个数据库?

程序运行起来后,您将看到一个输入数据库信息的对话框,请依次填入数据库所在机器的IP地址,数据库的库名称,选择数据库的类型以及输入登录数据库的用户 名和密码等必要信息。此后再点击“连接数据库”按钮,程序将打开数据库。如果您将以上信息填错也不要紧,程序会提示哪里出现了问题。此外您可以在登录前点 击“测试连接”按钮,程序也会告诉您是否能连接到指定的数据库。

打开数据库后程序左边部分如何使用?

成功连接到数据库以后,数据库的Schema和table结构会在画面的左边以树的形式展现出来,如果展现的内容过多,您还可以在上方的“过滤器”输入栏 中输入关键字以缩小展现范围。在这颗树中,表格(table)是以小圆点的方式展现的,左键点击这个圆点,程序将在右侧打开一个Sql语句操作窗口,并执 行“select * from table”语句,最后在下方以表格的形式展现给您;如果您用右键点击这个圆点,程序将弹出一个右键菜单,选择其中的项目您将可以在右边的Sql语句操作 窗口中得到单表的字段信息,创建(insert),查询(select),更新(update),删除语句(delete)及建表语句(create table),单表对应Pojo文件,单表的Hibernate映射文件等文字。

打开数据库后程序右边部分是如何使用的?

用左右键点击表格后,您将在右侧看到一个“Sql语句操作窗口”,它分成三部分:工具栏菜单,输入窗口和输出窗口。输入窗口是用以输入,编辑和整理Sql 语句的;工具栏菜单中的一大排按钮都是为编辑处理输入窗口中的文字而准备的;输出窗口则是展示Sql语句执行后的结果的,如果是查询语句,它会以表格的形 式告知您查询的结果,如果是其它语句,它会以文字的形式告知。通常的操作手法是,先在输入窗口中用鼠标选中您要操作的文本,再在工具栏菜单中点击执行特定 操作的按钮,然后在下方的输出窗口中就能看到具体的结果,当然如果仅是文本编辑操作的话输出窗口是不会有反应的。

如何执行Sql语句?

程序员和数据库管理员总是习惯使用语句来操作数据库,这也是本软件的最重要功能之一。执行Sql语句的过程具体来说是这样做的,首先,在输入窗口输入您向 执行的Sql语句,如“select * from table”之类,当然您更可以通过表格的右键菜单来获得常用的sql语句(在输入或是粘贴文本的过程中,Sql语句中的关键字会以蓝色显示,这是语法高 亮功能所致);其次,你需要选中你想执行的文本,再点击工具栏菜单中的向右三角形按钮,这段文本将得到执行,执行结果将在下方的输出窗口得到展示。如果您 执行的是查询语句,输出窗口将以表格的形式列出查询结果集的字段和内容;如果您执行的是删除,更新,添加,修改表等语句或是执行错误的Sql文本,输出窗 口将以文本形式告知执行结果。另外工具栏菜单中的双向右三角形按钮用于批量执行Sql语句,它以分号“;”来作为每段Sql的分隔标志,然后分别执行每 段。

如何快速调整对执行查询语句后得到的表格列宽度?

如果您想自动调整某列的宽度,可以双击这列的表头,此后这列的宽度会根据这列的最长文字进行调整;您还可以在表格上点击右键,选择“调整列宽为最适合状态”一项,那么所有的列宽都会进行调整。

如何得到执行查询语句后得到的表格的内容?

您还可以在表格上点击右键,选择“下载表格为CSV文件”一项,此后查询语句和得到的结果都会被放入一个CSV文件中。CSV是一中文本文件,但您可以用Excel打开它,也会得到xls文件一样的效果。

在新增或是删除一张表后,在左边的树中为什么没有相应的变化?

新增或是删除一张表后,您需要手动执行一下左上方的更新按钮(最上方的大图标中第一个),此后程序会重新载入数据库的Schema和table,这样您刚才对表格进行增删操作就能体现出来。

如果我需要常打开数据库进行操作或是需要常操作多个数据库,程序能为我提供那些便利?

本软件有记忆功能,如果您正确连接到一个数据库,那么相应的信息如IP地址,数据库名,数据库类型,连接数据库的用户名和密码都会被记忆下来,这样下次打 开时就不用重复输入了。如果您需要常操作多个数据库,您可以通过保存按钮(最上方五个大图标中的第二个)将数据库信息保存成XML文件,这样在登录画面中 就可以通过“打开文件按钮”得到相应的数据库信息。

如果我有想法和建议,如何与作者联系?

首先,您可以点击程序上方的信封按钮,通过邮件heyang78@gmail.com和我联系,我会乐于回复您的邮件并会认真考虑您提出的想法和建议;其次,您还可以通过QQ和我联系,我的Q号是805985315;其三,我的MSN是junglesong_5@gmail.com,通过MSN也能找到我;最后,欢迎您登录我的博客http://heyang.blogjava.net,如果SqlToolBox有所变化,我会在第一时间在博客上公告。

感谢名单

SqlToolBox的成长离不开以下人士的建议,激励和帮助,在此谨向他们表示诚挚的谢意:
  • danielxu(关于jtds-1.2.2.jar的添加)
  • creasure(关于开源的建议)
  • Always BaNg.(关于语法高亮)
  • mircle(关于提升加载数据库对象的性能)
  • willim2000(他也做了一个类型相同的软件)
  • ytfulz(提供连接SqlServer的连接测试以,改变输出表格形式,调整输出表格列宽的建议)
  • 王宏亮(提供将程序和JRE整体打包的建议)
  • 朱俭(关于帮助窗口只打开一个的建议)
  • ☆振兴中华☆(关于选择数据表的建议)


posted @ 2010-12-03 19:25 何杨 阅读(1220) | 评论 (4)编辑 收藏

安装步骤:
1.到http://sourceforge.jp/projects/amateras/releases/?package_id=4435 去下载 AmaterasUML_1.3.2.zip
2.下载完毕后,解开压缩包,将其中三个jar文件拷贝到你的Eclipse目录的plugins目录下。
3.启动或者重启您的Eclipse。

如何使用:
1.点击Eclipse的菜单"File"--"New"--"Others"。


2.找到Amateras UML一项,选择你要绘制的UML图类型。


3.选择一个要存储UML图文件的文件夹。


4.好了,可以开始画了。



我是在JavaEye看人介绍后装的,用了感觉确实不错,Visio可以见回收站去了。

posted @ 2010-12-02 14:29 何杨 阅读(1698) | 评论 (0)编辑 收藏

按:以下文字涉及RSA对WebService传递的数据的加密解密,如果您已经熟知RSA或是有其它更好的方法请不要往下看以免浪费时间.

WebService采用的协议是SOAP,它基于HTTP,而HTTP是明文方式,也就是说,采用WebService传递的数据是明文的。如果是天气预报这种公开的只读信息的WebService无所谓,如果涉及写入或是和私密数据相关,那么明文传递就有很大的潜在危险性,必须加以遏止。

一般来说有两种方法,一是采用https加密的方式,另一种是用非对称加密算法对数据加密,下文提到的RSA就是第二种。

使用RSA对WebService传递的信息加密解密的基本思想是:服务器端提供一个WebService方法byte[] getServerPublicKey(),客户端可以以此得到服务器端的公钥,然后使用服务器端的公钥对要传出去的数据进行RSA加密,并附带以自己的公钥;服务器端得到客户端的请求后,先用自己的私钥解密客户端送来的数据,得到处理结果后用客户端提供的公钥加密,然后传回;客户端得到服务器端的返回数据后,用自己的私钥进行解密,最终得到了服务器端的真实数据。服务器端和客户端各自保存自己的RSA私钥用于解密,提供给对方RSA公钥进行加密,这样中间传递的信息就安全了。

加密解密示意顺序图:


下面是服务器端实现类的代码:
package com.heyang;


public class ServiceImpl implements IService{
    @Override
    
public byte[] getResonse(byte[] params, byte[] clientPublicKey) {
        
try {
            
// 使用自己的私钥解密客户端用服务器端公钥加密的数据
            String decryptString=SecurityUtil.getCoder().getDecryptString(params);
            
            
// 要返回的结果
            String response="你好!"+decryptString;
            
            
// 使用客户端提供的公钥对返回的数据进行加密
            byte[] retval=SecurityUtil.getCoder().getEncryptArray(response, clientPublicKey);
            
            
return retval;
        } 
catch (Exception e) {
            e.printStackTrace();
            
            
return null;
        }
    }

    @Override
    
public byte[] getServerPublicKey() {
        
return SecurityUtil.getCoder().getPublicKey();
    }
}


客户端调用服务器端的代码:
package com.heyang;

import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;

public class Test {
    
public static void main(String[] args) {
        Service srvcModel 
= new ObjectServiceFactory().create(IService.class);
        XFireProxyFactory factory 
= new XFireProxyFactory(XFireFactory
                .newInstance().getXFire());

        String helloWorldURL 
= "http://localhost:8080/XfireSample/services/hello";
        
try {
            IService srvc 
= (IService) factory.create(srvcModel, helloWorldURL);

            
// 得到服务器端的公钥
            byte[] serverPublicKey=srvc.getServerPublicKey();
            System.out.print(
"从服务器端得到的公钥为:");
            
for(byte b:serverPublicKey){
                System.out.print(b);
            }
            System.out.println();
            
            
            RSASecurityCoder coder
=SecurityUtil.getCoder();
            String requestString
="世界";
            
            
// 使用服务器端的公钥对要传出去的数据进行加密
            byte[] params=coder.getEncryptArray(requestString, serverPublicKey);
            
            
// 得到服务器端的返回结果
            byte[] responseArray=srvc.getResonse(params, coder.getPublicKey());
            
            
// 使用自己的私钥进行解密
            String responseString=coder.getDecryptString(responseArray);
            System.out.println(
"从服务器端返回的字符串结果是:"+responseString);
        } 
catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出的结果为:
从服务器端得到的公钥为:48-127-9748136942-12272-122-913111503-127-115048-127-1192-127-1270-575108-121578675121-687-32-1165359-2586-50-127114-24-6769-17-128115114982868-11550-121-111-69-494021-48-22-5844-37-8645-115-125-984651-344761-117-7875-34115-101-119164666123-4211-13-103-62-30-587926842-12338-32-91-24-75-1177128103-12-71108-121-122112-712-1089753-2691-7863-6385-41-10210782-8784120344-69-90474108-3661-47089-1261812510046-123-3910723101
从服务器端返回的字符串结果是:你好!世界

服务器端和客户端使用的RSA加密解密类代码:
package com.heyang;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA加密解密类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-1 下午06:14:38
 * 修改时间:2010-12-1 下午06:14:38
 
*/
public class RSASecurityCoder{
    
// 非对称加密密钥算法
    private static final String Algorithm="RSA";
    
    
// 密钥长度,用来初始化
    private static final int Key_Size=1024;
    
    
// 公钥
    private final byte[] publicKey;
    
    
// 私钥
    private final byte[] privateKey;
    
    
/**
     * 构造函数,在其中生成公钥和私钥
     * 
@throws Exception
     
*/
    
public RSASecurityCoder() throws Exception{
        
// 得到密钥对生成器
        KeyPairGenerator kpg=KeyPairGenerator.getInstance(Algorithm);
        kpg.initialize(Key_Size);
        
        
// 得到密钥对
        KeyPair kp=kpg.generateKeyPair();
        
        
// 得到公钥
        RSAPublicKey keyPublic=(RSAPublicKey)kp.getPublic();
        publicKey
=keyPublic.getEncoded();
        
        
// 得到私钥
        RSAPrivateKey keyPrivate=(RSAPrivateKey)kp.getPrivate();
        privateKey
=keyPrivate.getEncoded();
    }
    
    
/**
     * 用公钥对字符串进行加密
     * 
     * 说明:
     * 
@param originalString
     * 
@param publicKeyArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:29:51
     
*/
    
public byte[] getEncryptArray(String originalString,byte[] publicKeyArray) throws Exception{
        
// 得到公钥
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyArray);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PublicKey keyPublic
=kf.generatePublic(keySpec);
        
        
// 加密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.ENCRYPT_MODE, keyPublic);
        
return cp.doFinal(originalString.getBytes());
    }
    
    
    
/**
     * 使用私钥进行解密
     * 
     * 说明:
     * 
@param encryptedDataArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:35:28
     
*/
    
public String getDecryptString(byte[] encryptedDataArray) throws Exception{
        
// 得到私钥
        PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(privateKey);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PrivateKey keyPrivate
=kf.generatePrivate(keySpec);
        
        
// 解密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.DECRYPT_MODE, keyPrivate);
        
byte[] arr=cp.doFinal(encryptedDataArray);
        
        
// 得到解密后的字符串
        return new String(arr);
    }

    
public byte[] getPublicKey() {
        
return publicKey;
    }
    
    
public static void main(String[] arr) throws Exception{
        String str
="你好,世界! Hello,world!";
        System.out.println(
"准备用公钥加密的字符串为:"+str);
        
        
// 用公钥加密
        RSASecurityCoder rsaCoder=new RSASecurityCoder();
        
byte[] publicKey=rsaCoder.getPublicKey();        
        
byte[] encryptArray=rsaCoder.getEncryptArray(str, publicKey);
        
        System.out.print(
"用公钥加密后的结果为:");
        
for(byte b:encryptArray){
            System.out.print(b);
        }
        System.out.println();
        
        
// 用私钥解密
        String str1=rsaCoder.getDecryptString(encryptArray);
        System.out.println(
"用私钥解密后的字符串为:"+str1);
    }
}

用于初始化RSASecurityCoder实例的SecurityUtil类代码:
package com.heyang;

/**
 * 信息安全实用类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-2 上午10:57:49
 * 修改时间:2010-12-2 上午10:57:49
 
*/
public class SecurityUtil{
    
// 用于加密解密的RSA编码类
    private static RSASecurityCoder coder;
    
    
/**
     * 初始化coder的静态构造子
     
*/
    
static{
        
try {
            coder
=new RSASecurityCoder();
        } 
catch (Exception e) {
            e.printStackTrace();
        }
    }

    
public static RSASecurityCoder getCoder() {
        
return coder;
    }
}


您可以从http://www.box.net/shared/cyg98xgz78 获得上述代码涉及到的两个实例工程。

好了,感谢您看到这里,希望此文字没有耽误您太多宝贵时间。
posted @ 2010-12-02 11:44 何杨 阅读(11018) | 评论 (16)编辑 收藏

按:以下文字涉及RSA解密加密的基本操作,您如果已经知晓就不用浪费时间了。

在加密解密过程中,如果加密解密双方都使用同一密钥,那么泄密的可能性还是存在的,无论你把这个密钥放在代码,文件或是数据库中。最好是密钥分成两部分,公钥提供出去给应答者,让它给返回的结果加密,请求者得到返回结果后,用自己的私钥将其解密,公钥和私钥都由程序生成。这样,客户端和服务器端程序的所有者和编写者都难以知道每个客户端的私钥是什么,从而难以破解数据。RSA就是实现这一想法的途径之一。

举例来说,现在有一客户端视图和WebService服务器端通信,假如服务器端的响应函数是 String getResponse(String params,byte[] publicKeyArray);两边程序都有下面的RSASecurityCoder类,客户端在发送请求前,可以得到此类的一个实例,并得到其公钥,然后调用服务器端的getResponse函数,公钥就是这个函数的第二个参数;服务器端得到请求后,处理得到结果,然后用第二个参数--客户端送来的公钥进行加密,然后送回结果;客户端得到结果后用自己的私钥进行解密就可以了。这样,信息在传输过程的安全性就有了充分的保证了。

下面请看代码:
package com.heyang.util;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA加密解密类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-12-1 下午06:14:38
 * 修改时间:2010-12-1 下午06:14:38
 
*/
public class RSASecurityCoder{
    
// 非对称加密密钥算法
    private static final String Algorithm="RSA";
    
    
// 密钥长度,用来初始化
    private static final int Key_Size=1024;
    
    
// 公钥
    private final byte[] publicKey;
    
    
// 私钥
    private final byte[] privateKey;
    
    
/**
     * 构造函数,在其中生成公钥和私钥
     * 
@throws Exception
     
*/
    
public RSASecurityCoder() throws Exception{
        
// 得到密钥对生成器
        KeyPairGenerator kpg=KeyPairGenerator.getInstance(Algorithm);
        kpg.initialize(Key_Size);
        
        
// 得到密钥对
        KeyPair kp=kpg.generateKeyPair();
        
        
// 得到公钥
        RSAPublicKey keyPublic=(RSAPublicKey)kp.getPublic();
        publicKey
=keyPublic.getEncoded();
        
        
// 得到私钥
        RSAPrivateKey keyPrivate=(RSAPrivateKey)kp.getPrivate();
        privateKey
=keyPrivate.getEncoded();
    }
    
    
/**
     * 用公钥对字符串进行加密
     * 
     * 说明:
     * 
@param originalString
     * 
@param publicKeyArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:29:51
     
*/
    
public byte[] getEncryptArray(String originalString,byte[] publicKeyArray) throws Exception{
        
// 得到公钥
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyArray);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PublicKey keyPublic
=kf.generatePublic(keySpec);
        
        
// 加密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.ENCRYPT_MODE, keyPublic);
        
return cp.doFinal(originalString.getBytes());
    }
    
    
    
/**
     * 使用私钥进行解密
     * 
     * 说明:
     * 
@param encryptedDataArray
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午06:35:28
     
*/
    
public String getDecryptString(byte[] encryptedDataArray) throws Exception{
        
// 得到私钥
        PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(privateKey);
        KeyFactory kf
=KeyFactory.getInstance(Algorithm);
        PrivateKey keyPrivate
=kf.generatePrivate(keySpec);
        
        
// 解密数据
        Cipher cp=Cipher.getInstance(Algorithm);
        cp.init(Cipher.DECRYPT_MODE, keyPrivate);
        
byte[] arr=cp.doFinal(encryptedDataArray);
        
        
// 得到解密后的字符串
        return new String(arr);
    }

    
public byte[] getPublicKey() {
        
return publicKey;
    }
    
    
public static void main(String[] arr) throws Exception{
        String str
="你好,世界! Hello,world!";
        System.out.println(
"准备用公钥加密的字符串为:"+str);
        
        
// 用公钥加密
        RSASecurityCoder rsaCoder=new RSASecurityCoder();
        
byte[] publicKey=rsaCoder.getPublicKey();        
        
byte[] encryptArray=rsaCoder.getEncryptArray(str, publicKey);
        
        System.out.print(
"用公钥加密后的结果为:");
        
for(byte b:encryptArray){
            System.out.print(b);
        }
        System.out.println();
        
        
// 用私钥解密
        String str1=rsaCoder.getDecryptString(encryptArray);
        System.out.println(
"用私钥解密后的字符串为:"+str1);
    }
}

输出:
准备用公钥加密的字符串为:你好,世界! Hello,world!
用公钥加密后的结果为:
62-90-128-107-100-7070-11157-123-9160-6-116-68-1476-45-112-107-53-90107-84-670-9862-35-11116-83-10864312117-96-117-56995-2510321-89-89-828977-8810940100-91-76986562-222574-12815-120118-103-11-121-6030-6490-79-804911111-17-473984-7046-12294-8454-27108-26-11281-43833782-7926-612284-81781132357-3108-12673245-5111912-86-10041-799104-8146-5712374-55
用私钥解密后的字符串为:你好,世界! Hello,world
!


看到这里,如果有人说客户端调用服务器端的getResponse函数时,第一个参数params不是还会暴露一部分信息吗? 不要怕,我们可以让服务器端再准备一个WebService函数 byte[] getServerPublicKey();客户端可以调用这个函数以得到服务器端的公钥,然后把params用这个公钥加密,然后再调用getResponse(String params,byte[] publicKeyArray)函数,服务器端接到请求后,用自己的私钥对第一个参数进行解密就可以了。这样,所有信息都得到了保护。

如果String的表现力不够怎么办,有了XML的帮助,这从来不是问题,您说呢?

好了,感谢您看到这里,希望上面的文字能对您有所帮助;如果您要使用的话,上面的代码需要改写一下,相信您知道该怎么办。

posted @ 2010-12-01 19:19 何杨 阅读(495) | 评论 (0)编辑 收藏

按:以下内容涉及传统的AES加密解密方法,熟悉它的请不要浪费宝贵时间。

如果用Base64进行加密解密是不安全的,因为这种方式的方法和密钥(字符映射表)都是公开的,对此熟悉的人如果看到一串字符后面带一些等号,很容易想到是Base64进行加密。因此,我们必须采取一些更安全的加密解密方式,AES就是其一。

在使用AES进行加密解密之前,需要到Sun的官方网站上下载一个权限文件:jce_policy,目前它的下载网址是:http://www.oracle.com/technetwork/java/javase/downloads/index.html ,找到“Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6”后点击按钮下载,得到下载文件后解开,然后将其中的local_policy.jar和US_export_policy.jar拷贝到你的JAVA_HOME\jre\lib\security和JRE_HOME\lib\security两个目录下。如果没有这一步骤,进行加密解密的时候会产生java.security.InvalidKeyException异常。

接下来就是代码了:
package com.heyang.util;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;


/**
 * AES算法加密解密实用工具类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-11-29 上午11:19:11
 * 修改时间:2010-11-29 上午11:19:11
 
*/
public class AESSecurityUtil{
    
// 加密方法
    private static final String Algorithm="AES";
    
    
// 进行加密解密的密钥
    private static final String Key="03a53dfc257fe1b0996626a5e2e2210692936bd16cc60f37211cbeef9353e268";
    
    
/**
     * 取得解密后的字符串
     * 
     * 说明:
     * 
@param encryptArr
     * 
@return
     * 创建时间:2010-12-1 下午03:33:31
     
*/
    
public static String getDecryptString(byte[] encryptArr){
        
try{
            Cipher cp
=Cipher.getInstance(Algorithm);
            cp.init(Cipher.DECRYPT_MODE, getKey());
            
byte[] arr=cp.doFinal(encryptArr);
            
            
return new String(arr);
        }
        
catch(Exception ex){
            System.out.println(
"无法进行解密,原因是"+ex.getMessage());
            
return null;
        }
    }
    
    
/**
     * 取得加密后的字节数组
     * 
     * 说明:
     * 
@param originalString
     * 
@return
     * 创建时间:2010-12-1 下午03:33:49
     
*/
    
public static byte[] getEncryptByteArray(String originalString){
        
try{
            Cipher cp
=Cipher.getInstance(Algorithm);
            cp.init(Cipher.ENCRYPT_MODE, getKey());
            
return cp.doFinal(originalString.getBytes());
        }
        
catch(Exception ex){
            System.out.println(
"无法进行加密,原因是"+ex.getMessage());
            
return null;
        }
    }
    
    
/**
     * 取得密钥数组
     * 
     * 说明:
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午03:31:08
     
*/
    
private static byte[] initKey() throws Exception{
        KeyGenerator kg
=KeyGenerator.getInstance(Algorithm);
        kg.init(
256);
        
        SecretKey sk
=kg.generateKey();
        
        
return sk.getEncoded();
    }
    
    
/**
     * 取得字符串形式的密钥
     * 
     * 说明:
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午03:31:36
     
*/
    
public static String initKeyHex() throws Exception{
        
return new String(Hex.encodeHex(initKey()));
    }
    
    
/**
     * 取得密钥
     * 
     * 说明:
     * 
@return
     * 
@throws Exception
     * 创建时间:2010-12-1 下午03:33:17
     
*/
    
private static Key getKey() throws Exception{
        
byte[] arr=Hex.decodeHex(Key.toCharArray());
        
        
return new SecretKeySpec(arr,Algorithm);
    }
    
    
public static void main(String[] args)  throws Exception{
        
//System.out.println(initKeyHex());
        
        String str
="Hello!World 你好!世界。";
        
        
byte[] arr=AESSecurityUtil.getEncryptByteArray(str);
        System.out.print(
"AES加密后的结果为:");
        
for(byte b:arr){
            System.out.print(b);
        }
        System.out.println();
        
        String str1
=AESSecurityUtil.getDecryptString(arr);
        System.out.println(
"AES解密后的字符串为:"+str1);
    }
}
测试输出如下:
AES加密后的结果为:833522115-115-6373-10-940-110-93-87736-561-1083427-99-6-6218-4104108-1031216395-92
AES解密后的字符串为:Hello
!World 你好!世界。

上面代码中值得注意的是,加密后的结果不能直接变成String形式,因为这会导致解密的不可行(解密抛出javax.crypto.IllegalBlockSizeException异常)。如果要使用其他的Key,可以单独执行一下initKeyHex()函数,将输出结果置换掉静态变量Key的值即可。

这样,在AES的帮助下,我们实现了比较安全的加密,破解者知道方法AES,但不知道密钥的话,解密会很困难。但是,话说回来,java程序被反编译很容易,别有用心的人还是可以看到密钥,但我们还是可以用公钥加密私钥解密的方式来对付,这个以后有空再说。

好了,感谢您看到这里。
posted @ 2010-12-01 16:10 何杨 阅读(4055) | 评论 (1)编辑 收藏

按:以下内容很简单,对Base64熟悉者无须往下看。

Base64是一种基于64个字符的编码算法,最早用于解决电子邮件传输的问题,它的编码和解码操作可以充当加密和解密操作,其字符映射表就是其密钥。但是,Base64算法及其密钥都是公开的,因此不能被认为是安全的加密解密方法。

下面是其示例代码:
package com.heyang.util;

import org.apache.commons.codec.binary.Base64;


/**
 * 常规Base64加密解密实用工具类
 * 说明:
 * 作者:何杨(heyang78@gmail.com)
 * 创建时间:2010-11-29 上午07:52:01
 * 修改时间:2010-11-29 上午07:52:01
 
*/
public class Base64SecurityUtil{
    
/**
     * 得到Base64加密后的字符串
     * 
     * 说明:
     * 
@param originalString
     * 
@return
     * 创建时间:2010-11-29 上午07:53:30
     
*/
    
public static String getEncryptString(String originalString){
        
byte[] arr = Base64.encodeBase64(originalString.getBytes(), true);
        
return new String(arr);
    }
    
    
/**
     * 得到Base64解密后的字符串
     * 
     * 说明:
     * 
@param encryptString
     * 
@return
     * 创建时间:2010-11-29 上午07:56:02
     
*/
    
public static String getDecryptString(String encryptString){
        
byte[] arr = Base64.decodeBase64(encryptString.getBytes());
        
return new String(arr);
    }
    
    
/**
     * 测试
     * 
     * 说明:
     * 
@param args
     * 创建时间:2010-11-29 上午07:56:39
     
*/
    
public static void main(String[] args){
        String str
="Hello world!你好,世界。";
        
        String str1
=Base64SecurityUtil.getEncryptString(str);
        System.out.println(
"经Base64加密后的密文为"+str1);
        
        String str2
=Base64SecurityUtil.getDecryptString(str1);
        System.out.println(
"经Base64解密后的原文为"+str2);
    }
}
输出:
经Base64加密后的密文为SGVsbG8gd29ybGQhxOO6w6OsysC956Gj

经Base64解密后的原文为Hello world
!你好,世界。


posted @ 2010-11-29 08:10 何杨 阅读(1232) | 评论 (0)编辑 收藏

按:以下还是炒冷饭,如果您对加盐了解就不用往下看了,以免浪费宝贵时间。
如果不了解下文部分细节的话,您可以参考这篇文章:使用MD5对存放在数据库中用户密码进行保护


直接对重要数据进行MD5处理后,反向解密确实难度很大,但还是可以找出破绽的,请看下图:


如果名为李自成的用户可以查看数据库,那么他可以观察到自己的密码和别人的密码加密后的结果都是一样,那么,别人用的和自己就是同一个密码,这样,就可以利用别人的身份登录了。

那么我们以前的加密方法是否对这种行为失效了呢?其实只要稍微混淆一下就能防范住了,这在加密术语中称为“加盐”。具体来说就是在原有材料(用户自定义密码)中加入其它成分(一般是用户自有且不变的因素),以此来增加系统复杂度。当这种盐和用户密码相结合后,再通过摘要处理,就能得到隐蔽性更强的摘要值。下面请见代码:
// 对密码进行加盐后加密,加密后再通过Hibernate往数据库里存
        String changedPswd=DigestUtils.md5Hex(name+pswd);

就是这样简单,上面代码中盐就是用户名,可以的话还可以用用户注册时的邮件,注册时间等非空信息(如果是空信息这个加盐处理会失效)。

下面是数据库中两个用户的记录,他们的实际登录密码都是123456,但光看用户记录是完全看不出来的。这下别有用心的人打开数据库看到的密码都完全不一样,他以前的手段就失效了。


加盐就是这样简单,感谢您看到这里。




posted @ 2010-11-28 09:53 何杨 阅读(11781) | 评论 (6)编辑 收藏

以下文章属于老调重弹,您如果对MD5的使用已经熟悉请不要往下看以免浪费宝贵时间。

登录Web系统时通常都采用用户名和密码的形式,如果这样的数据以明码的方式放在数据库中的话无疑会给别有用心的人以可趁之机,所以采取一定的防范措施是必要的。

现在比较安全的方式是用MD5进行加密,利用Apache commons的DigestUtils工具类我们可以迅速做到这一点。
要得到Apache commons的DigestUtils工具类,你必须加载commons-codec-1.x.jar包,我使用的是commons-codec-1.3.jar。使用的具体类是:org.apache.commons.codec.digest.DigestUtils.

下面,我们的任务是,当用户注册时,将他注册的密码加密后存入数据库,下面请见具体代码:
 1 // 对密码进行加密,加密后再通过Hibernate往数据库里存
 2         String changedPswd=DigestUtils.md5Hex(pswd);
 3         
 4         User user=new User(name,changedPswd,email,brief);
 5         
 6         if(service.hasSameName(name)){
 7             // 同名检测
 8             request.setAttribute("msg""已经有和'"+name+"'同名的用户存在了,请换个名称注册.");
 9             return new ActionForward("/web/page/register.jsp");
10         }
11         
12         if(service.hasSameEmail(email)){
13             // 同Emial检测
14             request.setAttribute("msg""已经有和'"+email+"'相同的用户存在了,请换个Email注册.");
15             return new ActionForward("/web/page/register.jsp");
16         }
17         
18         try{
19             service.create(user);
20             saveUserRegisterInforToLog(user,request);
21             request.setAttribute("msg"""+name+",欢迎您的加盟.Ȼ������¼��ť");
22             return new ActionForward("/web/page/login.jsp");
23         }
24         catch(Exception ex){
25             String str="创建用户时遇到未预计的异常,具体的异常信息为'"+ex.getMessage()+"',请与系统维护人员联系.";
26             request.setAttribute("msg",str );
27             logger.fatal(str);
28             return new ActionForward("/web/page/register.jsp");
29         }

以上第二行代码是进行MD5加密的处理,如果用户输入的密码是123456789,则会得到25f9e794323b453885f5181f1b624d0b这样的字符串。

注册用户后,数据库中您将看到如下的对应记录,看到这样的文字,要去反猜原始密码是非常困难的,当然您有山东大学王小云教授的本事则不费吹灰之力。


下面,我们还要对登录时做一番处理,因为登录时用的是原始密码,我们应该对它进行加密后再和数据库中的对应字段进行比对,代码如下:
            User user=objs.get(0);
            
            
// 得到MD5加密后的密码
            String changedPswd=DigestUtils.md5Hex(password);
                
            
// 再与数据库中用户密码进行比对
            if(user.getPassword().equals(changedPswd)==false){
                
throw new ErrorPswdException("密码不匹配.");
            }
else{
                
return user;


            }

以上代码中,password是用户在页面输入的原始密码,changedPswd是经过MD5加密后的密码,user是按名称查询出来的用户,他的密码部分就是已经经过MD5加密的,我们拿这两个密码进行比对即可。

之所以没有反向还原是因为MD5加密和Base64不一样,前者是不可逆的,后者则可以还原。当然,Base64不是严格意义上的加密手段。

最后的问题,如果数据库中原有数据未经加密怎么办,好在MySql数据库提供了md5函数帮我们做到这一点,使用update projectmanager_user set pswd=md5(pswd) 这样的语句就可以将原来数据库中的密码部分用MD5加密了。

下面的图片演示了这一过程:

原始数据:


使用update projectmanager_user set pswd=md5(pswd)加密后的数据库记录:


到此啰嗦完了,感谢您看到这里。
posted @ 2010-11-27 13:56 何杨 阅读(7851) | 评论 (4)编辑 收藏

仅列出标题
共28页: First 上一页 14 15 16 17 18 19 20 21 22 下一页 Last