RSA非对称性前端加密后端解密

参考:http://netsecurity.51cto.com/art/201108/287971.htm

对称加密和非对称加密。

对称加密中加密和解密用同一个密钥,如 AES/DES。密钥一旦被泄露,那么整体加密信息都将被破解。

非对称加密是生成一个密钥对即私钥和公钥,私钥加密的信息,只有对应的公钥才能解密;反之,公钥加密的信息,只能由对应的私钥才能解密。一定要保护好私钥。从性能上来说,非对称加密相对于对称加密要慢很多,所以一般只用于少量数据的加密,如银行三要素、登录密码等信息。 

数字签名

数字签名的意义在于,对传输过来的数据进行校验,确保数据在传输过程中不被修改。提交之前对明文信息通过hash算法获取摘要,然后进行加密即为数字签名。

数字证书

数字证书的意义在于,确保公钥没被篡改。数字证书主要包括:证书的发布机构,证书的有效期,公钥,证书所有者,签名所使用的的算法。

数字证书需要由权威的公司来提供,证书中心CA为公钥做认证,证书中心会对甲方的公钥和一些相关信息加密,生成数字证书。这样甲方在给乙方发送信息时,只需在签名的同时附上数字证书就可以了。乙方在收到信息后,使用CA的公钥解开数字证书,就可以拿到甲方的公钥,然后就证明数字签名是不是甲方的。https就是应用数字证书的一个示例。

数据交互流程分析

1、user向server发送一个通信请求
user->server:你好
2、server向user发送自己的数字证书。证书中有一个公钥用来加密信息,私钥由server持有
server->user:你好,我是server,这里是我的数字证书 
3、user收到server的证书后,首先验证这个数字证书到底是不是server的,数字证书有没有什么问题,数字证书如果检查没有问题,就说明数字证书中的公钥确实是server的。检查数字证书后,user会发送一个随机的字符串给server用私钥去加密(检查数字证书,后文介绍)
user->server:向我证明你就是server,这是一个随机字符串  
4、server把加密的结果返回给user。
server->user:{一个随机字符串(信息摘要加密)}(用私钥进行RSA加密)
5、user用公钥解密这个返回结果,如果解密结果与之前生成的随机字符串一致,那说明对方确实是私钥的持有者,或者说对方确实是server。 验证server的身份后,user生成一个对称加密算法和密钥,用于后面的通信的加密和解密。这个对称加密算法和密钥,user会用公钥加密后发送给server,别人截获了也没用,因为只有server手中有可以解密的私钥。这样,后面server和user就都可以用对称加密算法来加密和解密通信内容了。
server->user:{OK,已经收到你发来的对称加密算法和密钥!有什么可以帮到你的?}(用密钥进行对称加密)
user->server:{我的用户名是test,密码是123321,我要登录}(用密钥进行对称加密)
server->user:{你好,你已登录成功}(用密钥进行对称加密)

 

/** 
 * RSA 工具类。提供加密,解密,生成密钥对等方法。 
 * 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。 
 *  
 */
public class RSAUtils {
    public static final String WEB_MODULUS = "abcb0c959f370bcaae9dff448826ccec64616debac81b220d3302296c1f7cc845b83c449c0ae35bfe49869d0924466de5dfdf416998516e95bd4ec0fdfb825eb3c1b2864dad0786f35675f5cf63fbea271cb1079330ef84dab8941d140aa57f93c853e0518051e5751e78512667d8047b82e7e3adae0bf3dcb95c6a7852763db";
    public static final String WEB_PRIVATEEXPONENT = "528eb47fd3ab3348beb8c0d44f94dc380bb916266e190c321b6927fa1f8d60dda273c389398db0eb3c3cb1ac2ec049e6247cd6b70e158d200c6ef8bc42110c5d103cd5e5c51ce265f20dbd967231a505b5f179701e7b5e5e6d59530a9f291464c3101a18e7755fc9dfbefc091c52e51528d47a7b87a6f2349fb8c2a9ffc5f4d9";

    /** 
     * * 生成密钥对
     * @return KeyPair
     * @throws Exception
     */
    public static KeyPair generateKeyPair(File cfgFile) 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.generateKeyPair();
            saveKeyPair(keyPair, cfgFile);
            return keyPair;
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }

    /**
     * getKeyPair
     * @param cfgFile
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair(File cfgFile) throws Exception {
        FileInputStream fis = new FileInputStream(cfgFile);
        ObjectInputStream oos = new ObjectInputStream(fis);
        KeyPair kp = (KeyPair) oos.readObject();
        oos.close();
        fis.close();
        return kp;
    }

    /**
     * saveKeyPair
     * @param kp
     * @param cfgFile
     * @throws Exception
     */
    public static void saveKeyPair(KeyPair kp, File cfgFile) throws Exception {
        FileOutputStream fos = new FileOutputStream(cfgFile);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //生成密钥  
        oos.writeObject(kp);
        oos.close();
        fos.close();
    }

    /** 
     * * 生成公钥
     * @param modulus
     * @param publicExponent
     * @return RSAPublicKey
     * @throws Exception 
     */
    public static 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 
     */
    public static 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 pk 加密的密钥
     * @param data 待加密的明文数据
     * @return 加密后的数据 
     * @throws Exception 
     */
    public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
            cipher.init(Cipher.ENCRYPT_MODE, pk);
            int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024  
            // 加密块大小为127  
            // byte,加密后为128个byte;因此共有2个加密块,第一个127  
            // byte第二个为1个byte  
            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 pk 解密的密钥
     * @param raw 已经加密的数据
     * @return 解密后的明文
     * @throws Exception 
     */
    @SuppressWarnings("static-access")
    public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
            cipher.init(cipher.DECRYPT_MODE, pk);
            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());
        }
    }

    /**
     * hexStringToBytes
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (null == hexString || "".equals(hexString)) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        String result = "3bcf5f398f5017b66d3d8df2db3d88c9be06f8397b28b6f3b6e430d5abd84b3644d601b477c4292b53d4c28f17b9864803bdd8c93a2c2a4e9b277f89c5c648de96da9cc91d1cdab3e3adcdb837f0f0fbd6be8b6c2e36d735f8aa1674439b11ed3520303cef5c2c886363c63db70b844c95c8284b12bdb48b43ade84b707627a2";  
        System.out.println("原文加密后为:");  
        System.out.println(result);  
        byte[] en_result = hexStringToBytes(result);//new BigInteger(result, 16).toByteArray();  
        String modulus = WEB_MODULUS;
        String privateExponent = WEB_PRIVATEEXPONENT;
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) RSAUtils.generateRSAPrivateKey(new BigInteger(modulus, 16).toByteArray(), new BigInteger(privateExponent, 16).toByteArray());
        byte[] de_result = RSAUtils.decrypt(rsaPrivateKey, en_result);  
        System.out.println("还原密文:");  
        StringBuffer sb = new StringBuffer();  
        sb.append(new String(de_result));  
        System.out.println(sb.reverse().toString().substring(13));  
    }  
}
<!DOCTYPE html>
<html>
<head>
<!-- <base href=""></base> -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="jquery-1.8.3.js"></script>
<script src="jsencrypt.min.js"></script>
<script src="Barrett.js"></script>
<script src="BigInt.js"></script>
<script type="text/javascript">
     function webencryptAES(str){
        if(!str) return '';
        setMaxDigits(130);
        var PublicExponent ="10001";
        var modulus ="abcb0c959f370bcaae9dff448826ccec64616debac81b220d3302296c1f7cc845b83c449c0ae35bfe49869d0924466de5dfdf416998516e95bd4ec0fdfb825eb3c1b2864dad0786f35675f5cf63fbea271cb1079330ef84dab8941d140aa57f93c853e0518051e5751e78512667d8047b82e7e3adae0bf3dcb95c6a7852763db";
        var key = new RSAKeyPair(PublicExponent,"",modulus);
        var ramdomTxt= String(new Date().getTime());
        if(ramdomTxt.length>8){
            ramdomTxt= ramdomTxt.substring(ramdomTxt.length-8);
        }else if(ramdomTxt.length<8){
            var lStr='';
            for(var i=0;i<8-ramdomTxt.length;i++){
                lStr+='0';
            }
            ramdomTxt = lStr+ramdomTxt;
        }
        ramdomTxt+=String(Math.ceil(Math.random()*100000));
        return encryptedString(key,ramdomTxt+String(str));
    }
</script>
<script type="text/javascript">
	
	$(function(){
		$("#getPwtBtn").click(function(){
			var pwdText = $('#pwdText').val();
			var test = webencryptAES(pwdText);
			$("#resultPwd").text(test);
		});
	});
	
</script>
</body>
<body>
	<div id="" class="">
		<label>密码:</label>
		<input id="pwdText" type="text"></input>
		<button id="getPwtBtn">获取密文</button>
	</div>
	<div id="" class="" style="width:60%">
		<textfield id="resultPwd"></textfield>
	</div>
</body>
</html>

 

1、通过代码能看出来,公钥长度明显小于私钥
2、遵循:公钥加密-私钥解密,私钥加密-公钥解密的原则
3、公钥和私钥肯定是完全不同

参考:https://blog.csdn.net/chay_chan/article/details/58605605

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值