【Shiro】 密码学

Metadata

title: 【Shiro】 密码学
date: 2023-01-19 14:00
tags:
  - 行动阶段/完成
  - 主题场景/组件
  - 笔记空间/KnowladgeSpace/ProgramSpace/ModuleSpace
  - 细化主题/Module/Shiro/基础
categories:
  - Shiro
keywords:
  - Shiro
description: 【Shiro】 密码学

【Shiro】 密码学

密码学是隐藏或混淆数据的过程,因此窥探者无法理解它。Shiro 在密码学方面的目标是简化和使用 JDK 的密码学支持。

重要的是要注意,密码学通常并不特定于 Subject,因此它是 Shiro 的 API 的一个区域,它不是特定于 Subject 的。你可以在任何地方使用 Shiro 的加密支持,即使没有使用 Subject。Shiro 真正关注其密码学支持的两个领域是密码哈希(又名消息摘要)和密码密码领域。让我们更详细地看一下这两个。

Hash

如果您使用过 JDK 的MessageDigest类,您很快就会意识到它使用起来有点麻烦。它有一个笨拙的基于工厂的静态方法 API 而不是面向对象的 API,并且您被迫捕获可能永远不需要捕获的已检查异常。如果您需要对消息摘要输出进行十六进制编码或 Base64 编码,您只能靠自己了——这两者都没有标准的 JDK 支持。Shiro 在干净直观的哈希 API 中解决了这些问题。

例如,让我们考虑一下相对常见的情况,即对文件进行 MD5 哈希处理并确定该哈希值的十六进制值。这称为“校验和”,在提供文件下载时经常使用 - 用户可以对下载的文件执行他们自己的 MD5 哈希,并断言他们的校验和与下载站点上的校验和匹配。如果它们匹配,则用户可以充分假设文件在传输过程中未被篡改。

下面是你可以在没有Shiro 的情况下尝试这样做的方法:

  1. 将文件转换为字节数组。JDK 中没有任何东西可以对此提供帮助,因此您需要创建一个辅助方法来打开FileInputStream、使用字节缓冲区并抛出适当的 IOExceptions 等。
  2. 使用MessageDigest类来散列字节数组,处理适当的异常,如下面的清单 12 所示。
  3. 将哈希字节数组编码为十六进制字符。JDK 中也没有任何东西可以对此提供帮助,因此您需要创建另一个辅助方法,并且可能在您的实现中使用按位运算和位移位。

清单12: JDK 的 MessageDigest

try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.digest(bytes);
    byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} 

对于如此简单和相对常见的事情来说,这是一项大量的工作。现在这里是如何用Shiro做同样的事情。

String hex = new Md5Hash(myFile).toHex();

当您使用 Shiro 来简化所有这些工作时,理解正在发生的事情会变得非常简单和容易。密码的 SHA-512 散列和 Base64 编码同样简单。

String encodedPassword = 
    new Sha512Hash(password, salt, count).toBase64();

您可以看到 Shiro 在多大程度上简化了散列和编码,让您在这个过程中保持理智。

Ciphers

密码是可以使用密钥可逆地转换数据的加密算法。我们使用它们来保证数据安全,尤其是在传输或存储数据时,数据特别容易被窥视的时候。

如果您曾经使用过 JDK Cryptography API,尤其是 javax.crypto.Cipher 类,您就会知道它是一头难以驯服的极其复杂的野兽。对于初学者来说,每个可能的 Cipher 配置总是由 javax.crypto.Cipher 的实例表示。需要进行公钥/私钥加密吗?你使用密码。需要使用块密码进行流操作?你使用密码。需要创建 AES 256 位密码来保护数据?你使用密码。你明白了。

以及如何创建所需的 Cipher 实例?您创建了一个复杂的、不直观的令牌分隔的密码选项字符串,称为“转换字符串”,并将此字符串传递给 Cipher.getInstance 静态工厂方法。使用这种密码选项字符串方法,没有类型安全来确保您使用的是有效选项。这也隐含地意味着没有 JavaDoc 可以帮助您理解相关选项。如果您的 String 格式不正确,您还需要处理已检查的异常,即使您知道配置是正确的。如您所见,使用 JDK Ciphers 是一项相当繁琐的任务。很久以前,这些技术曾经是 Java API 的标准,但时代变了,我们需要一种更简单的方法。

Shiro 试图通过引入其 CipherService API 来简化加密密码的整个概念。CipherService 是大多数开发人员在保护数据时所需要的:一种简单、无状态、线程安全的 API,可以在一个方法调用中完整地加密或解密数据。您需要做的就是提供您的密钥,您可以根据需要进行加密或解密。例如,可以使用 256 位 AES 加密,如下面的清单 13 所示。

清单 13: Apache Shiro 的加密 API

AesCipherService cipherService = new AesCipherService(); 
cipherService.setKeySize(256);
//创建一个测试密钥:
byte[] testKey = cipherService.generateNewKey();

//加密文件的字节:
byte[] encrypted =
cipherService.encrypt(fileBytes, testKey);

与 JDK 的 Cipher API 相比,Shiro 示例更简单:

  • 您可以直接实例化 CipherService - 没有奇怪或令人困惑的工厂方法。
  • 密码配置选项表示为与 JavaBeans 兼容的 getter 和 setter——没有奇怪且难以理解的“转换字符串”。
  • 加密和解密在单个方法调用中执行。
  • 没有强制检查异常。如果需要,可以捕获 Shiro 的 CryptoException。

Shiro 的 CipherService API 还有其他好处,例如能够支持基于字节数组的加密/解密(称为“块”操作)以及基于流的加密/解密(例如,加密音频或视频)。

Java Cryptography 不需要很痛苦。Shiro 的密码学支持旨在简化您保护数据安全的工作。