一个完整的混合加密方式在Socket客户机服务器通信应用中的例子

按:前面(http://www.blogjava.net/heyang/archive/2010/12/25/341518.html)已经提到过混合加密方式,今天这里再来赘述一下完成的代码和流程,熟悉者就不用往下看了。

整个流程的UML Sequence图(Amaterus UML用得还不熟练请见谅,会意就好)


下面是以上八个步骤中使用到的代码和信息。

步骤一
取得服务器端RSA公钥的Socket通信代码

    public   static   byte [] getPublicKey()  throws  Exception{
        Socket s
= new  Socket( " 127.0.0.1 " , 8888 );
        
        InputStream  inStram
= s.getInputStream();
        OutputStream outStream
= s.getOutputStream();
        
        
//  输出
        PrintWriter out = new  PrintWriter(outStream, true );
        
        out.print(
" getPublicKey " );
        out.flush();

        s.shutdownOutput();
//  输出结束
        
        
//  输入
        Scanner in = new  Scanner(inStram);
        StringBuilder sb
= new  StringBuilder();
        
while (in.hasNextLine()){
            String line
= in.nextLine();
            sb.append(line);
        }
        String response
= sb.toString();
        
        
byte [] arr = Base64.decodeBase64(response);
        
        s.close();
        
return  arr;
    }

步骤二:
客户端加密过程代码:

         //  待加密的明文
        StringBuilder sb1 = new  StringBuilder();
        sb1.append(
" <request> " );
        sb1.append(
" <command>register</command> " );
        sb1.append(
" <username>赵云</username> " );
        sb1.append(
" <password>123456</password> " );
        sb1.append(
" </request> " );
        String plainText
= sb1.toString();
        
        
//  对明文进行AES加密
         byte [] aesArr = aesCoder.getEncryptByteArray(plainText);  //  对明文进行AES加密
        String cipherText = Base64.encodeBase64String(aesArr); //  得到AES加密后的密文
        
        
//  使用RSA对AES密钥进行加密
        String key = aesCoder.getAesKey(); //  取得AES的密钥
         byte [] rsaArr = rsaCoder.getEncryptArray(key, serverPublicKey);
        String encryptedKey
= Base64.encodeBase64String(rsaArr);

步骤三:
将密文,AES密钥,本地RSA公钥送到服务器端的代码(粗体部分):

        Socket s=new Socket("127.0.0.1",8888);
        
       InputStream  inStram=s.getInputStream();
       OutputStream outStream=s.getOutputStream();

        
        // 输出
        PrintWriter out=new PrintWriter(outStream,true);
        
        // 待加密的明文
        StringBuilder sb1=new StringBuilder();
        sb1.append("<request>");
        sb1.append("<command>register</command>");
        sb1.append("<username>赵云</username>");
        sb1.append("<password>123456</password>");
        sb1.append("</request>");
        String plainText=sb1.toString();
        
        // 对明文进行AES加密
        byte[] aesArr=aesCoder.getEncryptByteArray(plainText); // 对明文进行AES加密
        String cipherText=Base64.encodeBase64String(aesArr);// 得到AES加密后的密文
        
        // 使用RSA对AES密钥进行加密
        String key=aesCoder.getAesKey();// 取得AES的密钥
        byte[] rsaArr=rsaCoder.getEncryptArray(key, serverPublicKey);
        String encryptedKey=Base64.encodeBase64String(rsaArr);
        
        // 在发出的密文前附带经服务器RSA公钥加密的AES密钥
        StringBuilder sb3=new StringBuilder();
        sb3.append("<aeskey>"+encryptedKey+"</aeskey>");
        sb3.append("<rsakey>"+rsaCoder.getPublicKeyString()+"</rsakey>");
        sb3.append("<text>"+cipherText+"</text>");
        
        // 请求送出前用Base64加密
        String request=Base64SecurityUtil.getEncryptString(sb3.toString());
      
        out.print(request);
       out.flush();
       s.shutdownOutput();
// 输出结束

步骤四:
服务器端解密过程代码(变量request中就是客户端送来的请求文):

        // 得到请求后先用Base64解密
        request=Base64SecurityUtil.getDecryptString(request);
        
        // 用正则表达式得到密钥文,客户端的RSA公钥和密文
        String regex="<(\\w+)>((.|\\s)+)</\\1>";

        Pattern pattern=Pattern.compile(regex);
        Matcher matcher=pattern.matcher(request);
            
        String cipheredAesKey="";// 经服务器RSA公钥加密的客户端AES钥匙密文
        String clientRsaKey="";// 客户端的RSA公钥
        String cipherText="";// 经客户端AES加密的密文
        
        Map<String,String> map=new HashMap<String,String>();
        while(matcher.find()){
            map.put(matcher.group(1), matcher.group(2));
        }
        
        if(map.size()==3){
            cipheredAesKey=map.get("aeskey");
            clientRsaKey=map.get("rsakey");
            cipherText=map.get("text");
        }
        else{
            return "无法用正则表达式解析服务器端请求";
        }

        // 得到经过服务器RSA私钥解密后的AES密钥
        String plainAesKey="";
        try {
            byte[] cipheredAesKeyArr=Base64.decodeBase64(cipheredAesKey);
            plainAesKey=model.getRsaCoder().getDecryptString(cipheredAesKeyArr);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
        // 使用AES密钥解密出明文
        byte[] cipherTextArr=Base64.decodeBase64(cipherText);
        String plainText=model.getAesCoder().getDecryptString(cipherTextArr, plainAesKey);

步骤五
这里的主要操作是根据看用户名是否在用户列表中存在,是则创建用户,否则告知名称重复。这段代码很简单常见,故省略之。

步骤六:
服务器端加密过程代码:

         //  对明文进行AES加密
         byte [] aesArr = model.getAesCoder().getEncryptByteArray(retval);  //  对明文进行AES加密
        String cipherRetval = Base64.encodeBase64String(aesArr); //  得到AES加密后的密文
        
        
//  使用RSA对AES密钥进行加密
        String key = model.getAesCoder().getAesKey(); //  取得AES的密钥
        String aesKey = "" ;
        
try {
            
byte [] clientRsaKeyArr = null ;
            clientRsaKeyArr
= Base64.decodeBase64(clientRsaKey);
            
byte [] rsaArr = model.getRsaCoder().getEncryptArray(key, clientRsaKeyArr);
            aesKey
= Base64.encodeBase64String(rsaArr);
        }
        
catch (Exception ex){
            ex.printStackTrace();
        }
        
        
//  在发出的密文前附带经服务器RSA公钥加密的AES密钥
        StringBuilder sb3 = new  StringBuilder();
        sb3.append(
" <aeskey> " + aesKey + " </aeskey> " );
        sb3.append(cipherRetval);

步骤七:
将响应发还给客户端的代码(粗体部分):

            InputStream  inStram = incoming.getInputStream();
            OutputStream outStream
= incoming.getOutputStream();
            
            Scanner in
= new  Scanner(inStram);
            PrintWriter out
= new  PrintWriter(outStream, true );
            
            
//  得到客户端的请求
            StringBuilder sb = new  StringBuilder();
            
while (in.hasNextLine()){
                String line
= in.nextLine();
                sb.append(line);
            }
            
            
            String request
= sb.toString();
            String response
= "" ;
            
if ( " getPublicKey " .equals(request)){
                
//  求服务器公钥
                response = model.getPublicKey();
            }
            
else {
                response
= getResponse(request);
            }
            
            
//  向客户端送出反馈
            out.print(response);
            out.flush();
            out.close();

步骤八:
客户端解密服务器端响应的过程:

        String cipheredAesKey = "" ; //  经服务器RSA公钥加密的客户端AES钥匙密文
        String cipheredResponse = "" ; //  经客户端AES加密的密文
        
        
//  用正则表达式得到密钥文,客户端的RSA公钥和密文
        String regex = " <aeskey>(.+)</aeskey>(.+) " ;
        Pattern pattern
= Pattern.compile(regex);
        Matcher matcher
= pattern.matcher(response);
            
        
while (matcher.find()){
            cipheredAesKey
= matcher.group( 1 );
            cipheredResponse
= matcher.group( 2 );
            
break ;
        }
        
        
//  得到经过服务器RSA私钥解密后的AES密钥
        String plainAesKey = "" ;
        
try  {
            
byte [] cipheredAesKeyArr = Base64.decodeBase64(cipheredAesKey);
            plainAesKey
= rsaCoder.getDecryptString(cipheredAesKeyArr);
        } 
catch  (Exception e) {
            e.printStackTrace();
        }
        
        
//  使用AES密钥解密出明文
         byte [] cipheredResponseArr = Base64.decodeBase64(cipheredResponse);
        String plainResponse
= aesCoder.getDecryptString(cipheredResponseArr, plainAesKey);
        System.out.println(plainResponse);

好了,整个过程的代码都贴出来了,感谢您花费宝贵时间看到这里。另外三个加密解密类的代码如下:
AESSecurityCoder类:
package  com.heyang.common.code;

import  java.security.Key;
import  java.security.NoSuchAlgorithmException;

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-12-25 下午12:19:12
 * 修改时间:2010-12-25 下午12:19:12
 
*/
public   class  AESSecurityCoder{
    
//  加密方法
     private   static   final  String Algorithm = " AES " ;
    
    
//  进行加密解密的密钥
     private  String aesKey = "" ;
    
    
/**
     * 构造函数
     * 
@throws  NoSuchAlgorithmException 
     
*/
    
public  AESSecurityCoder()  throws  NoSuchAlgorithmException{
        KeyGenerator kg
= KeyGenerator.getInstance(Algorithm);
        kg.init(
256 );
        SecretKey sk
= kg.generateKey();
        
byte [] arr = sk.getEncoded();
        
        aesKey
= new  String(Hex.encodeHex(arr));
    }
    
    
/**
     * 取得解密后的字符串
     * 
     * 说明:
     * 
@param  encryptArr
     * 
@return
     * 创建时间:2010-12-1 下午03:33:31
     
*/
    
public  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  encryptArr
     * 
@param  aesKey
     * 
@return
     * 创建时间:2010-12-25 下午01:55:42
     
*/
    
public  String getDecryptString( byte [] encryptArr,String aesKeyIn){
        
try {
            Cipher cp
= Cipher.getInstance(Algorithm);
            
            
byte [] arr1 = Hex.decodeHex(aesKeyIn.toCharArray());
            cp.init(Cipher.DECRYPT_MODE, 
new  SecretKeySpec(arr1,Algorithm));
            
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   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:33:17
     
*/
    
private  Key getKey()  throws  Exception{
        
byte [] arr = Hex.decodeHex(aesKey.toCharArray());
        
        
return   new  SecretKeySpec(arr,Algorithm);
    }

    
/**
     * 取得AES加密钥匙
     * 
     * 说明:
     * 
@return
     * 创建时间:2010-12-25 下午12:27:16
     
*/
    
public  String getAesKey() {
        
return  aesKey;
    }
}

RSASecurityCoder类:
package  com.heyang.common.code;

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;

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

/**
 * 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   byte [] publicKey;
    
    
//  私钥
     private   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);
    }

    
/**
     * 取得数组形式的公钥
     * 
     * 说明:
     * 
@return
     * 创建时间:2010-12-25 上午07:50:04
     
*/
    
public   byte [] getPublicKey() {
        
return  publicKey;
    }
    
    
/**
     * 取得字符串形式的公钥
     * 
     * 说明:
     * 
@return
     * 创建时间:2010-12-25 上午07:51:11
     
*/
    
public  String getPublicKeyString() {
        
return   Base64.encodeBase64String(getPublicKey());
    }
    
    
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);
    }
}

Base64SecurityUtil类:
package  com.heyang.common.code;

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);
        
    }
}

 

http://www.blogjava.net/heyang/archive/2010/12/26/341556.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值