zoukankan      html  css  js  c++  java
  • java在非安全网络上建立可信任安全的通道(3/3)

           这篇博文的前两节(1/3,2/3)已经介绍了如何在不安全网络环境下面相互认证双方的身份(建立信任的连接),以及在此基础上进行可靠的密钥协商(DH算法)。

           这一节将介绍如何使用协商好的密钥对通道上流淌的数据进行加密。我将使用AES作为对称密钥的算法,密钥强度:128位。这个过程可以简单概括成下面两个步骤:

    • 利用协商好的key创建一个可以用于加密和解密的Aes Cipher;
    • 使用这个cipher对一个byte数组进行加密和解密。
    直接上代码吧:
    /**
     * 使用AES 128bit 算法进行加密和解密的工具类
     * 
     * @author atlas
     * @date 2012-9-18
     */
    public class AESCipher {
    	private static final int bsize = 16;
    	private static final int ivsize = 16;
    	private Cipher dCipher;
    	private Cipher eCipher;
    
    	private AESCipher(Cipher dCipher, Cipher eCipher) {
    		this.eCipher = eCipher;
    		this.dCipher = dCipher;
    	}
    
    	public static AESCipher getInstance(byte[] key) throws CryptoException {
    		String pad = "PKCS5Padding";
    		try {
    			byte[] tmpKey = ChecksumUtil.getChecksumAsBytes("md5", key);
    			byte[] tmpIV = new byte[ivsize];
    			if (key.length <= ivsize) {
    				System.arraycopy(key, 0, tmpKey, 0, key.length);
    			} else if (key.length > ivsize) {
    				System.arraycopy(key, 0, tmpIV, 0, tmpIV.length);
    			}
    			SecretKeySpec keyspec = new SecretKeySpec(tmpKey, "AES");
    			IvParameterSpec ivSpec = new IvParameterSpec(tmpIV);
    			Cipher dcipher = Cipher.getInstance("AES/CBC/" + pad);
    			Cipher ecipher = Cipher.getInstance("AES/CBC/" + pad);
    			ecipher.init(Cipher.ENCRYPT_MODE, keyspec, ivSpec);
    			dcipher.init(Cipher.DECRYPT_MODE, keyspec, ivSpec);
    			return new AESCipher(dcipher, ecipher);
    		} catch (Exception e) {
    			throw new CryptoException("initializing AESCipher fail.", e);
    		}
    	}
    
    	/**
    	 * 
    	 * @param str
    	 * @return
    	 * @throws CryptoException
    	 */
    	public String encrypt(String str) throws CryptoException {
    		try {
    			// Encode the string into bytes using utf-8
    			byte[] utf8 = str.getBytes("UTF8");
    			// Encrypt
    			byte[] enc = this.eCipher.doFinal(utf8);
    			// Encode bytes to hex string
    			return StringUtils.bytesToHex(enc);
    		} catch (Exception e) {
    			throw new CryptoException("encrypt failed.", e);
    		}
    	}
    
    	public String decrypt(String str) throws CryptoException {
    		try {
    			byte[] dec = StringUtils.hexToBytes(str);
    			// Decrypt
    			byte[] utf8 = this.dCipher.doFinal(dec);
    			// Decode using utf-8
    			return new String(utf8, "UTF8");
    		} catch (Exception e) {
    			throw new CryptoException("decrypt failed.", e);
    		}
    	}
    
    	public byte[] encrypt(byte[] message) throws CryptoException {
    		try {
    			// Encrypt
    			return this.eCipher.doFinal(message);
    		} catch (Exception e) {
    			throw new CryptoException("encrypt failed.", e);
    		}
    	}
    
    	/**
    	 * 这个方法是为了尽可能少的减少内存拷贝,input buffer和output
    	 * buffer可以是一个byte数组,不过调用者需要保证output可以输出数据的长度要足够大,即能够容纳加密后的padding。
    	 * 这个padding不会超过 {@link #getBsize() }-1
    	 * 
    	 * @param input
    	 *            待加密的buffer
    	 * @param inputOffset
    	 *            待加密的数据在input buffer中的起始位置(从0开始)
    	 * @param inputLen
    	 *            待加密的数据的长度,不超过(input.length-inputOffset).
    	 * @param output
    	 *            加密后的数据的输出buffer。
    	 * @param outputOffset
    	 *            输出buffer的起始位置。
    	 * @return 在output里面实际解密的数据长度
    	 * 
    	 * @throws ShortBufferException
    	 *             如果output buffer太小,无法容纳输出结果
    	 */
    	public int encrypt(byte[] input, int inputOffset, int inputLen,
    			byte[] output, int outputOffset) throws CryptoException {
    		try {
    			return eCipher.doFinal(input, inputOffset, inputLen, output,
    					outputOffset);
    		} catch (Exception e) {
    			throw new CryptoException("encryption failed", e);
    		}
    	}
    
    	/**
    	 * 这个方法是为了尽可能少的减少内存拷贝,input buffer和output buffer可以是同一个byte数组。
    	 * 
    	 * @param input
    	 *            待解密的buffer
    	 * @param inputOffset
    	 *            待解密的数据在input buffer中的起始位置(从0开始)
    	 * @param inputLen
    	 *            待解密的数据的长度,不超过(input.length-inputOffset).
    	 * @param output
    	 *            解密后的数据的输出buffer。
    	 * @param outputOffset
    	 *            输出buffer的起始位置。
    	 * @return 在output里面实际解密的数据长度
    	 * @throws ShortBufferException
    	 *             如果output buffer太小,无法容纳输出结果
    	 */
    	public int decrypt(byte[] input, int inputOffset, int inputLen,
    			byte[] output, int outputOffset) throws CryptoException {
    		try {
    			return dCipher.doFinal(input, inputOffset, inputLen, output,
    					outputOffset);
    		} catch (Exception e) {
    			throw new CryptoException("decryption failed", e);
    		}
    	}
    
    	/**
    	 * 返回需要的padding的长度
    	 * 
    	 * @param len
    	 * @return
    	 */
    	public int pad(int len) {
    		return eCipher.getOutputSize(len) - len;
    	}
    
    	public byte[] decrypt(byte[] message) throws CryptoException {
    		try {
    			// Decrypted
    			byte[] decrypted = this.dCipher.doFinal(message);
    			return decrypted;
    		} catch (Exception e) {
    			throw new CryptoException("decrypt failed.", e);
    		}
    	}
    }
     
     几个工具类的代码我就不贴了。
  • 相关阅读:
    PAT (Advanced Level) Practice 1054 The Dominant Color (20 分)
    PAT (Advanced Level) Practice 1005 Spell It Right (20 分) (switch)
    PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) (排序)
    hdu 5114 Collision
    hdu4365 Palindrome graph
    单链表查找最大值、两个递增的链表合并并且去重
    蓝桥杯-最短路 (SPFA算法学习)
    蓝桥杯-最大最小公倍数
    Codeforces-470 div2 C题
    蓝桥杯-地宫取宝
  • 原文地址:https://www.cnblogs.com/cwjcsu/p/8433075.html
Copyright © 2011-2022 走看看