PBE——Password-based encryption(基于密码加密)

除了DES,我们还知道有DESedeTripleDES,就是3DES)、AESBlowfishRC2RC4ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法——PBE
  
PBE
  PBE——Password-based encryption(基于密码加密)。其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。是一种简便的加密方式。

  通过java代码实现如下:
  import java.security.Key;
  
import java.util.Random;
  
import javax.crypto.Cipher;
  
import javax.crypto.SecretKey;
  
import javax.crypto.SecretKeyFactory;
  
import javax.crypto.spec.PBEKeySpec;
  
import javax.crypto.spec.PBEParameterSpec;
  
/** *//**
  * PBE安全编码组件

  *
  
*/
  
public abstract class PBECoder extends Coder {
  
/** *//**
  * 支持以下任意一种算法

  *
  
* <pre>
  
* PBEWithMD5AndDES
  
* PBEWithMD5AndTripleDES
  
* PBEWithSHA1AndDESede
  
* PBEWithSHA1AndRC2_40
  
* </pre>
  
*/
  
public static final String ALGORITHM = "PBEWITHMD5andDES";
  
/** *//**
  * 盐初始化

  *
  
* @return
  
* @throws Exception
  
*/
  
public static byte[] initSalt() throws Exception {
  
byte[] salt = new byte[8];
  
Random random = new Random();
  
random.nextBytes(salt);
  
return salt;
  
}
  
/** *//**
  * 转换密钥
<br>
  
*
  
* @param password
  
* @return
  
* @throws Exception
  
*/
  
private static Key toKey(String password) throws Exception {
  
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
  
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
  
SecretKey secretKey = keyFactory.generateSecret(keySpec);
  
return secretKey;
  
}
  
/** *//**
  * 加密

  *
  
* @param data
  * 数据

  * @param password
  * 密码

  * @param salt
  *

  * @return
  
* @throws Exception
  */

        public static byte[] encrypt(byte[] data, String password, byte[] salt)
  
throws Exception {
  
Key key = toKey(password);
  
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
  
Cipher cipher = Cipher.getInstance(ALGORITHM);
  
cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
  
return cipher.doFinal(data);
  
}
  
/** *//**
  * 解密

  *
  
* @param data
  * 数据

  * @param password
  * 密码

  * @param salt
  *

  * @return
  
* @throws Exception
  
*/
  
public static byte[] decrypt(byte[] data, String password, byte[] salt)
  
throws Exception {
  
Key key = toKey(password);
  
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
  
Cipher cipher = Cipher.getInstance(ALGORITHM);
  
cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
  
return cipher.doFinal(data);
  
}
  
}
  再给出一个测试类:

  import static org.junit.Assert.*;
  
import org.junit.Test;
  
/** *//**
  
*
  
* @version 1.0
  
* @since 1.0
  
*/
  
public class PBECoderTest {
  
@Test
  
public void test() throws Exception {
  
String inputStr = "abc";
  System.err.println("原文
: " + inputStr);
  
byte[] input = inputStr.getBytes();
  
String pwd = "efg";
  System.err.println("密码
: " + pwd);
  
byte[] salt = PBECoder.initSalt();
  
byte[] data = PBECoder.encrypt(input, pwd, salt);
  System.err.println("加密后
: " + PBECoder.encryptBASE64(data));
  
byte[] output = PBECoder.decrypt(data, pwd, salt);
  
String outputStr = new String(output);
  System.err.println("解密后
: " + outputStr);
  
assertEquals(inputStr, outputStr);
  
}
  
}
  控制台输出:

  原文: abc
  密码:
efg
  加密后:
iCZ0uRtaAhE=
  解密后: abc

       RSA
  这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest AdiShamir Leonard Adleman.这种加密算法的特点主要是密钥的变化,上文我们看到DES只有一个密钥。相当于只有一把钥匙,如果这把钥匙丢了,数据也就不安全了。RSA同时有两把钥匙,公钥与私钥。同时支持数字签名。数字签名的意义在于,对传输过来的数据进行校验。确保数据在传输工程中不被修改。

  流程分析:
  1、甲方构建密钥对儿,将公钥公布给乙方,将私钥保留。
  2、甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。
  3、乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。
  通过java代码实现如下:
  import java.security.Key;
  
import java.security.KeyFactory;
  
import java.security.KeyPair;
  
import java.security.KeyPairGenerator;
  
import java.security.PrivateKey;
  
import java.security.PublicKey;
  
import java.security.Signature;
  
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 javax.crypto.Cipher;
  
/** *//**
  * RSA安全编码组件

  *
  
* @version 1.0
  
* @since 1.0
  
*/
  
public abstract class RSACoder extends Coder {
  
public static final String KEY_ALGORITHM = "RSA";
  
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
  
private static final String PUBLIC_KEY = "RSAPublicKey";
  
private static final String PRIVATE_KEY = "RSAPrivateKey";
  
/** *//**
  * 用私钥对信息生成数字签名

  *
  
* @param data
  * 加密数据

  * @param privateKey
  * 私钥

  *
  
* @return
  
* @throws Exception
  
*/
  
public static String sign(byte[] data, String privateKey) throws Exception {
  // 解密由base64编码的私钥

  byte[] keyBytes = decryptBASE64(privateKey);
  // 构造PKCS8EncodedKeySpec对象

  PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  // KEY_ALGORITHM 指定的加密算法

  KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  // 取私钥匙对象

  PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
  // 用私钥对信息生成数字签名

  Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  
signature.initSign(priKey);
  
signature.update(data);
  
return encryptBASE64(signature.sign());
  
}
  
/** *//**
  * 校验数字签名

  *
  
* @param data
  * 加密数据

  * @param publicKey
  * 公钥

  * @param sign
  * 数字签名

  *
  * @return 校验成功返回true 失败返回
false
  
* @throws Exception
  
*
  
*/
  
public static boolean verify(byte[] data, String publicKey, String sign)
  
throws Exception {
  // 解密由base64编码的公钥

  byte[] keyBytes = decryptBASE64(publicKey);
  // 构造X509EncodedKeySpec对象

  X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
  // KEY_ALGORITHM 指定的加密算法

  KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  // 取公钥匙对象

  PublicKey pubKey = keyFactory.generatePublic(keySpec);
  
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  
signature.initVerify(pubKey);
  
signature.update(data);
  // 验证签名是否正常

  return signature.verify(decryptBASE64(sign));
  }

       /** *//**
  * 解密
<br>
  * 用私钥解密

  *
  
* @param data
  
* @param key
  
* @return
  
* @throws Exception
  
*/
  
public static byte[] decryptByPrivateKey(byte[] data, String key)
  
throws Exception {
  // 对密钥解密

  byte[] keyBytes = decryptBASE64(key);
  // 取得私钥

  PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
  // 对数据解密

  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  
cipher.init(Cipher.DECRYPT_MODE, privateKey);
  
return cipher.doFinal(data);
  
}
  
/** *//**
  * 解密
<br>
  * 用私钥解密

  *
  
* @param data
  
* @param key
  
* @return
  
* @throws Exception
  
*/
  
public static byte[] decryptByPublicKey(byte[] data, String key)
  
throws Exception {
  // 对密钥解密

  byte[] keyBytes = decryptBASE64(key);
  // 取得公钥

  X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  
Key publicKey = keyFactory.generatePublic(x509KeySpec);
  // 对数据解密

  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  
cipher.init(Cipher.DECRYPT_MODE, publicKey);
  
return cipher.doFinal(data);
  
}
  
/** *//**
  * 加密
<br>
  * 用公钥加密

  *
  
* @param data
  
* @param key
  
* @return
  
* @throws Exception
  
*/
  
public static byte[] encryptByPublicKey(byte[] data, String key)
  
throws Exception {
  // 对公钥解密

  byte[] keyBytes = decryptBASE64(key);
  // 取得公钥

  X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  
Key publicKey = keyFactory.generatePublic(x509KeySpec);
  // 对数据加密

  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  
return cipher.doFinal(data);
  
}
  
/** *//**
  * 加密
<br>
  * 用私钥加密

  *
  
* @param data
  
* @param key
  
* @return
  
* @throws Exception
  
*/
  
public static byte[] encryptByPrivateKey(byte[] data, String key)
  
throws Exception {
  // 对密钥解密

  byte[] keyBytes = decryptBASE64(key);
  // 取得私钥

  PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
  // 对数据加密

  Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
  
return cipher.doFinal(data);
  
}
  
/** *//**
  * 取得私钥

  *
  
* @param keyMap
  
* @return
  
* @throws Exception
  
*/
  
public static String getPrivateKey(Map<String, Object> keyMap)
  
throws Exception {
  
Key key = (Key) keyMap.get(PRIVATE_KEY);
  
return encryptBASE64(key.getEncoded());
  
}
  
/** *//**
  * 取得公钥

  *
  
* @param keyMap
  
* @return
  
* @throws Exception
  
*/
  
public static String getPublicKey(Map<String, Object> keyMap)
  
throws Exception {
  
Key key = (Key) keyMap.get(PUBLIC_KEY);
  
return encryptBASE64(key.getEncoded());
  
}
  
/** *//**
  * 初始化密钥

  *
  
* @return
  
* @throws Exception
  */

        public static Map<String, Object> initKey() throws Exception {
  
KeyPairGenerator keyPairGen = KeyPairGenerator
  
.getInstance(KEY_ALGORITHM);
  
keyPairGen.initialize(1024);
  
KeyPair keyPair = keyPairGen.generateKeyPair();
  // 公钥

  RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  // 私钥

  RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  
Map<String, Object> keyMap = new HashMap<String, Object>(2);
  
keyMap.put(PUBLIC_KEY, publicKey);
  
keyMap.put(PRIVATE_KEY, privateKey);
  
return keyMap;
  
}
  
}
  再给出一个测试类:

  import static org.junit.Assert.*;
  
import org.junit.Before;
  
import org.junit.Test;
  
import java.util.Map;
  
/** *//**
  
*
  
* @version 1.0
  
* @since 1.0
  
*/
  
public class RSACoderTest {
  
private String publicKey;
  
private String privateKey;
  
@Before
  
public void setUp() throws Exception {
  
Map<String, Object> keyMap = RSACoder.initKey();
  
publicKey = RSACoder.getPublicKey(keyMap);
  
privateKey = RSACoder.getPrivateKey(keyMap);
  System.err.println("公钥
: /n/r" + publicKey);
  System.err.println("私钥:
/n/r" + privateKey);
  
}
  
@Test
  
public void test() throws Exception {
  System.err.println("公钥加密——私钥解密
");
  
String inputStr = "abc";
  
byte[] data = inputStr.getBytes();
  
byte[] encodedData = RSACoder.encryptByPublicKey(data, publicKey);
  
byte[] decodedData = RSACoder.decryptByPrivateKey(encodedData,
  
privateKey);
  
String outputStr = new String(decodedData);
  System.err.println("加密前: " + inputStr + "/n/r" + "解密后
: " + outputStr);
  
assertEquals(inputStr, outputStr);
  
}
  
@Test
  
public void testSign() throws Exception {
  System.err.println("私钥加密——公钥解密
");
  
String inputStr = "sign";
  
byte[] data = inputStr.getBytes();
  
byte[] encodedData = RSACoder.encryptByPrivateKey(data, privateKey);
  
byte[] decodedData = RSACoder
  
.decryptByPublicKey(encodedData, publicKey);
  
String outputStr = new String(decodedData);
  System.err.println("加密前: " + inputStr + "/n/r" + "解密后
: " + outputStr);
  
assertEquals(inputStr, outputStr);
  System.err.println("私钥签名——公钥验证签名
");
  // 产生签名

  String sign = RSACoder.sign(encodedData, privateKey);
  System.err.println("签名
:/r" + sign);
  // 验证签名

  boolean status = RSACoder.verify(encodedData, publicKey, sign);
  System.err.println("状态
:/r" + status);
  
assertTrue(status);
  
}
  
}
  
  公钥加密——私钥解密
  加密前: abc
  解密后
: abc
  公钥
:
 
  私钥加密——公钥解密
  加密前: sign
  解密后
: sign
  私钥签名——公钥验证签名

  签名:
  
ud1RsIwmSC1pN22I4IXteg1VD2FbiehKUfNxgVSHzvQNIK+d20FCkHCqh9djP3h94iWnIUY0ifU+
  
mbJkhAl/i5krExOE0hknOnPMcEP+lZV1RbJI2zG2YooSp2XDleqrQk5e/QF2Mx0Zxt8Xsg7ucVpn
  
i3wwbYWs9wSzIf0UjlM=
  状态
:
  
true
  简要总结一下,使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签  名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互!

  类似数字签名,数字信封是这样描述的:
  数字信封
  数字信封用加密技术来保证只有特定的收信人才能阅读信的内容。
  流程:
  信息发送方采用对称密钥来加密信息,然后再用接收方的公钥来加密此对称密钥(这部分称为数字信封),再将它和信息一起发送给接收方;接收方先用相应的私钥打开数字信封,得到对称密钥,然后使用对称密钥再解开信息。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值