最近做的一个项目,服务器为Java,采用SSH框架,客户端为Android和IOS。当用户登录时,从客户端向服务器提交用户名和密码。这就存在一个问题,如果数据包在网络上被其他人截取了,密码就有可能泄露。

可以采用Base64对密码编码,但是Base64要进行解码是很容易的事。

另一种方法是对密码进行MD5加密,MD5是不可逆的,只能加密不能解密。但是其他人截取了密码的MD5字符串以后,可以原封不动的将MD5加密后的字符串提交给服务器,服务器肯定会判断这是正确的密码,这样还是可以登录进去。

解决的方法就只能采用加密算法了。加密算法分为对称加密和非对称加密。对称加密算法,加密和解密使用相同的密钥,密钥在网络传输的过程中有可能被截取,所以不是很安全。非对称加密,使用公钥加密,只能使用私钥解密,公钥是公开的,私钥是不公开的。即使在传递的过程中,公钥被其他人获取了也无所谓,因为公钥是用来加密的,只有私钥才能解密,而私钥是不会传递的,也就不可能被其他人获取。

非对称加密最常用的就是RSA算法,RSA算法是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的,取了他们姓的第一个字母来命名。RSA算法的原理就不讲了。密钥长度为768的RSA算法有可能被破解,密钥长度为1024的RSA算法还没有被破解,所以可以认为密钥长度为1024的RSA算法是比较安全的。但是RSA算法的计算量大,一般只用于关键信息的加密,如密码、对称加密算法的密钥等。在我们的项目中,就使用RSA算法对用户密码进行加密。具体的步骤如下:

1. 客户端向服务器申请密钥;

2. 服务器接收到客户端的申请以后,生成一对密钥,将公钥发给客户端,私钥自己保存;

3. 客户端接收到公钥以后,使用公钥对密码加密,然后将密文发给服务器;

4. 服务器接收到密文以后,使用私钥解密,判断是否是正确的密码。

下面是关键代码。

生成密钥和加密、解密的代码:

/**
* 生成公钥和私钥
* @throws NoSuchAlgorithmException
*
*/
public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException{
HashMap<String, Object> map = new HashMap<String, Object>();
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
map.put("public", publicKey);
map.put("private", privateKey);
return map;
} /**
* 使用模和指数生成RSA公钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
* /None/NoPadding】
*
* @param modulus
* 模
* @param exponent
* 指数
* @return
*/
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 使用模和指数生成RSA私钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
* /None/NoPadding】
*
* @param modulus
* 模
* @param exponent
* 指数
* @return
*/
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 公钥加密
*
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 模长
int key_len = publicKey.getModulus().bitLength() / 8;
// 加密数据长度 <= 模长-11
String[] datas = splitString(data, key_len - 11);
String mi = "";
//如果明文长度大于模长-11则要分组加密
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
} /**
* 私钥解密
*
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey)
throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//模长
int key_len = privateKey.getModulus().bitLength() / 8;
byte[] bytes = data.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
System.err.println(bcd.length);
//如果密文长度大于模长则要分组解密
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for(byte[] arr : arrays){
ming += new String(cipher.doFinal(arr));
}
return ming;
}

服务器收到客户端的请求时,生成一对密钥:

                HashMap<String, Object> mymap = RSAUtils.getKeys();
// 生成公钥和私钥
RSAPublicKey publicKey = (RSAPublicKey) mymap.get("public");
RSAPrivateKey privateKey = (RSAPrivateKey) mymap.get("private");
// 模
String modulus = publicKey.getModulus().toString();
// 公钥指数
String public_exponent = publicKey.getPublicExponent().toString();
// 私钥指数
String private_exponent = privateKey.getPrivateExponent().toString();
// 使用模和指数生成公钥和私钥
RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulus, private_exponent);

将其中的模和私钥指数发给客户端,客户端收到以后,使用getPublicKey(String modulus, String exponent)生成公钥,使用公钥对密码加密,然后发给服务器。服务器收到密文以后,使用decryptByPrivateKey(String data, RSAPrivateKey privateKey)解密,获得密码明文,然后就可以判断密码是否正确。

Java Web项目RSA加密的更多相关文章

  1. IOS, Android, Java Web Rest : RSA 加密和解密问题

    IOS, Android, Java Web Rest :  RSA 加密和解密问题 一对公钥私钥可以使用 OpenSSL创建, 通常 1024位长度够了. 注意: 1. 公钥私钥是BASE64编码的 ...

  2. 【转】 我的java web登录RSA加密

    [转] 我的java web登录RSA加密 之前一直没关注过web应用登录密码加密的问题,这两天用appscan扫描应用,最严重的问题就是这个了,提示我明文发送密码.这个的确很不安全,以前也大概想过, ...

  3. C# Java间进行RSA加密解密交互(二)

    原文:C# Java间进行RSA加密解密交互(二) 接着前面一篇文章C# Java间进行RSA加密解密交互,继续探讨这个问题. 在前面,虽然已经实现了C# Java间进行RSA加密解密交互,但是还是与 ...

  4. Java web项目综合练习(Estore)

    Java web项目综合练习(Estore) 复习day18: ajax代码的书写步骤 2)json格式文本,转js对象的方法是那个 项目开发流程介绍 这里学习的JavaWEB项目实战,主要是把前面学 ...

  5. JAVA WEB项目中各种路径的获取

    JAVA WEB项目中各种路径的获取 标签: java webpath文件路径 2014-02-14 15:04 1746人阅读 评论(0) 收藏 举报  分类: JAVA开发(41)  1.可以在s ...

  6. 怎么将java web 项目导入idea 中

    1.将 java web 项目导 入idea 中, 显示 然后进行 Configure 配置. 2. 点击 open module settings. 3. 4. 选择jar包. 5. 6. 配置to ...

  7. 在cmd命令行使用Maven Archetype插件 generate命令创建简单的java web项目

    前提: 1.下载apache-maven:https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache ...

  8. Java Web项目报错java.lang.NullPointerException at org.apache.jsp.front.index_jsp._jspInit(index_jsp.java:30)

    环境:myeclipse+tomcat6+jdk6 今天搭建了一个Java Web项目,访问index.jsp时报如下错误: 严重: Servlet.service() for servlet jsp ...

  9. 使用Spring Boot来加速Java web项目的开发

    我想,现在企业级的Java web项目应该或多或少都会使用到Spring框架的. 回首我们以前使用Spring框架的时候,我们需要首先在(如果你使用Maven的话)pom文件中增加对相关的的依赖(使用 ...

随机推荐

  1. [.net 面向对象编程基础] (1) 开篇

    [.net 面向对象编程基础] (1)开篇 使用.net进行面向对象编程也有好长一段时间了,整天都忙于赶项目,完成项目任务之中.最近偶有闲暇,看了项目组中的同学写的代码,感慨颇深.感觉除了定义个类,就 ...

  2. 高灵活度,高适用性,高性能,轻量级的 ORM 实现

    ORM(Object-Relational Mapping 对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,目的是提供易于理解的模型化数据的方法. ORM虽然有诸多好处,但是在实 ...

  3. yformater - chrome谷歌浏览器json格式化json高亮json解析插件

    yformater是一款chrome浏览器插件,用来格式化(高亮)服务端接口返回的json数据. 实际上小菜并不是第一个写这种插件的,但是现有的chrome json格式化插件实在是不太好用,索性小菜 ...

  4. [ASP.NET MVC 小牛之路]09 - Controller 和 Action (1)

    我们知道,在 MVC 中每个请求都会提交到 Controller 进行处理.Controller 是和请求密切相关的,它包含了对请求的逻辑处理,能对 Model 进行操作并选择 View 呈现给用户, ...

  5. Java集合类的总结

    Java语言的java.until包中提供了一些集合类,这些集合类又被称为容器.说到集合就会想到数组,集合类与数组的不同之处是,数组的长度是固定的,集合的长度是可变的:数组用来存放基本数据类型,集合从 ...

  6. [VB] if 判断语句 和 If、IIf函数的比较

    Module Module1 Sub Main() Dim s1 As String = "我是真的" Dim s2 As String = "我不是真的" D ...

  7. Utility1:Overview

    Utility 是利用,使用的意思,utilization是指使用效率,利用率的意思. SQL Sever 内置 Utility Feature,便于集中监控Server关键资源(CPU和Disk)的 ...

  8. SQL Server 日期函数:EOMonth、DateFormat、Format、DatePart、DateName

    一,月份的最后一天 函数 EOMonth 返回指定日期的最后一天 EOMONTH ( start_date [, month_to_add ] ) 1,对于start_date 有两种输入方式,能够转 ...

  9. LINQ系列:Linq to Object分组操作符

    分组是指根据一个特定的值将序列中的值或元素进行分组.LINQ只包含一个分组操作符:GroupBy. GroupBy 1>. 原型定义 public static IQueryable<IG ...

  10. 【转】Linux C动态内存泄漏追踪方法

    原文:http://www.cnblogs.com/san-fu-su/p/5737984.html C里面没有垃圾回收机制,有时候你申请了动态内存却忘记释放,这就尴尬了(你的程序扮演了强盗角色,有借 ...