码迷,mamicode.com
首页 > 编程语言 > 详细

[Java 安全]对称加密算法

时间:2016-07-20 14:57:50      阅读:309      评论:0      收藏:0      [点我收藏+]

标签:

简介

对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yao)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。

 

特点

优点:

计算量小、加密速度快、加密效率高。

缺点:

算法是公开的,安全性得不到保证。

通信双方每次使用对称加密算法时,都需要使用其他人不知道的惟一密钥,这会使得通信双方所拥有的密钥数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。

而与公钥、密钥加密算法比起来,对称加密算法能够提供加密和认证却缺乏了签名功能,使得使用范围有所缩小。

 

常用算法

对称加密算法主要有DES3DESTripleDES)、AESIDEARC2RC4RC5Blowfish等。

 

原理

对称加密要求加密与解密使用同一个密钥,解密是加密的逆运算。由于加密、解密使用同一个密钥,这要求通信双方必须在通信前商定该密钥,并妥善保存该密钥。

对称加密体制分为两种:

一种是对明文的单个位(或字节)进行运算,称为流密码,也称为序列密码;

一种是把明文信息划分为不同的组(或块)结构,分别对每个组(或块)进行加密、解密,称为分组密码。

技术分享

 

假设甲乙方作为通信双方。假定甲乙双方在消息传递前已商定加密算法,欲完成一次消息传递需要经过如下步骤。

技术分享

工作模式

DES算法的工作模式为例,DES算法根据其加密算法所定义的明文分组的大小(56位),将数据分割成若干56位的加密区块,再以加密区块为单位,分别进行加密处理。如果最后剩下不足一个区块的大小,称之为短块。短块的处理方法有填充法、流密码加密法、密文挪用技术。

根据数据加密时每个加密区块见得关联方式来区分,可以分为以下种工作模式:

(1) 电子密码本模式(Electronic Code Book, ECB)

用途:适合加密密钥,随机数等短数据。例如,安全地传递DES密钥,ECB是最合适的模式。

(2) 密文链接模式(Cipher Booki Chaining, CBC)

用途:可加密任意长度的数据,适用于计算产生检测数据完整性的消息认证MAC

(3) 密文反馈模式(Cipher Feed Back, CFB)

用途:因错误传播无界,可以用于检查发现明文密文的篡改。

(4) 输出反馈模式(Output Feed Back, OFB)

用途:使用于加密冗余性较大的数据,比如语音和图像数据。

AES算法除了以上4中模式外,还有一种新的工作模式:

(5) 计数器模式(Counter, CTR)

用途:适用于各种加密应用。

本文对于各种工作模式的原理展开描述。个人认为,作为工程应用,了解其用途即可。

 

填充方法

Java中对称加密对于短块的处理,一般是采用填充方式。

常采用的是:NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。

ZerosPadding

方式:全部填充为0的字节

结果如下:

F1 F2 F3 F4 F5 F6 F7 F8 //第一块

F9 00 00 00 00 00 00 00 //第二块

 

PKCS5Padding

方式:每个填充的字节都记录了填充的总字节数

结果如下:

F1 F2 F3 F4 F5 F6 F7 F8 //第一块

F9 07 07 07 07 07 07 07 //第二块

 

术语

明文(Plaintext):指待加密信息。明文可以是文本文件、图片文件、二进制数据等。

密文(Ciphertext):指经过加密后的明文。密文通常以文本、二进制等形式存在。

加密(Encryption):指将明文转换为密文的过程。

解密(Decryption):指将密文转换为明文的过程。

加密密钥(Encryption Key):指通过加密算法进行加密操作用的密钥。

解密密钥(Decryption Key):指通过解密算法进行解密操作用的密钥。

信道(Channel):通信的通道,是信号传输的媒介。

 

Java对于对称加密的支持

基于密钥加密的流程(DESDESedeAESIDEA

DESDESedeAESIDEA等算法都是基于密钥加密的对称加密算法,它们的实现流程也基本一致。步骤如下:

(1)生成密钥

KeyGenerator kg = KeyGenerator.getInstance("DES");
SecureRandom random = new SecureRandom();
kg.init(random);
SecretKey secretKey = kg.generateKey();

建议使用随机数来初始化密钥的生成。

 

(2)初始化密码对象

Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

ENCRYPT_MODE:加密模式

DECRYPT_MODE:解密模式

 

(3)执行

String plaintext = "Hello World";
byte
[] ciphertext = cipher.doFinal(plaintext.getBytes());

 

完整实例

一个完整的DES加密解密范例

技术分享
  1 import org.bouncycastle.util.encoders.Base64;
  2 
  3 import javax.crypto.BadPaddingException;
  4 import javax.crypto.Cipher;
  5 import javax.crypto.IllegalBlockSizeException;
  6 import javax.crypto.KeyGenerator;
  7 import javax.crypto.NoSuchPaddingException;
  8 import javax.crypto.spec.IvParameterSpec;
  9 import java.security.InvalidAlgorithmParameterException;
 10 import java.security.InvalidKeyException;
 11 import java.security.Key;
 12 import java.security.NoSuchAlgorithmException;
 13 import java.security.NoSuchProviderException;
 14 import java.security.SecureRandom;
 15 
 16 /**
 17  * @Title DESCoder
 18  * @Description DES安全编码:是经典的对称加密算法。密钥仅56位,且迭代次数偏少。已被视为并不安全的加密算法。
 19  * @Author zhangpeng0913
 20  * @Date 2016年7月14日
 21  */
 22 public class DESCoder {
 23     public static final String KEY_ALGORITHM_DES = "DES";
 24     public static final String CIPHER_DES_DEFAULT = "DES";
 25     public static final String CIPHER_DES_ECB_PKCS5PADDING = "DES/ECB/PKCS5Padding"; // 算法/模式/补码方式
 26     public static final String CIPHER_DES_CBC_PKCS5PADDING = "DES/CBC/PKCS5Padding";
 27     public static final String CIPHER_DES_CBC_NOPADDING = "DES/CBC/NoPadding";
 28     private static final String SEED = "%%%today is nice***"; // 用于生成随机数的种子
 29 
 30     private Key key;
 31     private Cipher cipher;
 32     private String transformation;
 33 
 34     public DESCoder() throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
 35         this.key = initKey();
 36         this.cipher = Cipher.getInstance(CIPHER_DES_DEFAULT);
 37         this.transformation = CIPHER_DES_DEFAULT;
 38     }
 39 
 40     public DESCoder(String transformation)
 41             throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
 42         this.key = initKey();
 43         this.cipher = Cipher.getInstance(transformation);
 44         this.transformation = transformation;
 45     }
 46 
 47     /**
 48      * @Title decrypt
 49      * @Description 解密
 50      * @Author zhangpeng0913
 51      * @Date 2016年7月20日
 52      * @param input 密文
 53      * @return byte[] 明文
 54      * @throws InvalidKeyException
 55      * @throws IllegalBlockSizeException
 56      * @throws BadPaddingException
 57      * @throws InvalidAlgorithmParameterException
 58      */
 59     public byte[] decrypt(byte[] input) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException,
 60             InvalidAlgorithmParameterException {
 61         if (transformation.equals(CIPHER_DES_CBC_PKCS5PADDING) || transformation.equals(CIPHER_DES_CBC_NOPADDING)) {
 62             cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(getIV()));
 63         } else {
 64             cipher.init(Cipher.DECRYPT_MODE, key);
 65         }
 66         return cipher.doFinal(input);
 67     }
 68 
 69     /**
 70      * @Title encrypt
 71      * @Description 加密
 72      * @Author zhangpeng0913
 73      * @Date 2016年7月20日
 74      * @param input 明文
 75      * @return byte[] 密文
 76      * @throws InvalidKeyException
 77      * @throws IllegalBlockSizeException
 78      * @throws BadPaddingException
 79      * @throws InvalidAlgorithmParameterException
 80      */
 81     public byte[] encrypt(byte[] input) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException,
 82             InvalidAlgorithmParameterException {
 83         if (transformation.equals(CIPHER_DES_CBC_PKCS5PADDING) || transformation.equals(CIPHER_DES_CBC_NOPADDING)) {
 84             cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(getIV()));
 85         } else {
 86             cipher.init(Cipher.ENCRYPT_MODE, key);
 87         }
 88         return cipher.doFinal(input);
 89     }
 90 
 91     /**
 92      * @Title initKey
 93      * @Description 根据随机数种子生成一个密钥
 94      * @Author zhangpeng0913
 95      * @Date 2016年7月14日
 96      * @Return Key
 97      * @throws NoSuchAlgorithmException
 98      * @throws NoSuchProviderException
 99      */
100     private Key initKey() throws NoSuchAlgorithmException, NoSuchProviderException {
101         // 根据种子生成一个安全的随机数
102         SecureRandom secureRandom = null;
103         secureRandom = new SecureRandom(SEED.getBytes());
104 
105         KeyGenerator keyGen = KeyGenerator.getInstance(KEY_ALGORITHM_DES);
106         keyGen.init(secureRandom);
107         return keyGen.generateKey();
108     }
109 
110     private byte[] getIV() {
111         String iv = "01234567"; // IV length: must be 8 bytes long
112         return iv.getBytes();
113     }
114 
115     public static void main(String[] args) throws Exception {
116         DESCoder aes = new DESCoder(CIPHER_DES_CBC_PKCS5PADDING);
117 
118         String msg = "Hello World!";
119         System.out.println("[DES加密、解密]");
120         System.out.println("message: " + msg);
121         byte[] encoded = aes.encrypt(msg.getBytes("UTF8"));
122         String encodedBase64 = Base64.toBase64String(encoded);
123         System.out.println("encoded: " + encodedBase64);
124 
125         byte[] decodedBase64 = Base64.decode(encodedBase64);
126         byte[] decoded = aes.decrypt(decodedBase64);
127         System.out.println("decoded: " + new String(decoded));
128     }
129 }
View Code


基于口令加密的流程(PBE

DESDESedeAESIDEA这几种算法的应用模型几乎如出一辙。

但是,并非所有对称加密算法都是如此。

基于口令加密(Password Based Encryption, PBE)是一种基于口令加密的算法。其特点是:口令由用户自己掌管,采用随机数(这里叫做盐)杂凑多重加密等方法保证数据的安全性。

PBE没有密钥概念,密钥在其他对称加密算法中是经过计算得出的,PBE则使用口令替代了密钥。

流程:

技术分享

 

步骤如下:

(1)  产生盐

SecureRandom secureRandom = new SecureRandom();
byte
[] salt = secureRandom.generateSeed(8); // 盐长度必须为8字节

 

(2)  根据密码产生Key

String password = "123456";
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(keySpec);

 

(3)  初始化加密或解密对象

PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);

 

(4)  执行

byte[] plaintext = "Hello World".getBytes();
byte
[] ciphertext = cipher.doFinal(plaintext);


[Java 安全]对称加密算法

标签:

原文地址:http://www.cnblogs.com/jingmoxukong/p/5688306.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!