package com.monitor.util; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; public class SHAEncrypt { /** * 生成SALT的数组(86) */ private final String[] SALT_ARR = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", "-", "*", "/", "'", ":", ";", ">", "<", "~", "!", "@", "#", "$", "%", "^", "&", "(", ")", "{", "}", "[", "]", "|" }; /** * 循环加密次数 */ private final int ENCODE_COUNT = 1000; /** * 加密算法类型 */ private final String ENCODE_TYPE = "SHA-256"; /** * SALT长度 */ private final int SALT_LENGTH = 16; /** * getBytes时指定使用的字符集 */ private final String CHAR_SET = "UTF-8"; /** * 对明文密码进行SSHA-256加密,加密步骤如下: <br> * 1. 生成随机salt值 <br> * 2. 明文密码变形:前后各补4位0 <br> * 3. 连接salt值: 将salt分成前8位temp1和剩余部分temp2,以temp2+transformedPwd+temp1的形式连接 <br> * 4. 对连接后的字串进行多次SHA-256加密<br> * 5. 对加密后的密文右移6位<br> * 6. 将salt值转换成字节数组(utf-8)再转换成16进制字符串<br> * 7. 将转换后的salt值作左移4位变形<br> * 8. 连接移位后的密文和移位后的变形salt值字串<br> * 9. 对连接字串右移8位作为最终加密结果<br> * * @param pwd * 密码明文 * @return 加密后的密码 */ public String encryptPwd(String pwd) { String ret = ""; String salt = this.genSalt(); ret = this.encryptPwdWithSalt(pwd, salt); return ret; } /** * 对明文密码进行SSHA-256加密,加密步骤如下: <br> * 1. 明文密码变形:前后各补4位0 <br> * 2. 连接salt值: 将salt分成前8位temp1和剩余部分temp2,以temp2+transformedPwd+temp1的形式连接 <br> * 3. 对连接后的字串进行多次SHA-256加密<br> * 4. 对加密后的密文右移6位<br> * 5. 将salt值转换成字节数组(utf-8)再转换成16进制字符串<br> * 6. 将转换后的salt值作左移4位变形<br> * 7. 连接移位后的密文和移位后的变形salt值字串<br> * 8. 对连接字串右移8位作为最终加密结果<br> * * @param pwd * 明文密码 * @param salt * 用于加密的salt值 * @return */ private String encryptPwdWithSalt(String pwd, String salt) { String ret = ""; try { String transformedPwd = this.transform(pwd, 4); // 将salt分成前8位temp1和剩余部分temp2 // 以temp2+transformedPwd+temp1的形式连接 String joinStr = this.joinSaltAndPwd(salt, transformedPwd); String encodePwd = this.encodeJoinStr(joinStr); String rightMovedPwd = this.rightMove(encodePwd, 6); String hexStrSalt = this.bytes2Hex(salt.getBytes(CHAR_SET)); String leftMovedHexStrSalt = this.rightMove(hexStrSalt, -4); ret = this.rightMove(rightMovedPwd + leftMovedHexStrSalt, 8); } catch (Exception e) { ret = ""; e.printStackTrace(); } return ret; } /** * 对明文/密文进行验证,检查是否一致 验证步骤如下: <br> * 1. 从原密文中获取通过逆运算获取salt字串 <br> * 2. 对明文密码使用salt字串再次进行加密 <br> * 3. 两个密文是否一致 <br> * * @param pwd * 明文密码 * @param encPwd * 密文密码 * @return 校验结果 */ public boolean validatePwd(String pwd, String encPwd) { if (null == encPwd) { return false; } boolean ret = false; String salt = this.getSaltFromEncryptedPwd(encPwd); ret = encPwd.equals(encryptPwdWithSalt(pwd, salt)); return ret; } /** * 从密文密码中通过逆运算获取加密时使用到的salt字串 <br> * 获取步骤如下: <br> * 1. 对密文左移8位 <br> * 2. 从尾部截取变形后的salt字串 <br> * 长度为2倍原salt字串长度(因为转为16进制字节数组字串时长度会加倍) <br> * 3. 对salt值的16进制字节数组字符串右移4位 <br> * 4. 将变形后的salt值从16进制字节数组字符串还原成原来的字符串形式 <br> * * @param encPwd * 密文密码 * @return 加密时使用的salt字串,获取出错则返回"" */ private String getSaltFromEncryptedPwd(String encPwd) { String ret = ""; try { String leftMoved = this.rightMove(encPwd, -8); int hexSaltLength = SALT_LENGTH * 2; if(encPwd.length()<hexSaltLength){ // 加密密码长度比16进制字节数组字串的salt值短,不可能获取得到正确的salt值 return ""; } String hexSalt = this.rightMove(leftMoved.substring(encPwd.length() - hexSaltLength, encPwd.length()), 4); ret = new String(this.hex2Bytes(hexSalt), CHAR_SET); } catch (Exception e) { ret = ""; e.printStackTrace(); } return ret; } /** * * 获得随机SALT值 * * @return 返回一个包含字母、数字、特殊字符的16位随机数 */ private String genSalt() { StringBuffer result = new StringBuffer(); Random r = new Random(); int temp = 0; for (int i = 0; i < this.SALT_LENGTH; i++) { temp = r.nextInt(this.SALT_ARR.length); result.append(this.SALT_ARR[temp]); } return result.toString(); } /** * 密码变形(前后补N位0) * * @param pwd * 密码原文 * @param n * 补0的个数 * @return 返回一个密码前后补N位0的字符串 */ private String transform(String pwd, int n) { String toTransform = null == pwd ? "" : pwd; StringBuffer temp = new StringBuffer(); for (int i = 0; i < n; i++) temp.append("0"); return temp.toString() + toTransform + temp.toString(); } /** * * 把指定字符串右移N位,若N<0则为左移 * * @param src * 源字符串 * @param n * 右移的位数 * @return 返回一个右移N位的字符串 */ private String rightMove(String src, int n) { if (src == null || src.length() == 0) { return src; } boolean isRight = true; int absN = n; if (n < 0) { isRight = false; absN = -n; } int cnt = absN > src.length() ? absN % src.length() : absN; if (0 == cnt) { return src; } if (isRight) { // 右移cnt位 String temp1 = src.substring(src.length() - cnt, src.length()); String temp2 = src.substring(0, src.length() - cnt); return temp1 + temp2; } else { // 左移cnt位 String temp1 = src.substring(0, cnt); String temp2 = src.substring(cnt, src.length()); return temp2 + temp1; } } /** * * 把对应的随机数分成2部分,前半部分8个字符,调换顺序后把变形密码加到中间 * * @param pwd * 变形密码 * @param salt * 对应的随机数 * @return 返回一个随机数与变形密码连接的字符串 */ private String joinSaltAndPwd(String salt, String pwd) { if(salt.length()!=SALT_LENGTH){ // salt值的长度与给定的不符(校验的时候可能会出现) // 返回pwd+salt return pwd+salt; } String temp1 = salt.substring(0, 8); String temp2 = salt.substring(8, salt.length()); return temp2 + pwd + temp1; } /** * * 使用加密算法进行多次加密 * * @param joinStr * 连接字符串 * @return 返回一个多次加密后的字符串 */ private String encodeJoinStr(String joinStr) { if (joinStr == null) return null; String temp = joinStr; for (int i = 0; i < this.ENCODE_COUNT; i++) { temp = this.encrypt(temp); } return temp; } /** * 把字节数组输出成16进制字符串 * * @param bts * @return */ private String bytes2Hex(byte[] bts) { StringBuffer des = new StringBuffer(); String tmp = null; for (int i = 0; i < bts.length; i++) { tmp = (Integer.toHexString(bts[i] & 0xFF)); if (tmp.length() == 1) { des.append("0"); } des.append(tmp); } return des.toString(); } /** * 把16进制字符串输出成字节数组 * * @param hexStr * @return */ private byte[] hex2Bytes(String hexStr) { if ((hexStr.length() % 2) != 0) { return new byte[] {}; } byte[] ret = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { ret[i] = (byte) (Long.decode("0x" + hexStr.substring(i * 2, i * 2 + 2)) & 0xFF); } return ret; } /** * * 利用SHA-256对源字符串进行加密 * * @param src * @return 返回加密串,注:本例中,空串表示加密失败 */ private String encrypt(String src) { // 源字符串转换成byte数组 try { byte[] btSource = src.getBytes(CHAR_SET); // 此处选择了SHA-256加密算法,实际可选的算法有"MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512" MessageDigest md = MessageDigest.getInstance(this.ENCODE_TYPE); md.reset(); md.update(btSource); String result = bytes2Hex(md.digest()); // to HexString return result; } catch (NoSuchAlgorithmException e) { return ""; } catch (UnsupportedEncodingException e) { return ""; } } public static void main(String args[]) throws Exception { SHAEncrypt demo = new SHAEncrypt(); String str = "12test中文濲騃"; long startTime = System.currentTimeMillis(); String encPwd = demo.encryptPwd(str); System.out.println("encrypt time costs:" + (System.currentTimeMillis() - startTime)); System.out.println("encrypted pwd:" + encPwd + ",length:" + encPwd.length()); System.out.println(demo.validatePwd(str, encPwd)); System.out.println(new String(demo.hex2Bytes(encPwd), "UTF-8")); } }
发表评论
-
遍历文件夹查找字符串并写入文件小例子
2012-11-22 10:31 929package com.zeng.find; im ... -
dd/MM/yyyy:HH:mm:ss +0800时间格式的转换
2012-11-19 10:23 3198SimpleDateFormat sdf1 = new ... -
各种排序算法及其java程序实现
2012-09-28 14:39 909各种排序算法:冒择 ... -
Java排序算法之 —— 插入排序
2012-09-27 10:33 879package algorithm.sort; / ... -
Java排序算法之 —— 选择排序
2012-09-27 10:32 911package algorithm.sort; ... -
Java排序算法之 —— 归并排序
2012-09-27 10:31 1303package algorithm.sort; / ... -
Java排序算法之 —— 冒泡排序
2012-09-27 10:29 895package algorithm.sort; ... -
Java线程超时控制的实现
2012-09-27 10:20 1504一.何时需要超时控制 超时控制一般使用阻塞时间比较 ... -
随机生成由字母和数字组成的字符串
2012-08-23 16:25 977private final static String[ ... -
java图片压缩、解压缩
2012-08-23 15:57 1639/** * 对图像进行压缩 * @param imag ...
相关推荐
总结一下,Java中的密码加密与解密主要涉及哈希函数如MD5和更安全的派生函数如PBKDF2。MD5虽然广泛使用,但因存在安全风险,现在更多地被用作基本的验证,而非密码存储。在实际应用中,应当结合加盐和多次迭代来提高...
排列码是一种在信息安全领域常用的编码方式,主要用于数据的加密与解密。它的基本思想是将原始数据通过特定的算法进行编码,使得数据在传输或存储过程中不易被破解,增加了数据的安全性。在Java中实现排列码,我们...
"对密码进行加密解密" 在本篇文章中,我们将讨论如何实现对登录密码的加密解密,以确保项目安全。为了实现这一点,我们将使用 Java 语言和 DES 加密算法来实现密码的加密和解密。 首先,我们需要了解什么是 DES ...
总的来说,这本书是Java开发者深入学习加密解密技术的宝贵资源,无论你是初学者还是有经验的开发者,都能从中受益匪浅,提升你在网络安全领域的专业技能。通过阅读这本书,你将能够更好地应对各种安全挑战,保护你的...
本示例通过Java实现了字符串的加密与解密功能,采用DES加密算法,提供了基本的加密解密功能及字符串与十六进制之间的转换。这种实现方式适用于简单的加密需求,但对于更复杂的安全场景,建议考虑使用更先进的加密...
Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。《Java加密与解密的艺术》,它的...
在这个Java课程设计中,我们将深入探讨如何使用Java实现文件的加密和解密过程。 首先,我们需要理解加密的基本概念。加密是一种将明文数据转换为难以理解的形式(密文)的过程,目的是防止未经授权的访问者获取信息...
全书包含3个部分,基础篇对Java企业级应用的安全知识、密码学核心知识、与Java加密相关的API和通过权限文件加强系统安全方面的知识进行了全面的介绍;实践篇不仅对电子邮件传输算法、消息摘要算法、对称加密算法、非...
Java安全领域的百科全书,密码..., Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。
Java作为广泛使用的编程语言,提供了丰富的加密解密功能,适用于各种应用场景,如网络通信、数据库存储、身份验证等。 #### Java中的加密技术分类 Java支持多种加密算法和技术,主要包括: 1. **对称加密**:使用...
本书名为《Java加密与解密的艺术》,由梁栋撰写,ISBN为978-7-111-29762-8。书籍内容围绕Java开发中的加密与解密技术,覆盖了大部分加解密问题,旨在帮助企业应用提高安全性,并提供实用的解决策略。文中介绍了一...
总的来说,这个主题涵盖了密码学的基本概念,加密算法的原理,以及如何通过GUI实现用户友好的加密和解密操作。对于IT从业者,尤其是那些关注数据安全和隐私保护的人员,理解和掌握这些知识点是非常必要的。通过学习...
3. **密码器创建与初始化**:`Cipher`类负责实际的加密和解密操作。`Cipher.getInstance("AES")`获取一个AES密码器实例,然后根据操作模式(加密或解密)进行初始化。例如,`cipher.init(Cipher.ENCRYPT_MODE, key)`...
源代码整理部分,`javaSrc175.zip`可能包含了与书中各个章节对应的示例代码,这些代码可以帮助读者更直观地理解和实现上述加密解密技术。下载并解压后,按照`下载及使用说明.txt`的指示,可以浏览和运行代码,加深对...
Java文本加密解密是计算机编程领域中的一个重要主题,特别是在数据安全和信息安全方面。在这个课程设计中,我们将使用Java语言来实现一个简单的文本加解密系统,该系统具有图形用户界面(GUI),使得用户能够方便地...
"Java加密与解密的艺术"是一本深入探讨这个主题的专业书籍,它提供了详细的理论知识和实际操作示例,帮助开发者掌握如何在Java环境中实现安全的数据加密和解密。这本书的PDF版本和源码一起提供,为读者提供了更直观...
总结来说,Java编程实现的同步序列密码加密解密系统是一种高效且灵活的解决方案,适用于需要实时加密大量数据的场景。理解其工作原理和实现细节,对于提升软件的安全性和合规性至关重要。在开发过程中,应始终关注...
《Java加密与解密的艺术(第2版)》共12章,分为3个部分:基础篇(第1~4章)对Java企业级应用的安全知识、密码学核心知识、与Java加密相关的API和通过权限文件加强系统安全方面的知识进行了全面的介绍;实践篇(第5...
Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。 第一部分基础篇 第1章企业应用...