Crypt 类

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 方法为例进行介绍:

public static String crypt(String key, String salt)

该方法将以与 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

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号