Java加密技术(四)

文章转自:http://snowolf.iteye.com/blog/381767 

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

流程分析:

  1. 甲方构建密钥对儿,将公钥公布给乙方,将私钥保留。
  2. 甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。
  3. 乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。



按如上步骤给出序列图,如下:



  • 通过java代码实现如下:Coder类见 Java加密技术(一)
  • 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安全编码组件
     * 
     * @author 梁栋
     * @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;
    	}
    }
    


    再给出一个测试类:

    Java代码 复制代码  收藏代码
    import static org.junit.Assert.*;
    
    import org.junit.Before;
    import org.junit.Test;
    
    import java.util.Map;
    
    /**
     * 
     * @author 梁栋
     * @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加密技术(一)
    Java加密技术(二)
    Java加密技术(三)
    Java加密技术(四)
    Java加密技术(五)
    Java加密技术(六)
    Java加密技术(七)
    Java加密技术(八)
    Java加密技术(九)
    Java加密技术(十)

    猜你喜欢

    转载自lengjing.iteye.com/blog/1176190