Crypt 类兼容 GNU libc crypt(3) 散列方法(可参考:http://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.3/html_node/libc_650.html)。并且,这个类是不可变的和线程安全的。
该类提供了四个参数类型不同的 crypt 方法,用来以与 crypt(3) 兼容的方式加密密码。下面将通过接收字符串的 crypt 方法为例进行介绍:
该方法将以与 crypt(3) 兼容的方式加密密码。确切的算法取决于盐字符串的格式:
SHA-512 盐以 $6$ 字符串开始,最长为 16 个字符。
SHA-256 盐以 $5$ 字符串开始,最长为 16 个字符。
MD5 盐以 $1$ 字符串开始,最长为 8 个字符
DES 传统的 UnixCrypt 算法仅使用 2 个字符
DES 算法仅使用密码的前 8 个字符!
此方法无法识别魔术字符串 “$apr1$” 和 “$2a$”,因为其输出应与 libc 实现的输出相同。
盐字符串的其余部分是从集合 [a-Za-Z0-9.] 中提取的,如果遇到 “$” 符号,则以最大长度切割。例如:
String key = "hello world"; String md5 = Crypt.crypt(key, "$1$0123$4567"); System.out.println("MD5:" + md5); // MD5:$1$0123$Ogizgcf47rN5Sbjs5RAMm.
上面实例中,我们指定的盐字符串为 “$1$0123$4567”,其中:$1$ 表示 MD5 算法;剩下的 “0123$4567” 字符串将从左到右依次获取位于 [a-Za-Z0-9.] 范围内的字符串,最多获取指定算法允许的字符数。如:MD5 最大允许获取 8 个字符,SHA-512 / SHA-256 允许最大获取 16 个字符。如果在获取盐的过程中遇到了 “$” 符号,则结束。因此,上面实例中实际获取到的盐为 “0123”,这点可以从消息摘要结果 “$1$0123$Ogizgcf47rN5Sbjs5RAMm.” 得知。
因此,输入一个完整的散列值作为盐是有效的,例如用以下方法验证密码:
String enteredPwd = "输入的密码"; String storedPwd = "$1$0123$Ogizgcf47rN5Sbjs5RAMm"; // 数据库中存储的密码 if(storedPwd.equals(crypt(enteredPwd, storedPwd))) { System.out.println("匹配成功"); }
上面实例中的 crypt(enteredPwd, storedPwd) 实际等价于 crypt(enteredPwd, "$1$0123"),因为 “$1$0123$Ogizgcf47rN5Sbjs5RAMm” 取到 “0123” 字符串后遇到了 “$” 符号,被截取了。
Crypt 加密后的结果字符串以标记字符串 ($n$) 开头,其中 n 与盐类中的输入相同;然后,将盐附加到后面;然后是 “$” 符号,最后跟着实际的散列值。对于 DES,字符串只包含盐和实际哈希。它们的总长度取决于所使用的算法:
SHA-512: 106 个字符
SHA-256: 63 个字符
MD5: 34 个字符
DES: 13 个字符
示例:
crypt("secret", "$1$xxxx") => "$1$xxxx$aMkevjfEIpa35Bh3G4bAc."
上面将计算字符串 “secret” 的 MD5 消息摘要结果,结算结果长度为 30 个字符,这是因为盐 “xxxx” 只指定了 4 个字符,实际上可以指定 8 个字符。如果指定为 8 个字符,则消息摘要总长度为 34 个字符。
crypt("secret", "xx") => "xxWAum7tHdIUw"
上面将计算字符串 “secret” 的 DES 消息摘要结果,计算结果长度为 13 个字符。
下面将演示使用 Crypt 类实现 SHA-512、SHA-256、MD5 和 DES 消息摘要计算。代码如下:
import org.apache.commons.codec.digest.Crypt; public class CryptDemo1 { public static void main(String[] args) { String key = "hello world"; String sha512 = Crypt.crypt(key, "$6$0123456789012356"); System.out.println("SHA-512:" + sha512); String sha256 = Crypt.crypt(key, "$5$0123456789012356"); System.out.println("SHA-256:" + sha256); String md5 = Crypt.crypt(key, "$1$01234567"); System.out.println("MD5:" + md5); String des = Crypt.crypt(key, "01"); System.out.println("DES:" + des); } }
输出结果:
SHA-512:$6$0123456789012356$kt3zgxr2RKmFgtPNZqtxB9sebvtvawEfjk1fhMxaUC8E.sH3omiqBFHPLQSJqH5snHlzhiSVqmZ6IRhzCMhLj/ SHA-256:$5$0123456789012356$zalDYsDnI2CKQwQ.b0fsgk32UZ6stnJCzopRV87b8sB MD5:$1$01234567$hrZxh5BCBsbRPc89Bq0By1 DES:01IZKH2s/QTR6
注意:更多关于 Crypt 的用法,请参考官网API:
http://commons.apache.org/proper/commons-codec/apidocs/index.html