zoukankan      html  css  js  c++  java
  • Android网络传输中必用的两个加密算法:MD5 和 RSA (附java完毕測试代码)

    MD5和RSA是网络传输中最经常使用的两个算法,了解这两个算法原理后就能大致知道加密是怎么一回事了。但这两种算法使用环境有差异,刚好互补。

    一、MD5算法

    首先MD5是不可逆的,仅仅能加密而不能解密。比方明文是yanzi1225627,得到MD5加密后的字符串是:14F2AE15259E2C276A095E7394DA0CA9  但不能由后面一大串倒推出yanzi1225627.因此能够用来存储用户输入的password在server上。如今下载文件校验文件是否中途被篡改也是用的它,原理參见:http://blog.csdn.net/forgotaboutgirl/article/details/7258109 不管在Android上还是pc上用java实现MD5都比較easy,由于java已经把它做到了java.security.MessageDigest里。以下是一个MD5Util.java类:

    package org.md5.util;
    
    import java.security.MessageDigest;
    public class MD5Util {
    	public final static String getMD5String(String s) {
    		char hexDigits[] = { '0', '1', '2', '3', '4',
    				'5', '6', '7', '8', '9',
    				'A', 'B', 'C', 'D', 'E', 'F' };
    		try {
    			byte[] btInput = s.getBytes();
    			//获得MD5摘要算法的 MessageDigest 对象
    			MessageDigest mdInst = MessageDigest.getInstance("MD5");
    			//使用指定的字节更新摘要
    			mdInst.update(btInput);
    			//获得密文
    			byte[] md = mdInst.digest();
    			//把密文转换成十六进制的字符串形式
    			int j = md.length;
    			char str[] = new char[j * 2];
    			int k = 0;
    			for (int i = 0; i < j; i++) {
    				byte byte0 = md[i];
    				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
    				str[k++] = hexDigits[byte0 & 0xf];
    			}
    			return new String(str);
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    }

    通过以下两行代码调用:

    /************************************MD5加密測试*****************************/
    String srcString = "yanzi1225627";
    System.out.println("MD5加密后 = " + MD5Util.getMD5String(srcString));

    二、RSA加密

    RSA是可逆的,一个字符串能够经rsa加密后,经加密后的字符串传到对端如server上,再进行解密就可以。前提是server知道解密的私钥,当然这个私钥最好不要再网络传输。RSA算法描写叙述中须要以下几个变量:

    1、p和q 是不相等的,足够大的两个质数。 p和q是保密的

    2、n = p*q n是公开的

    3、f(n) = (p-1)*(q-1)

    4、e 是和f(n)互质的质数

    5、计算參数d 

    6、经过上面5步计算得到公钥KU=(e,n) 私钥KR=(d,n)

    以下两篇文章对此有清晰的描写叙述:

    http://wenku.baidu.com/view/e53fbe36a32d7375a417801b.html

    http://bank.hexun.com/2009-06-24/118958531.html

    以下是java实现RSAUtil.java类:

    package org.rsa.util;
    
    import javax.crypto.Cipher;
    import java.security.*;
    import java.security.spec.RSAPublicKeySpec;
    import java.security.spec.RSAPrivateKeySpec;
    import java.security.spec.InvalidKeySpecException;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.io.*;
    import java.math.BigInteger;
    
    /**
     * RSA 工具类。提供加密,解密,生成密钥对等方法。
     * 须要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。
     * RSA加密原理概述  
     * RSA的安全性依赖于大数的分解,公钥和私钥都是两个大素数(大于100的十进制位)的函数。  
     * 据推測,从一个密钥和密文判断出明文的难度等同于分解两个大素数的积  
     * ===================================================================  
     * (该算法的安全性未得到理论的证明)  
     * ===================================================================  
     * 密钥的产生:  
     * 1.选择两个大素数 p,q ,计算 n=p*q;  
     * 2.随机选择加密密钥 e ,要求 e 和 (p-1)*(q-1)互质  
     * 3.利用 Euclid 算法计算解密密钥 d , 使其满足 e*d = 1(mod(p-1)*(q-1)) (当中 n,d 也要互质)  
     * 4:至此得出公钥为 (n,e) 私钥为 (n,d)  
     * ===================================================================  
     * 加解密方法:  
     * 1.首先将要加密的信息 m(二进制表示) 分成等长的数据块 m1,m2,...,mi 块长 s(尽可能大) ,当中 2^s<n  
     * 2:相应的密文是: ci = mi^e(mod n)  
     * 3:解密时作例如以下计算: mi = ci^d(mod n)  
     * ===================================================================  
     * RSA速度  
     * 由于进行的都是大数计算,使得RSA最快的情况也比DES慢上100倍,不管 是软件还是硬件实现。  
     * 速度一直是RSA的缺陷。一般来说仅仅用于少量数据 加密。 
     *文件名称:RSAUtil.java<br>
     *@author 董利伟<br>
     *版本号:<br>
     *描写叙述:<br>
     *创建时间:2008-9-23 下午09:58:16<br>
     *文件描写叙述:<br>
     *改动者:<br>
     *改动日期:<br>
     *改动描写叙述:<br>
     */
    public class RSAUtil {
    
    	//密钥对
    	private KeyPair keyPair = null;
    	
    	/**
    	 * 初始化密钥对
    	 */
    	public RSAUtil(){
    		try {
    			this.keyPair = this.generateKeyPair();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/**
    	* 生成密钥对
    	* @return KeyPair
    	* @throws Exception
    	*/
    	private KeyPair generateKeyPair() throws Exception {
    		try {
    			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",new org.bouncycastle.jce.provider.BouncyCastleProvider());
    			//这个值关系到块加密的大小,能够更改,但是不要太大,否则效率会低
    			final int KEY_SIZE = 1024;
    			keyPairGen.initialize(KEY_SIZE, new SecureRandom());
    			KeyPair keyPair = keyPairGen.genKeyPair();
    			return keyPair;
    		} catch (Exception e) {
    			throw new Exception(e.getMessage());
    		}
    	
    	}
    
    	/**
    	* 生成公钥
    	* @param modulus
    	* @param publicExponent
    	* @return RSAPublicKey
    	* @throws Exception
    	*/
    	private RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) throws Exception {
    	
    		KeyFactory keyFac = null;
    		try {
    			keyFac = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
    		} catch (NoSuchAlgorithmException ex) {
    		throw new Exception(ex.getMessage());
    		}
    		RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));
    		try {
    			return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
    		} catch (InvalidKeySpecException ex) {
    			throw new Exception(ex.getMessage());
    		}
    	
    	}
    
    	/**
    	* 生成私钥
    	* @param modulus
    	* @param privateExponent
    	* @return RSAPrivateKey
    	* @throws Exception
    	*/
    	private RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) throws Exception {
    		KeyFactory keyFac = null;
    		try {
    			keyFac = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
    		} catch (NoSuchAlgorithmException ex) {
    			throw new Exception(ex.getMessage());
    		}
    		RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(modulus), new BigInteger(privateExponent));
    		try {
    			return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
    		} catch (InvalidKeySpecException ex) {
    			throw new Exception(ex.getMessage());
    		}
    	}
    
    	/**
    	* 加密
    	* @param key 加密的密钥
    	* @param data 待加密的明文数据
    	* @return 加密后的数据
    	* @throws Exception
    	*/
    	public byte[] encrypt(Key key, byte[] data) throws Exception {
    		try {
    			Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
    			cipher.init(Cipher.ENCRYPT_MODE, key);
    			//获得加密块大小,如:加密前数据为128个byte,而key_size=1024 加密块大小为127 byte,加密后为128个byte;
    			//因此共同拥有2个加密块,第一个127 byte第二个为1个byte
    			int blockSize = cipher.getBlockSize();
    			int outputSize = cipher.getOutputSize(data.length);//获得加密块加密后块大小
    			int leavedSize = data.length % blockSize;
    			int blocksSize = leavedSize != 0 ? data.length / blockSize + 1 : data.length / blockSize;
    			byte[] raw = new byte[outputSize * blocksSize];
    			int i = 0;
    			while (data.length - i * blockSize > 0) {
    				if (data.length - i * blockSize > blockSize)
    				cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
    				else
    				cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
    				//这里面doUpdate方法不可用,查看源码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到ByteArrayOutputStream中
    				//,而最后doFinal的时候才将全部的byte[]进行加密,但是到了此时加密块大小非常可能已经超出了OutputSize所以仅仅好用dofinal方法。
    				i++;
    			}
    			return raw;
    		} catch (Exception e) {
    		throw new Exception(e.getMessage());
    		}
    	}
    
    	/**
    	* 解密
    	* @param key 解密的密钥
    	* @param raw 已经加密的数据
    	* @return 解密后的明文
    	* @throws Exception
    	*/
    	public byte[] decrypt(Key key, byte[] raw) throws Exception {
    		try {
    			Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
    			cipher.init(cipher.DECRYPT_MODE, key);
    			int blockSize = cipher.getBlockSize();
    			ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
    			int j = 0;
    			while (raw.length - j * blockSize > 0) {
    				bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
    				j++;
    			}
    			return bout.toByteArray();
    		} catch (Exception e) {
    			throw new Exception(e.getMessage());
    		}
    	}
    	
    	/**
    	 * 返回公钥
    	 * @return
    	 * @throws Exception 
    	 */
    	public RSAPublicKey getRSAPublicKey() throws Exception{
    		
    		//获取公钥
    		RSAPublicKey pubKey = (RSAPublicKey) keyPair.getPublic();
    		//获取公钥系数(字节数组形式)
    		byte[] pubModBytes = pubKey.getModulus().toByteArray();
    		//返回公钥公用指数(字节数组形式)
    		byte[] pubPubExpBytes = pubKey.getPublicExponent().toByteArray();
    		//生成公钥
    		RSAPublicKey recoveryPubKey = this.generateRSAPublicKey(pubModBytes,pubPubExpBytes);
    		return recoveryPubKey;
    	}
    	
    	/**
    	 * 获取私钥
    	 * @return
    	 * @throws Exception 
    	 */
    	public RSAPrivateKey getRSAPrivateKey() throws Exception{
    		
    		//获取私钥
    		RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
    		//返回私钥系数(字节数组形式)
    		byte[] priModBytes = priKey.getModulus().toByteArray();
    		//返回私钥专用指数(字节数组形式)
    		byte[] priPriExpBytes = priKey.getPrivateExponent().toByteArray();
    		//生成私钥
    		RSAPrivateKey recoveryPriKey = this.generateRSAPrivateKey(priModBytes,priPriExpBytes);
    		return recoveryPriKey;
    	}
    	
    	
    
    }
    
    測试代码:

    /****************************RSA加密解密測试********************************/
    try {
    RSAUtil rsa = new RSAUtil();
    String str = "yanzi1225627";
    RSAPublicKey pubKey = rsa.getRSAPublicKey();
    RSAPrivateKey priKey = rsa.getRSAPrivateKey();
    byte[] enRsaBytes = rsa.encrypt(pubKey,str.getBytes());
    String enRsaStr = new String(enRsaBytes, "UTF-8");
    System.out.println("加密后==" + enRsaStr);
    System.out.println("解密后==" + new String(rsa.decrypt(priKey, rsa.encrypt(pubKey,str.getBytes()))));
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    以下是运行结果:

    加密后==s?ko?1@lo????BJ?iE???1Ux?Kx&??=??n
    O? ?l?>?????2r?y??8v- A??` ????r?t3?-3y?hjL?M??Se?Z???????~?"??e??XZ?苜?
    解密后==yanzi1225627

    上面代码须要用到一个包rsa.jar,下载链接及上面的測试代码我已打包,下载链接见下:

    http://download.csdn.net/detail/yanzi1225627/7382263




  • 相关阅读:
    poj3278 Catch That Cow
    poj2251 Dungeon Master
    poj1321 棋盘问题
    poj3083 Children of the Candy Cor
    jvm基础知识—垃圾回收机制
    jvm基础知识1
    java面试基础必备
    java soket通信总结 bio nio aio的区别和总结
    java scoket aIO 通信
    java scoket Blocking 阻塞IO socket通信四
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3780432.html
Copyright © 2011-2022 走看看