信息安全基本概念:java
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.) git
使用:推荐使用 org.apache.commons.codec.binary.Base64算法
Base64编码说明数据库
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),以后在6位的前面补两个0,造成8位一个字节的形式。 若是剩下的字符不足3个字节,则用0填充,输出字符使用'=',所以编码后输出的文本末尾可能会出现1或2个'='。apache
为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。编程
码值 | 字符 | 码值 | 字符 | 码值 | 字符 | 码值 | 字符 | |||
---|---|---|---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w | |||
1 | B | 17 | R | 33 | h | 49 | x | |||
2 | C | 18 | S | 34 | i | 50 | y | |||
3 | D | 19 | T | 35 | j | 51 | z | |||
4 | E | 20 | U | 36 | k | 52 | 0 | |||
5 | F | 21 | V | 37 | l | 53 | 1 | |||
6 | G | 22 | W | 38 | m | 54 | 2 | |||
7 | H | 23 | X | 39 | n | 55 | 3 | |||
8 | I | 24 | Y | 40 | o | 56 | 4 | |||
9 | J | 25 | Z | 41 | p | 57 | 5 | |||
10 | K | 26 | a | 42 | q | 58 | 6 | |||
11 | L | 27 | b | 43 | r | 59 | 7 | |||
12 | M | 28 | c | 44 | s | 60 | 8 | |||
13 | N | 29 | d | 45 | t | 61 | 9 | |||
14 | O | 30 | e | 46 | u | 62 | + | |||
15 | P | 31 | f | 47 | v | 63 | / |
1
2
3
4
5
6
7
|
import
java.util.Base64;
对于标准的Base64:
加密为字符串使用Base64.getEncoder().encodeToString();
加密为字节数组使用Base64.getEncoder().encode();
解密使用Base64.getDecoder().decode();
对于URL安全或MIME的Base64,只需将上述getEncoder()getDecoder()更换为getUrlEncoder()getUrlDecoder()
或getMimeEncoder()和getMimeDecoder()便可。
|
@Test public void testEncodeBase64() throws Exception { byte[] encodeBase64 = org.apache.commons.codec.binary.Base64 .encodeBase64("进行Base64".getBytes("UTF-8")); System.out.println(new String(encodeBase64));//6L+b6KGMQmFzZTY0 } @Test public void testSDecodeBase64() throws Exception { byte[] decodeBase64 = org.apache.commons.codec.binary.Base64 .decodeBase64("6L+b6KGMQmFzZTY0"); System.out.println(new String(decodeBase64));//进行Base64 }
Base58是用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及"+"和"/"符号。数组
基于ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"共计58个安全
import java.io.UnsupportedEncodingException; import java.math.BigInteger; public class Base58 { public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); private static final int[] INDEXES = new int[128]; static { for (int i = 0; i < INDEXES.length; i++) { INDEXES[i] = -1; } for (int i = 0; i < ALPHABET.length; i++) { INDEXES[ALPHABET[i]] = i; } } /** * Encodes the given bytes in base58. No checksum is appended. */ public static String encode(byte[] input) { if (input.length == 0) { return ""; } input = copyOfRange(input, 0, input.length); // Count leading zeroes. int zeroCount = 0; while (zeroCount < input.length && input[zeroCount] == 0) { ++zeroCount; } // The actual encoding. byte[] temp = new byte[input.length * 2]; int j = temp.length; int startAt = zeroCount; while (startAt < input.length) { byte mod = divmod58(input, startAt); if (input[startAt] == 0) { ++startAt; } temp[--j] = (byte) ALPHABET[mod]; } // Strip extra '1' if there are some after decoding. while (j < temp.length && temp[j] == ALPHABET[0]) { ++j; } // Add as many leading '1' as there were leading zeros. while (--zeroCount >= 0) { temp[--j] = (byte) ALPHABET[0]; } byte[] output = copyOfRange(temp, j, temp.length); try { return new String(output, "US-ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); // Cannot happen. } } public static byte[] decode(String input) throws IllegalArgumentException { if (input.length() == 0) { return new byte[0]; } byte[] input58 = new byte[input.length()]; // Transform the String to a base58 byte sequence for (int i = 0; i < input.length(); ++i) { char c = input.charAt(i); int digit58 = -1; if (c >= 0 && c < 128) { digit58 = INDEXES[c]; } if (digit58 < 0) { throw new IllegalArgumentException("Illegal character " + c + " at " + i); } input58[i] = (byte) digit58; } // Count leading zeroes int zeroCount = 0; while (zeroCount < input58.length && input58[zeroCount] == 0) { ++zeroCount; } // The encoding byte[] temp = new byte[input.length()]; int j = temp.length; int startAt = zeroCount; while (startAt < input58.length) { byte mod = divmod256(input58, startAt); if (input58[startAt] == 0) { ++startAt; } temp[--j] = mod; } // Do no add extra leading zeroes, move j to first non null byte. while (j < temp.length && temp[j] == 0) { ++j; } return copyOfRange(temp, j - zeroCount, temp.length); } public static BigInteger decodeToBigInteger(String input) throws IllegalArgumentException { return new BigInteger(1, decode(input)); } // // number -> number / 58, returns number % 58 // private static byte divmod58(byte[] number, int startAt) { int remainder = 0; for (int i = startAt; i < number.length; i++) { int digit256 = (int) number[i] & 0xFF; int temp = remainder * 256 + digit256; number[i] = (byte) (temp / 58); remainder = temp % 58; } return (byte) remainder; } // // number -> number / 256, returns number % 256 // private static byte divmod256(byte[] number58, int startAt) { int remainder = 0; for (int i = startAt; i < number58.length; i++) { int digit58 = (int) number58[i] & 0xFF; int temp = remainder * 58 + digit58; number58[i] = (byte) (temp / 256); remainder = temp % 256; } return (byte) remainder; } private static byte[] copyOfRange(byte[] source, int from, int to) { byte[] range = new byte[to - from]; System.arraycopy(source, from, range, 0, range.length); return range; } } 复制代码
Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域普遍使用的一种散列函数,用以提供消息的完整性保护。服务器
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机普遍使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言广泛已有MD5实现。将数据(如汉字)运算为另外一固定长度值,是杂凑算法的基础原理,MD5的前身有MD二、MD3和MD4。网络
使用:
public void testMD5() throws Exception { String md5Msg = msgSafeBase("测试MD5","MD5"); System.out.println(md5Msg);// c2dbb895a66c3ca924ccdbea49fa6884 } public String msgSafeBase(String msg, String algorithmName) throws Exception { MessageDigest m = MessageDigest.getInstance(algorithmName); m.update(msg.getBytes("UTF8")); byte s[] = m.digest(); return Hex.encodeHexString(s); }
MD5是经常使用的加密算法,也常常用于校验信息完整,如文件的完整性。用术语讲,MD5是一种消息摘要算法(Message Digest Algorithm)。另外还有一种经常使用的消息摘要算法SHA1。若是想了解这些的话,能够去百度百科:MD五、SHA一、消息摘要算法。
Java已经实现了MD五、SHA1算法。利用java.security.MessageDigest类就能够获取字符串和文件的MD5以及SHA1结果。
特色:
- 不管输入的消息有多长,计算出来的消息摘要的长度老是固定的。
- 通常地,只要输入的消息不一样,对其进行摘要之后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。
- 只能进行正向的信息摘要,而没法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息(不可逆性)。
- 好的摘要算法,没有人能从中找到“碰撞”或者说极度难找到,虽然“碰撞”是确定存在的(碰撞即不一样的内容产生相同的摘要)。
应用:
通常地,把对一个信息的摘要称为该消息的指纹或数字签名。数字签名是保证信息的完整性和不能否认性的方法。数据的完整性是指信宿接收到的消息必定是信源发送的信息,而中间绝无任何更改;信息的不能否认性是指信源不可否认曾经发送过的信息。其实,经过数字签名还能实现对信源的身份识别(认证),即肯定“信源”是不是信宿意定的通讯伙伴。 数字签名应该具备惟一性,即不一样的消息的签名是不同的;同时还应具备不可伪造性,即不可能找到另外一个消息,使其签名与已有的消息的签名同样;还应具备不可逆性,即没法根据签名还原被签名的消息的任何信息。这些特征偏偏都是消息摘要算法的特征,因此消息摘要算法适合做为数字签名算法。
有哪些具体的消息摘要算法?
介绍:
message digest 5,消息摘要算法第五版,以前有md2,md4。MD5消息摘要算法( 英语:MD5 Message-Digest Algorithm),一种被普遍使用的密码散列函数,能够产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由罗纳德·李维斯特设计,于1992年公开,用以取代MD4算法。
MD5已经普遍使用在为文件传输提供必定的可靠性方面。例如,服务器预先提供一个MD5校验和,用户下载完文件之后,用MD5算法计算下载文件的MD5校验和,而后经过检查这两个校验和是否一致,就能判断下载的文件是否出错。应用:
由于消息摘要算法具备惟一性、不可逆性、不可伪造性,所以普遍用于验证性加密领域,之因此叫验证性加密是由于不可逆性决定了没法还原出明文。
加密:一致性验证、数字证书、安全访问认证
安全性:
2009年,冯登国、谢涛二人利用差分攻击,将MD5的碰撞算法复杂度从王小云的2^42进一步下降到2^21,极端状况下甚至能够下降至2^10。仅仅2^21的复杂度意味着即使是在2008年的计算机上,也只要几秒即可以找到一对碰
1.字符串的MD5(下面的代码有详细注释)
public static String stringMD5(String input) { try { // 拿到一个MD5转换器(若是想要SHA1参数换成”SHA1”) MessageDigest messageDigest =MessageDigest.getInstance("MD5"); // 输入的字符串转换成字节数组 byte[] inputByteArray = input.getBytes(); // inputByteArray是输入字符串转换获得的字节数组 messageDigest.update(inputByteArray); // 转换并返回结果,也是字节数组,包含16个元素 byte[] resultByteArray = messageDigest.digest(); // 字符数组转换成字符串返回 return byteArrayToHex(resultByteArray); } catch (NoSuchAlgorithmException e) { return null; } }
//下面这个函数用于将字节数组换成成16进制的字符串
public static String byteArrayToHex(byte[] byteArray) { // 首先初始化一个字符数组,用来存放每一个16进制字符 char[] hexDigits = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; // new一个字符数组,这个就是用来组成结果字符串的(解释一下:一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方)) char[] resultCharArray =new char[byteArray.length * 2]; // 遍历字节数组,经过位运算(位运算效率高),转换成字符放到字符数组中去 int index = 0; for (byte b : byteArray) { resultCharArray[index++] = hexDigits[b>>> 4 & 0xf]; resultCharArray[index++] = hexDigits[b& 0xf]; } // 字符数组组合成字符串返回 return new String(resultCharArray);
从上面代码能够看出,使用MessageDigest对字符串进行MD5算法的步骤是,先将字符串转换成字节数组,在进行MD5算法,最后返回的也是一个字节数组,要咱们本身转成32位的字符串。
2.文件MD5
对文件进行MD5也能够像字符串MD5同样的,首先要把文件转成字节数组,后面和字符串MD5彻底同样。
可是若是是一个特别大的文件,一会儿把一个文件的数组所有读到内存中,那么估计内存也吃不消。
对于大文件,可使用DigestInputStream。
public static String fileMD5(String inputFile) throws IOException { // 缓冲区大小(这个能够抽出一个参数) int bufferSize = 256 * 1024; FileInputStream fileInputStream = null; DigestInputStream digestInputStream = null; try { // 拿到一个MD5转换器(一样,这里能够换成SHA1) MessageDigest messageDigest =MessageDigest.getInstance("MD5"); // 使用DigestInputStream fileInputStream = new FileInputStream(inputFile); digestInputStream = new DigestInputStream(fileInputStream,messageDigest); // read的过程当中进行MD5处理,直到读完文件 byte[] buffer =new byte[bufferSize]; while (digestInputStream.read(buffer) > 0); // 获取最终的MessageDigest messageDigest= digestInputStream.getMessageDigest(); // 拿到结果,也是字节数组,包含16个元素 byte[] resultByteArray = messageDigest.digest(); // 一样,把字节数组转换成字符串 return byteArrayToHex(resultByteArray); } catch (NoSuchAlgorithmException e) { return null; } finally { try { digestInputStream.close(); } catch (Exception e) { } try { fileInputStream.close(); } catch (Exception e) { } } }
上面的方法本人亲测过大小约4G的文件,得出的MD5值和网上下载的一个MD5小工具获得的MD5值同样,说明上面的方式没有什么问题。不过取大文件的MD5很慢,4G的文件跑一下要一分钟(I5处理器 6G内存 64位XP系统 本本)。
附1:我在网上还看到一种给文件MD5的方式
public static String getFileMD5String(File file) throws IOException{ FileInputStream in = new FileInputStream(file); FileChannel ch =in.getChannel(); MappedByteBuffer byteBuffer =ch.map(FileChannel.MapMode.READ_ONLY, 0,file.length()); messagedigest.update(byteBuffer); return byteArrayToHex (messagedigest.digest()); }
我也尝试过这样的方式,可是若是文件大于2G,那么这种方式会出现异常。因此不推荐。
附2:测试文件MD5的main方法
public static void main(String[] args) { long startTime = System.currentTimeMillis(); try { System.out.println(fileMD5("E:/软件/VS2008ProEdition90DayTrialCHSX1435983.iso")); } catch (IOException e) { e.printStackTrace(); } long endTime = System.currentTimeMillis(); System.out.println((endTime - startTime)/1000); }
参考:http://blog.csdn.net/xiao__gui/article/details/8148203
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。该算法通过加密专家多年来的发展和改进已日益完善,并被普遍使用。该算法的思想是接收一段明文,而后以一种不可逆的方式将它转换成一段(一般更小)密文,也能够简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值能够说是对明文的一种“指纹”或是“摘要”因此对散列值的数字签名就能够视为对此明文的数字签名。
sha1已不推荐使用
使用:
@Test public void testSHA() throws Exception { // SHA-1,SHA-256,SHA-384,和SHA-512 String hashMsg = msgSafeBase("测试SHA", "SHA-1"); System.out.println(hashMsg); // sha1:9bfec0ff7027c76c28fdaa51bd5a619c5e2f69bb } public String msgSafeBase(String msg, String algorithmName) throws Exception { MessageDigest m = MessageDigest.getInstance(algorithmName); m.update(msg.getBytes("UTF8")); byte s[] = m.digest(); return Hex.encodeHexString(s); }
HMAC是密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要做为输出。
运算做用
使用:
@Test public void testHashMsgCode() throws Exception { String macKey = initMacKey(); System.out.println(macKey); //vTVhh1xBdDTm9/TZhVsOK0+G/Aw2fkCx0gC6KcM7o2lbCy6DyatcUSe66PTu70E7J0r/hhtodcZBPuLI4/aCgw== String msgCode=hashMsgCode("测试HMAC".getBytes(),macKey); System.out.println(msgCode); //7e4f0f95cfef2c8f5af9799d03798e76 } public static String initMacKey() throws Exception { // HmacMD5,HmacSHA1,HmacSHA256,HmacSHA384,HmacSHA512 KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); SecretKey secretKey = keyGenerator.generateKey(); return new String(Base64.encodeBase64(secretKey.getEncoded())); } public static String hashMsgCode(byte[] data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(key), "HmacMD5"); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); return new String(Hex.encodeHex(mac.doFinal(data))); }
BC加密包:The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 to JDK 1.8.
RIPEMD算法 原始完整性校验消息摘要
RIPEMD(RACE Integrity Primitives Evaluation Message Digest,RACE原始完整性校验消息摘要),是Hans Dobbertin等3人在md4,md5的基础上,于1996年提出来的。算法共有4个标准12八、160、256和320,其对应输出长度分别为16字节、20字节、32字节和40字节。不过,让人难以至信的是RIPEMD的设计者们根本就没有真正设计256和320位这2种标准,他们只是在128位和160位的基础上,修改了初始参数和s-box来达到输出为256和320位的目的。因此,256位的强度和128至关,而320位的强度和160位至关。RIPEMD创建在md的基础之上,因此,其添加数据的方式和md5彻底同样。
除了MD、SHA和MAC三大主流信息摘要算法以外,还有一些不常见的消息摘要算法。包括RipeMD系列、Tiger、Whirlpool和Gost3411算法。同时,RipeMD算法和MAC算法系列相结合,有产生了HmacRipeMD128和HmacRipeMD160两种算法。
针对这些算法进行简单介绍
一、RipeMD算法:针对MD4和MD5算法缺陷分析提出的算法。这些算法主要是针对摘要值得长度进行了区分
二、Tiger算法:号称最快的Hash算法,专门针对64为机器作优化了。其消息长度为192位
三、Whirlpool:被列入iso标准。与AES加密标准使用了相同的转化技术,极大提升了安全性,被称为最安全的摘要算法,长度为512位
四、Gost3411:信息摘要长度为256位
这些算法的实现java6都没提供。这里BouncyCastle进行了支持。其实这些算法的调用都一个样,就是换一个调用的名字而已。
2、RipeMD算法和HmacRipeMD算法系列
算法 | 摘要长度 | 备注 |
RipeMD128 | 128 | BouncyCastle实现 |
RipeMD160 | 160 | BouncyCastle实现 |
RipeMD256 | 256 | BouncyCastle实现 |
RipeMD320 | 320 | BouncyCastle实现 |
HmacRipeMD128 | 128 | BouncyCastle实现 |
HmacRipeMD160 | 160 | BouncyCastle实现 |
4、总结
一、HmacRipeMD消息摘要的长度与相应的摘要算法的摘要长度相同:HmacRipeMD128与RipeMD128相对应,消息摘要长度都是32个字符的16进制串。HmacRipeMD160与RipeMD160相对应,消息摘要长度都是40个字符的16进制串。
二、BouncyCastle不只仅提供了HmacRipeMD算法的实现,还提供了HmacTiger算法的实现。实现方式与上边的代码清单类似