密码学研究-玩转密钥

引入:

在我们的博客:http://supercharles888.blog.51cto.com/609344/1313864中可以看到,对于加密解密,最重要的是密码,因为从加密方式上来看,有对称加密和非对称加密,所以我们这里就用java的例子来说明,如何使用java security的API 来创造一个符合我们要求的密码。


实践:


从类角度上来说,因为对称加密,非对称加密都会用到密钥,所以顶层接口是Key(密钥因为经常要传输给对方,所以它一定是可序列化的),而对称加密来说,使用的是SecretKey,它继承自Key接口,而对于非对称加密来说,它会使用到PublicKey接口和PrivateKey接口,而且总是成对出现的,所以他们都封装在KeyPair类中:


其核心接口,类关系如下:

174452117.png




对称加密

对于对称加密来说,加密的密码和解密的密码是同一个,而比较经典的对称加密算法是DES,我们这里也用DES为例子,一般来说,要生成一个用于对称加密的密钥,我们做以下几步:

(1)实例化SecureRandom对象,让它产生一个安全随机数

(2)实例化KeyGenerator对象,它会负责产生一个半成品密钥

(3)初始化KeyGenerator,并调用generateKey()方法让其产生一个密钥(注意:这里的密钥不是最终的密钥,而是半成品,相当于做钥匙的铜片)

(4)将半成品密钥转为字节数组

(5)获取对称加密的密钥规范XXXKeySpec,比如DES,AES等,它决定密钥最终长什么样子,它相当于配钥匙时候使用的模具

(6)实例化SecureKeyFactory对象,它负责产生一个最终密钥

(7)调用SecureKeyFactorygenerateSecret()方法产生一个最终密钥,从参数可以看出来,就是铜片和模具的组合,最终才能产生一个我们需要的纹路的钥匙。


代码如下,可直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
  */
package com.charles.keystudy;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Map;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
/**
  *
  * Description:这个工具类专门来生成对称的密钥
  *
  * @author charles.wang
  * @created Oct 24, 2013 5:07:41 PM
  *
  */
public  class  SymmetricKeyUtil {
                                                                                                                                                                                                                                              
     public  static  Key generateSecretKey()  throws  Exception {
                                                                                                                                                                                                                                                  
         //实例化SecureRandom对象,这个对象作为安全的随机数生成器
         SecureRandom secureRandom =  new  SecureRandom();
         //实例化KeyGenerator对象,这个对象专门用来产生对称的密钥
         KeyGenerator kg = KeyGenerator.getInstance( "DES" );
         //初始化密钥产生器
         kg.init(secureRandom);
         //产生对称的密钥
         SecretKey secretKey = kg.generateKey();
                                                                                                                                                                                                                                                  
         //获得密钥的字节数组
         byte [] secretKeyBytes = secretKey.getEncoded();
         //获得密钥规范, 比如说"DES"
         DESKeySpec dks =   new  DESKeySpec(secretKeyBytes);
         //实例化SecureKeyFactory对象
         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" );
         //生成对称的密钥
         SecretKey finalSecretKey = keyFactory.generateSecret(dks);
                                                                                                                                                                                                                                                  
         return  finalSecretKey;
                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                  
     }
}



非对称加密:

对于非对称加密来说,加密的密码和解密的密码是两个密码(公钥加密则私钥解密,私钥加密则公钥解密),而比较经典的对称加密算法是RSA,我们这里也用RSA为例子,一般来说,要生成一个用于非对称加密的公钥私钥对,我们做以下几步:

(1)实例化KeyPairGenerator对象,它会负责产生一个半成品公钥私钥对

(2)初始化KeyPairGenerator,用希望的密钥长度作为参数

(3)调用KeyPairGeneratorgenerateKeyPair()方法产生半成品的公钥私钥对

(4)将半成品公钥私钥对转为字节数组

(5)获取非对称加密的密钥规范XXXKeySpec,对于RSA来说,一般公钥用X.509,私钥用PKCS#8

(6)实例化KeyFactory对象,它负责产生最终公钥私钥对

(7)调用KeyFactorygeneratePublic()方法产生最终公钥,generatePrivate()方法产生最终私钥


代码如下,可直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package  com.charles.keystudy;
import  java.security.Key;
import  java.security.KeyFactory;
import  java.security.KeyPair;
import  java.security.KeyPairGenerator;
import  java.security.interfaces.RSAPrivateKey;
import  java.security.interfaces.RSAPublicKey;
import  java.security.spec.PKCS8EncodedKeySpec;
import  java.security.spec.X509EncodedKeySpec;
import  java.util.HashMap;
import  java.util.Map;
import  sun.misc.BASE64Encoder;
/**
  *
  * Description: 这个工具类专门来生成非对称的密钥(分为公钥和私钥)
  *
  * @author charles.wang
  * @created Oct 24, 2013 12:02:30 PM
  *
  */
public  class  AsymmetricKeyUtil {
     /**
      *
      * @return
      * @throws Exception
      */
     public  static  Map<String, Key> generatePublicPrivateKeyPair()  throws  Exception {
         // KeyPairGenerator这个密钥对生成器是用来生成非对称的公钥的
         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "RSA" );
         // 初始化密钥生成器,用密钥的位数作为参数
         keyPairGenerator.initialize( 1024 );
         // 产生公钥对
         KeyPair keyPair = keyPairGenerator.generateKeyPair();
         // 甲方公钥
         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
         // 甲方私钥
         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
         // 获得公钥的字节数组
         byte [] publicKeyBytes = publicKey.getEncoded();
         // 获得公钥的密钥规范 ,publicKey是用X.509编码的
         X509EncodedKeySpec publicKeySpec =  new  X509EncodedKeySpec(publicKeyBytes);
         // 获得私钥的字节数组
         byte [] privateKeyBytes = privateKey.getEncoded();
         // 获得私钥的密钥规范,privateKey是用PKCS#8规范编码的
         PKCS8EncodedKeySpec privatePKC8ENcodedKeySpec =  new  PKCS8EncodedKeySpec(privateKeyBytes);
         // 实例化密钥工厂
         KeyFactory keyFactory = KeyFactory.getInstance( "RSA" );
         // 生成公钥,它是通过密钥工厂将公钥字节数组转为公钥对象
         Key publicKeyValue = keyFactory.generatePublic(publicKeySpec);
         // 生成私钥,它是通过密钥工厂将私钥字节数组转为私钥对象
         Key privateKeyValue = keyFactory.generatePrivate(privatePKC8ENcodedKeySpec);
         Map<String, Key> finalKeyPair =  new  HashMap<String, Key>();
         finalKeyPair.put( "publicKey" , publicKeyValue);
         finalKeyPair.put( "privateKey" , privateKeyValue);
         return  finalKeyPair;
     }
                                                                                                                                            
                                                                                                                                            
                                                                                                                                            
                                                                                                                                            
}



最后,交给用户使用的时候,应该是一个经过Base64编码的,我们很容易就可以做到这一点,这里附上我们的测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
  */
package com.charles.keystudy;
import java.security.Key;
import java.util.Map;
import sun.misc.BASE64Encoder;
/**
  *
  * Description: 演示类,用于演示用法
  *
  * @author charles.wang
  * @created Oct 24, 2013 5:02:36 PM
  *
  */
public class KeyDemo {
                                                                                                                               
                                                                                                                               
     /**
      * 把产生的密钥转为Base64编码的格式
      * @param key
      * @return
      * @throws Exception
      */
     public  static  String getKeyString(Key key)  throws  Exception{
         byte [] keyBytes = key.getEncoded();
         String s = ( new  BASE64Encoder()).encode(keyBytes);
         return  s;
     }
                                                                                                                              
     public  static  void  main(String[] args)  throws  Exception{
                                                                                                                                   
         //演示对称密钥的产生 过程
         System.out.println( "演示对称密钥的产生 过程" );
         Key secretKey = SymmetricKeyUtil.generateSecretKey();
         System.out.println( "Format:" +secretKey.getFormat());
         System.out.println( "secretKey:" +getKeyString(secretKey) );
         System.out.println();
                                                                                                                                   
         //演示非对称密钥的产生过程
         System.out.println( "演示非对称密钥的产生过程" );
         Map<String,Key> keyPair = AsymmetricKeyUtil.generatePublicPrivateKeyPair();
         for ( String s :keyPair.keySet()){
             System.out.println(s+ "Format:" +keyPair.get(s).getFormat());;
             System.out.println(s+ ":" +getKeyString(keyPair.get(s)) );
             System.out.println();
         }
                                                                                                                                   
     }
}



最后我们执行来观察结果,果然对称加密会生成一个密钥,而非对称加密会生成公钥私钥对:

180118258.png





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1314607,如需转载请自行联系原作者
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值