漫谈Java加密技术

除了DES,我们还知道有DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法——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);
  }
  }
  Console代码:
  公钥:
  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYU/+I0+z1aBl5X6DUUOHQ7FZpmBSDbKTtx89J
  EcB64jFCkunELT8qiKly7fzEqD03g8ALlu5XvX+bBqHFy7YPJJP0ekE2X3wjUnh2NxlqpH3/B/xm
  1ZdSlCwDIkbijhBVDjA/bu5BObhZqQmDwIxlQInL9oVz+o6FbAZCyHBd7wIDAQAB
  私钥:
  MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJhT/4jT7PVoGXlfoNRQ4dDsVmmY
  FINspO3Hz0kRwHriMUKS6cQtPyqIqXLt/MSoPTeDwAuW7le9f5sGocXLtg8kk/R6QTZffCNSeHY3
  GWqkff8H/GbVl1KULAMiRuKOEFUOMD9u7kE5uFmpCYPAjGVAicv2hXP6joVsBkLIcF3vAgMBAAEC
  gYBvZHWoZHmS2EZQqKqeuGr58eobG9hcZzWQoJ4nq/CarBAjw/VovUHE490uK3S9ht4FW7Yzg3LV
  /MB06Huifh6qf/X9NQA7SeZRRC8gnCQk6JuDIEVJOud5jU+9tyumJakDKodQ3Jf2zQtNr+5ZdEPl
  uwWgv9c4kmpjhAdyMuQmYQJBANn6pcgvyYaia52dnu+yBUsGkaFfwXkzFSExIbi0MXTkhEb/ER/D
  rLytukkUu5S5ecz/KBa8U4xIslZDYQbLz5ECQQCy5dutt7RsxN4+dxCWn0/1FrkWl2G329Ucewm3
  QU9CKu4D+7Kqdj+Ha3lXP8F0Etaaapi7+EfkRUpukn2ItZV/AkEAlk+I0iphxT1rCB0Q5CjWDY5S
  Df2B5JmdEG5Y2o0nLXwG2w44OLct/k2uD4cEcuITY5Dvi/4BftMCZwm/dnhEgQJACIktJSnJwxLV
  o9dchENPtlsCM9C/Sd2EWpqISSUlmfugZbJBwR5pQ5XeMUqKeXZYpP+HEBj1nS+tMH9u2/IGEwJA
  fL8mZiZXan/oBKrblAbplNcKWGRVD/3y65042PAEeghahlJMiYquV5DzZajuuT0wbJ5xQuZB01+X
  nfpFpBJ2dw==
  公钥加密——私钥解密
  加密前: abc
  解密后: abc
  公钥:
  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdOj40yEB48XqWxmPILmJAc7UecIN7F32etSHF
  9rwbuEh3+iTPOGSxhoSQpOED0vOb0ZIMkBXZSgsxLaBSin2RZ09YKWRjtpCA0kDkiD11gj4tzTiM
  l9qq1kwSK7ZkGAgodEn3yIILVmQDuEImHOXFtulvJ71ka07u3LuwUNdB/wIDAQAB
  私钥:
  MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN06PjTIQHjxepbGY8guYkBztR5w
  g3sXfZ61IcX2vBu4SHf6JM84ZLGGhJCk4QPS85vRkgyQFdlKCzEtoFKKfZFnT1gpZGO2kIDSQOSI
  PXWCPi3NOIyX2qrWTBIrtmQYCCh0SffIggtWZAO4QiYc5cW26W8nvWRrTu7cu7BQ10H/AgMBAAEC
  gYEAz2JWBizjI31bqhP4XiP9PuY5F3vqBW4T+L9cFbQiyumKJc58yzTWUAUGKIIn3enXLG7dNqGr
  mbJro4JeFIJ3CiVDpXR9+FluIgI4SXm7ioGKF2NOMA9LR5Fu82W+pLfpTN2y2SaLYWEDZyp53BxY
  j9gUxaxi1MQs+C1ZgDF2xmECQQDy70bQntbRfysP+ppCtd56YRnES1Tyekw0wryS2tr+ivQJl7JF
  gp5rPAOXpgrq36xHDwUspQ0sJ0vj0O7ywxr1AkEA6SAaLhrJJrYucC0jxwAhUYyaPN+aOsWymaRh
  9jA/Wc0wp29SbGTh5CcMuGpXm1g0M+FKW3dGiHgS3rVUKim4owJAbnxgapUzAgiiHxxMeDaavnHW
  9C2GrtjsO7qtZOTgYI/1uT8itvZW8lJTF+9OW8/qXE76fXl7ai9dFnl5kzMk2QJBALfHz/vCsArt
  mkRiwY6zApE4Z6tPl1V33ymSVovvUzHnOdD1SKQdD5t+UV/crb3QVi8ED0t2B0u0ZSPfDT/D7kMC
  QDpwdj9k2F5aokLHBHUNJPFDAp7a5QMaT64gv/d48ITJ68Co+v5WzLMpzJBYXK6PAtqIhxbuPEc2
  I2k1Afmrwyw=
  私钥加密——公钥解密
  加密前: sign
  解密后: sign
  私钥签名——公钥验证签名
  签名:
  ud1RsIwmSC1pN22I4IXteg1VD2FbiehKUfNxgVSHzvQNIK+d20FCkHCqh9djP3h94iWnIUY0ifU+
  mbJkhAl/i5krExOE0hknOnPMcEP+lZV1RbJI2zG2YooSp2XDleqrQk5e/QF2Mx0Zxt8Xsg7ucVpn
  i3wwbYWs9wSzIf0UjlM=
  状态:
  true
  简要总结一下,使用公钥加密、私钥解密,完成了乙方到甲方的一次数据传递,通过私钥加密、公钥解密,同时通过私钥签  名、公钥验证签名,完成了一次甲方到乙方的数据传递与验证,两次数据传递完成一整套的数据交互!
  类似数字签名,数字信封是这样描述的:
  数字信封
  数字信封用加密技术来保证只有特定的收信人才能阅读信的内容。
  流程:
  信息发送方采用对称密钥来加密信息,然后再用接收方的公钥来加密此对称密钥(这部分称为数字信封),再将它和信息一起发送给接收方;接收方先用相应的私钥打开数字信封,得到对称密钥,然后使用对称密钥再解开信息。

漫谈Java加密技术,布布扣,bubuko.com

漫谈Java加密技术

上一篇:第一个Java程序


下一篇:GetWindowThreadProcessId获得进程、线程ID