bigywater.tech
Java · 212

Security Provider:Java 加密算法如何找到实现

Java 里的 MessageDigest、Cipher、Signature 是怎么找到具体实现的?这篇看提供者列表与顺序、算法名的解析、错误信息,再自己写一个提供者验证优先级(KeyStore 与 PKIX 在后面的篇目,JSSE 的握手见前面)。

13 个
JDK 21 在 macOS 上安装的提供者数,顺序决定谁先被选中
insertProviderAt(p, 1)
让自定义提供者优先于 SUN
ECB + PKCS5Padding
Cipher.getInstance("AES") 不写模式时的默认转换

提供者与顺序

实测 · 本机执行输出
  已安装的提供者(按优先级):
     1. SUN          版本 21,提供 55 个服务
     2. SunRsaSign   版本 21,提供 19 个服务
     3. SunEC        版本 21,提供 42 个服务
     4. SunJSSE      版本 21,提供 15 个服务
     5. SunJCE       版本 21,提供 179 个服务
     6. SunJGSS      版本 21,提供 2 个服务
     7. SunSASL      版本 21,提供 8 个服务
     8. XMLDSig      版本 21,提供 13 个服务
     9. SunPCSC      版本 21,提供 1 个服务
    10. JdkLDAP      版本 21,提供 1 个服务
    11. JdkSASL      版本 21,提供 2 个服务
    12. Apple        版本 21,提供 1 个服务
    13. SunPKCS11    版本 21,提供 0 个服务
  java.security 里的配置:security.provider.1 = SUN,security.provider.2 = SunRsaSign
  MessageDigest.getInstance("SHA-256") 用的提供者 = SUN
  Cipher.getInstance("AES/GCM/NoPadding") 用的提供者 = SunJCE
  KeyFactory.getInstance("RSA") = SunRsaSign;Signature.getInstance("SHA256withECDSA") = SunEC;SecureRandom 默认 = SUN

算法名与错误

实测 · 本机执行输出
  MessageDigest.getInstance("SHA-256"                 ) → 成功,getAlgorithm = SHA-256
  MessageDigest.getInstance("SHA256"                  ) → 成功,getAlgorithm = SHA256
  MessageDigest.getInstance("SHA-1"                   ) → 成功,getAlgorithm = SHA-1
  MessageDigest.getInstance("SHA1"                    ) → 成功,getAlgorithm = SHA1
  MessageDigest.getInstance("2.16.840.1.101.3.4.2.1"  ) → 成功,getAlgorithm = 2.16.840.1.101.3.4.2.1
  MessageDigest.getInstance("Sha-256"                 ) → 成功,getAlgorithm = Sha-256
  MessageDigest.getInstance("SHA-999"                 ) → NoSuchAlgorithmException: SHA-999 MessageDigest not available
  指定一个不存在的提供者 → NoSuchProviderException: no such provider: NoSuchProvider
  指定的提供者没有这个算法(SunJCE 里没有 SHA-256)→ NoSuchAlgorithmException: no such algorithm: SHA-256 for provider SunJCE
  Cipher.getInstance("AES") 的默认转换(不写模式与填充)实际是 AES;加密 16 字节后的密文长度 = 32(ECB + PKCS5Padding)

自定义提供者

实测 · 本机执行输出
  安装自定义提供者之前:SHA-256 的提供者 = SUN
  addProvider(MyProvider)(加在末尾):SHA-256 的提供者 = SUN,MyProvider 的位置 = 14
  insertProviderAt(MyProvider, 1) 返回 1:SHA-256 的提供者 = MyProvider
    [MyProvider] 我的 SHA-256 实现被调用了
  调用 digest 的结果(前 4 字节)= 2cf24dba,与直接用 SUN 的结果一致:true
  指定 "SUN" 的 getInstance 不受优先级影响:SUN
  removeProvider 之后:SHA-256 的提供者 = SUN

分步演示

Security Provider
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS(Apple 提供者在其它平台上不存在)
    • 没有验证:Cipher 的延迟提供者选择(init 之后才确定提供者)、FIPS 模式与 BouncyCastle 等第三方提供者、security.provider 在 java.security 里的修改与 -Djava.security.properties、提供者签名要求(JCE 在新版本里已不要求签名);服务类构造器必须 public 是实测观察,没有查规范
    京ICP备2026067502号-1京公网安备11010502063487号