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

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
按:以下文字涉及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 on 2010-12-02 11:44 何杨 阅读(11008) 评论(16)  编辑  收藏

Feedback

# re: 使用RSA进行信息加密解密的WebService示例[未登录] 2010-12-02 13:22 zz
支持一下,幸苦了  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2010-12-09 09:59 mashiguang
谢谢,先收藏再细读。  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2010-12-09 10:06 mashiguang
学习了。我感觉这样做解决了明文的问题,是不是还不能解决假冒客户端的问题?  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2010-12-09 14:12 何杨
@mashiguang

是的,还需要用数字证书等。  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例[未登录] 2010-12-10 09:41 mashiguang
@何杨
谢谢
期待你出一篇https加密的方式的文章。  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2010-12-10 09:55 何杨
@mashiguang

客气了,我也是初学。尽力吧!  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例[未登录] 2011-03-06 15:13 s
客户端的密钥怎么产生的?是不是也在服务器端产生然后返回到了客户端?那传输过程中被人截取了私钥怎么办?再说你定义的方法都是在服务器端执行,加密也是先把明文发送到服务器加密 ,然后返回加密的数据,再发送到服务器  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例[未登录] 2011-03-07 23:04 何杨
@s

服务器和客户端都是各自产生自己的私钥和公钥,公钥用于发给对方来给要发给自己的数据加密,收到数据后再用自己这边的私钥解密。  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2011-04-18 08:41 柳寄悠
你好,我是一名大四的学生,现在正在做毕业设计,你的文章“使用RSA进行信息加密解密的WebService示例 ”对我很有帮助,我还有问题要问你,希望加qq:912614339  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例[未登录] 2011-12-09 23:13 Ruby
@mashiguang
@何杨
不仅客户端,服务端也有被假冒的危险。
公钥传输过程不可靠。
使用RSA进行常规通讯还有低效问题。
直接上有可信数字证书的HTTPS更靠谱。
  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2011-12-10 09:05 何杨
@Ruby

说的没错,这篇文章只是学习过程中的一步,还会前进的。  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2012-02-08 16:13 ss
您好,我想问一下那个XfireSample导进去怎么会有错的,我的QQ:414038013,希望您能加我,你这篇文章对我非常有帮助,谢谢  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2012-02-13 11:06 何杨
@ss

库导入进去了?  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2012-09-04 18:21 魏燕
这个是java的 有.net的吗?有的话 麻烦解答一下~  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2012-09-05 09:09 何杨
@魏燕

没。  回复  更多评论
  

# re: 使用RSA进行信息加密解密的WebService示例 2014-05-08 09:57 tanjun
实例怎么下载不了  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: