`

RSA浏览器加密,服务端解密

 
阅读更多

       最近公司一直提及网络安全,特别是密码传输安全,由于LZ一直给运营商做web平台,切均为内网访问,所以也一直未使用https管理用户登陆和密码重置页面。首先声明若想做到彻底的密码安全,https是必需的,可以防止传输过程中的抓包窃取行为,从根本上解决密码泄露问题。LZ本次尝试的js端加密,java端解密的方式,只能从一定意义上实现密码安全传输,不能防止恶意模仿http进行请求操作。

       LZ本次使用的是RSA非对称加密算法,该算法需要生成一个秘钥对,称为公钥和私钥,发送方使用公钥加密,接收方使用私钥解密,只要私钥不泄露,采用1024位方式生成的秘钥加密,几乎是不可能破解的,更多该加密算法详情,请自行了解。js端加解密,参考附件jsencrypt.zip,不做赘述,使用比较简单。RSA秘钥对的生成,使用OpenSSL工具1024位方式生成,网上亦有资料可供参考。

       仅贴出java端代码供大家参考使用,其中public_key.txt和private_key.txt分别存放OpenSSL生成的公私钥信息,方便管理,同时此类需要引用第三方jar包bcprov-jdk14-138.jar,版本需自己选定。

package com.ai.wyw.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import sun.misc.BASE64Decoder;

public final class RSAUtils
{
	/**
	 * openSSL生成的公钥串
	 */
	private static final String DEFAULT_PUBLIC_KEY = "";
	
	/**
	 * openSSl生成的公钥串
	 */
	private static final String DEFAULT_PRIVATE_KEY = "";
	
	/**
	 * 私钥
	 */
	private static RSAPrivateKey privateKey;
	
	/**
	 * 公钥
	 */
	private static RSAPublicKey publicKey;
	
	/**
	 * 字节数据转字符串专用集合
	 */
	private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
			'9', 'a', 'b', 'c', 'd', 'e', 'f' };
	
	/**
	 * 私有构造方法
	 */
	private RSAUtils()
	{
		
	}

	/**
	 * 获取私钥
	 * 
	 * @return 当前的私钥对象
	 */
	public static RSAPrivateKey getPrivateKey()
	{
		return privateKey;
	}

	/**
	 * 获取公钥
	 * 
	 * @return 当前的公钥对象
	 */
	public static RSAPublicKey getPublicKey()
	{
		return publicKey;
	}

	/**
	 * 随机生成密钥对
	 */
	public static void genKeyPair()
	{
		KeyPairGenerator keyPairGen = null;
		try
		{
			keyPairGen = KeyPairGenerator.getInstance("RSA");
		}
		catch (NoSuchAlgorithmException e)
		{
			e.printStackTrace();
		}
		keyPairGen.initialize(1024, new SecureRandom());
		KeyPair keyPair = keyPairGen.generateKeyPair();
		privateKey = (RSAPrivateKey) keyPair.getPrivate();
		publicKey = (RSAPublicKey) keyPair.getPublic();
	}

	/**
	 * 从文件中输入流中加载公钥
	 * 
	 * @param in
	 *            公钥输入流
	 * @throws Exception
	 *             加载公钥时产生的异常
	 */
	public static void loadPublicKey(InputStream in) throws Exception
	{
		try
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null)
			{
				if (readLine.charAt(0) == '-')
				{
					continue;
				}
				else
				{
					sb.append(readLine);
					sb.append('\r');
				}
			}
			loadPublicKey(sb.toString());
		}
		catch (IOException e)
		{
			throw new Exception("公钥数据流读取错误");
		}
		catch (Exception e)
		{
			throw new Exception("公钥输入流为空");
		}
	}

	/**
	 * 从字符串中加载公钥
	 * 
	 * @param publicKeyStr
	 *            公钥数据字符串
	 * @throws Exception
	 *             加载公钥时产生的异常
	 */
	public static void loadPublicKey(String publicKeyStr) throws Exception
	{
		try
		{
			BASE64Decoder base64Decoder = new BASE64Decoder();
			byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new Exception("无此算法");
		}
		catch (InvalidKeySpecException e)
		{
			throw new Exception("公钥非法");
		}
		catch (IOException e)
		{
			throw new Exception("公钥数据内容读取错误");
		}
		catch (Exception e)
		{
			throw new Exception("公钥数据为空");
		}
	}

	/**
	 * 从文件中加载私钥
	 * 
	 * @param keyFileName
	 *            私钥文件名
	 * @return 是否成功
	 * @throws Exception
	 */
	public static void loadPrivateKey(InputStream in) throws Exception
	{
		try
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null)
			{
				if (readLine.charAt(0) == '-')
				{
					continue;
				}
				else
				{
					sb.append(readLine);
					sb.append('\r');
				}
			}
			loadPrivateKey(sb.toString());
		}
		catch (IOException e)
		{
			throw new Exception("私钥数据读取错误");
		}
		catch (NullPointerException e)
		{
			throw new Exception("私钥输入流为空");
		}
	}

	public static void loadPrivateKey(String privateKeyStr) throws Exception
	{
		try
		{
			BASE64Decoder base64Decoder = new BASE64Decoder();
			byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new Exception("无此算法");
		}
		catch (InvalidKeySpecException e)
		{
			throw new Exception("私钥非法");
		}
		catch (IOException e)
		{
			throw new Exception("私钥数据内容读取错误");
		}
		catch (Exception e)
		{
			throw new Exception("私钥数据为空");
		}
	}

	/**
	 * 加密过程
	 * 
	 * @param publicKey
	 *            公钥
	 * @param plainTextData
	 *            明文数据
	 * @return
	 * @throws Exception
	 *             加密过程中的异常信息
	 */
	public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception
	{
		if (publicKey == null)
		{
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher = null;
		try
		{
			cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(plainTextData);
			return output;
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new Exception("无此加密算法");
		}
		catch (NoSuchPaddingException e)
		{
			e.printStackTrace();
			return null;
		}
		catch (InvalidKeyException e)
		{
			throw new Exception("加密公钥非法,请检查");
		}
		catch (IllegalBlockSizeException e)
		{
			throw new Exception("明文长度非法");
		}
		catch (Exception e)
		{
			throw new Exception("明文数据已损坏");
		}
	}

	/**
	 * 解密过程
	 * 
	 * @param privateKey
	 *            私钥
	 * @param cipherData
	 *            密文数据
	 * @return 明文
	 * @throws Exception
	 *             解密过程中的异常信息
	 */
	public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception
	{
		if (privateKey == null)
		{
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher = null;
		try
		{
			cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] output = cipher.doFinal(cipherData);
			return output;
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new Exception("无此解密算法");
		}
		catch (NoSuchPaddingException e)
		{
			e.printStackTrace();
			return null;
		}
		catch (InvalidKeyException e)
		{
			throw new Exception("解密私钥非法,请检查");
		}
		catch (IllegalBlockSizeException e)
		{
			throw new Exception("密文长度非法");
		}
		catch (Exception e)
		{
			throw new Exception("密文数据已损坏");
		}
	}

	/**
	 * 字节数据转十六进制字符串
	 * 
	 * @param data
	 *            输入数据
	 * @return 十六进制内容
	 */
	public static String byteArrayToString(byte[] data)
	{
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < data.length; i++)
		{
			// 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
			stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
			// 取出字节的低四位 作为索引得到相应的十六进制标识符
			stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
			if (i < data.length - 1)
			{
				stringBuilder.append(' ');
			}
		}
		return stringBuilder.toString();
	}

	public static void main(String[] args)
	{
		// rsaEncrypt.genKeyPair();
		// 加载秘钥
		try
		{
			//rsaUtils.loadPublicKey(RSAUtils.DEFAULT_PUBLIC_KEY);
			//rsaUtils.loadPrivateKey(RSAUtils.DEFAULT_PUBLIC_KEY);
			RSAUtils.loadPublicKey(new FileInputStream(new File("public_key.txt")));
			RSAUtils.loadPrivateKey(new FileInputStream(new File("private_key.txt")));
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
		}
		
		// 测试字符串
		String encryptStr = 1234!@#$;
		try
		{
			// 加密
			byte[] cipher = RSAUtils.encrypt(RSAUtils.getPublicKey(), encryptStr.getBytes());
			// 解密
			byte[] plainText = RSAUtils.decrypt(RSAUtils.getPrivateKey(), cipher);
			System.out.println("密文长度:" + cipher.length);
			System.out.println(RSAUtils.byteArrayToString(cipher));
			System.out.println("明文长度:" + plainText.length);
			System.out.println(RSAUtils.byteArrayToString(plainText));
			System.out.println(new String(plainText));
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
}

        LZ看过一些关于密码安全的书籍,采用md5withRSA的数字签名的方式,可以很好的解决此类问题,首先使用md5方式生成内容摘要,对内容+salt进行公钥加密,一起发送后台,对密文内容私钥解密后去salt生成md5摘要,对比前台发送的md5摘要值,确保内容是否伪造,对此LZ没有进行实现,但的确是一个完善的安全策略。

      

分享到:
评论

相关推荐

    js加密服务端解密

    客户端的`jsencrypt.js`库是一个JavaScript实现的RSA加密工具,它允许在浏览器端进行加密操作。`common.js`可能包含辅助函数或配置,以帮助JavaScript代码执行加密过程。`JS加密,java服务端解密,采用RAS非对称加密...

    RSA加密解密 JS加密 JAVA解密 【完美版】

    经过本人修改,简化并完善了别人的代码,使其更加的容易理解和学习! 此为一个完整的项目,...功能:服务端随机生成密钥,JS用公钥加密,服务端用私钥解密。用到的JS加密文件是从官网下载的最新版,速度快,稳定性好!

    JS客户端RSA加密,Java服务端解密

    JavaScript客户端RSA加密与Java服务端解密是一种常见的安全通信机制,尤其在Web应用中,用于保护敏感数据,如用户密码、API密钥等。这里我们将深入探讨这一过程,包括RSA算法的基本原理,JavaScript中的实现,以及...

    AES+RSA加解密服务端

    通过分析和理解这些代码,我们可以更好地掌握AES+RSA加密服务端的工作原理和实现细节。 综上所述,"AES+RSA加解密服务端"是信息安全领域的一个重要应用,它利用了两种加密算法的优势,确保了数据在传输过程中的安全...

    基于.net的RSA私钥加密 公钥解密的源码2019

    如果源码与此有关,可能涉及将RSA加密应用于Word文档内容的某部分,或者是在处理XML数据时使用了RSA加密。 8. **安全注意事项**: 在实际应用中,务必妥善保管私钥,避免暴露。同时,由于RSA的加密速度较慢,通常...

    RSA加密 js客户端加密 java服务端servlet解密

    Java提供了强大的Java Cryptography Architecture (JCA) 和Java Cryptography Extension (JCE),它们包含了处理RSA加密解密的类和接口,如`java.security.KeyPairGenerator`用于生成密钥对,`javax.crypto.Cipher`...

    基于.net的RSA私钥加密 公钥解密的源码

    通过分析和理解这段源码,开发者可以更好地掌握.NET下RSA加密解密的实际应用,为自己的项目提供安全保障。 总的来说,基于.NET的RSA私钥加密和公钥解密是.NET开发中一个重要的安全功能,它结合了理论与实践,为网络...

    在iOS上使用Object-C进行RSA算法的加密+解密实现代码.zip

    在iOS平台上使用Objective-C进行RSA加密和解密通常涉及几个步骤,包括生成RSA密钥对、使用公钥加密数据、以及使用私钥解密数据。以下是一个简化的步骤说明和示例代码,展示了如何使用Objective-C和CommonCrypto库...

    RSA加密解密之javascript与java配套源码.zip

    在提供的压缩包中,有两个Java文件(RSACrypt.java和RSACryptTest.java)和一个JavaScript文件(jsencrypt.min.js),这表明代码实现了RSA加密解密的Java版本和JavaScript版本,可以在客户端和服务端之间进行安全的...

    flutter加密java解密

    在Flutter和Java混合开发的场景中,"flutter加密java解密"的主题涉及到如何在Flutter客户端与Java后台之间进行安全的数据交互,确保信息在传输过程中不被窃取或篡改。这里我们将详细讨论如何实现这一目标,并保证App...

    关于Flutter中RSA分段加密

    1.首页需要公钥私钥 生成方法百度很多; 在flutter中,密钥文件直接存放在目录中是无法使用File读取到的,只能放在asset中才可以,所以需要在 pubspec.yaml中增加相关密钥文件才...3.创建加密辅助类EncryptHelper.dart

    javaEE服务端RSA解加解密.zip

    在JavaEE环境中,RSA加密通常用于以下几个关键场景: 1. **HTTPS通信**:在服务器与客户端之间建立安全的HTTPS连接时,RSA可以用于交换会话密钥。服务器会提供其公钥,客户端使用该公钥加密会话密钥并发送给服务器...

    关于使用JS前台加密、JAVA后台解密的RSA实现,RSA加密和签名

    这篇博文"关于使用JS前台加密、JAVA后台解密的RSA实现,RSA加密和签名"探讨了如何在JavaScript前端进行RSA加密,并在Java后端进行解密,以及如何使用RSA进行数字签名。 RSA加密的核心在于一对公钥和私钥。公钥用于...

    e语言-linux加密服务端

    《易语言Linux加密服务端详解》 在信息技术领域,安全始终是至关重要的议题。本文将深入探讨基于易语言编写的Linux加密服务端源码,它为开发者提供了一种在Linux系统上实现控制台加密服务的方法。易语言,作为国内...

    iOS RSA 加密解密

    本文将深入探讨iOS平台上的RSA加密与解密技术,包括基本原理、实现方式以及相关的注意事项。 RSA(Rivest–Shamir–Adleman)算法是一种公开密钥加密技术,由Ron Rivest、Adi Shamir和Leonard Adleman在1977年提出...

    C# RSA分段加密SOCKET通信

    `RSA`是一种非对称加密算法,它使用一对公钥和私钥进行数据加密和解密,以确保在网络传输过程中数据的安全性。 首先,让我们深入了解一下`SOCKET`通信。在`C#`中,`System.Net.Sockets`命名空间提供了一套完整的`...

    脚本加密解密器脚本加密解密器

    4. **非对称加密算法**:如RSA,使用一对公钥和私钥,公钥用于加密,私钥用于解密。这种方法安全性更高,但计算量较大,不适用于大块数据的加密。 5. **许可证验证**:在解密过程中,许多脚本加密器会添加许可证...

Global site tag (gtag.js) - Google Analytics